如何在pandas中从多列计算多列数据

4
我正在尝试使用函数从pandas数据框的多个列中计算多个列。该函数需要三个参数-a-,-b-和-c-,并返回三个计算值-sum-,-prod-和-quot-。在我的pandas数据框中,我有三个列-a-,-b-和-c-,我想要从这些列中计算出-sum-,-prod-和-quot-。
当我只有三行时,我所做的映射才有效。我不知道出了什么问题,但我认为它与选择正确的轴有关。有人能解释一下发生了什么以及如何计算我想要的值吗?
以下是我测试过的情况。 初始值
def sum_prod_quot(a,b,c):
    sum  = a + b + c
    prod = a * b * c
    quot = a / b / c
    return (sum, prod, quot)

df = pd.DataFrame({ 'a': [20, 100, 18],
                    'b': [ 5,  10,  3],
                    'c': [ 2,  10,  6],
                    'd': [ 1,   2,  3]
                 })

df
    a   b   c  d
0   20   5   2  1
1  100  10  10  2
2   18   3   6  3

计算步骤

使用三行数据

当我从这个数据框中计算三列并使用函数时,得到的结果如下:

df['sum'], df['prod'], df['quot'] = \
        list( map(sum_prod_quot, df['a'], df['b'], df['c']))

df
     a   b   c  d    sum     prod   quot
0   20   5   2  1   27.0    120.0   27.0
1  100  10  10  2  200.0  10000.0  324.0
2   18   3   6  3    2.0      1.0    1.0

这正是我想要的结果:sum-column 中的数字是 a、b、c 三列数值之和;prod-column 中的数字是 a、b、c 三列数值之积;quot-column 中的数字是 a、b、c 三列数值之商。请保留 HTML 标签,不作解释。 使用多于三行 当我增加一行数据到数据框时,就会出现错误!
数据框定义如下:
df = pd.DataFrame({ 'a': [20, 100, 18, 40],
                    'b': [ 5,  10,  3, 10],
                    'c': [ 2,  10,  6,  4],
                    'd': [ 1,   2,  3,  4]
                 })
df
     a   b   c  d
0   20   5   2  1
1  100  10  10  2
2   18   3   6  3
3   40  10   4  4

这个调用是

df['sum'], df['prod'], df['quot'] = \
        list( map(sum_prod_quot, df['a'], df['b'], df['c']))

结果是
...
    list( map(sum_prod_quot, df['a'], df['b'], df['c']))
ValueError: too many values to unpack (expected 3) 

尽管我期望会有额外的一行:

df
     a   b   c  d    sum     prod   quot
0   20   5   2  1   27.0    120.0   27.0
1  100  10  10  2  200.0  10000.0  324.0
2   18   3   6  3    2.0      1.0    1.0
3   40  10   4  4   54.0   1600.0    1.0

使用少于三行

当我将数据帧减少到一行时,也会出现错误。 该数据帧定义为:

df = pd.DataFrame({ 'a': [20, 100],
                    'b': [ 5,  10],
                    'c': [ 2,  10],
                    'd': [ 1,   2]
                 })
df
     a   b   c  d
0   20   5   2  1
1  100  10  10  2

这个调用是

df['sum'], df['prod'], df['quot'] = \
        list( map(sum_prod_quot, df['a'], df['b'], df['c']))

结果是
...
    list( map(sum_prod_quot, df['a'], df['b'], df['c']))
ValueError: need more than 2 values to unpack

虽然我期望少一行:

df
     a   b   c  d    sum     prod   quot
0   20   5   2  1   27.0    120.0   27.0
1  100  10  10  2  200.0  10000.0  324.0

问题

我有以下问题:

1)为什么会出现这些错误?

2)我需要如何修改调用才能获取所需的数据框?

注意

此链接中,提出了类似的问题,但给出的答案对我没有起作用。


你确定你的答案是正确的吗?你能检查一下产品列吗? - niraj
有一种更简单的方法来完成这个操作 df['sum'] = df['a'] + df['b'] + df['c'],其他操作也是同理。除非这只是一个错误的例子。 - DJK
谢谢您的建议。上面是一个示例,用于展示错误。原始函数是另一个模块中的函数。开源提供的解决方案很有效。 - PeterDev
2个回答

7
答案对于3行也似乎不正确。您可以检查除第一行和第一列之外的其他值吗?从结果来看,20 * 5 * 2的乘积不是120,而是200,并放置在sum列下方。在分配给新列之前,您需要以正确的方式形成列表。您可以尝试使用以下内容设置新列:
df['sum'], df['prod'], df['quot'] = zip(*map(sum_prod_quot, df['a'], df['b'], df['c']))

详细信息请查看链接


2
这正是我正在寻找的那一行。谢谢。它也适用于原始函数(位于另一个模块中),在那里我需要从直角坐标计算极坐标。 - PeterDev
@PeterDev 太好了!如果你愿意的话,可以接受这个答案。愉快编码 - niraj
zip(*map(...)) 中的解压缩和重新压缩是什么意思?看起来是多余的工作。 - Pedro Contipelli

0
apply()方法可以用于解决这个问题,当提供result_type参数时。
df[["sum", "prod", "quot"]] = df.apply(
    lambda row: sum_prod_quot(row["a"], row["b"], row["c"]),
    axis=1,
    result_type="expand",
)

或者(对于较大的数据框更快)只在数据框的一部分上使用apply()函数,并解包row的值。
df[["sum", "prod", "quot"]] = df[["a", "b", "c"]].apply(
    lambda row: sum_prod_quot(*row),
    axis=1,
    result_type="expand",
)

在这两种情况下,sum_prod_quot()return值被添加为df的新列。
解释如下:
  • apply()axis=1一起,将函数(第一个参数)分别应用于每一行。
  • 使用lambda确保传递的row与函数的签名匹配(sum_prod_quot()需要3个参数)。
  • result_type="expand"sum_prod_quot()的类似列表的返回值转换为列。
  • 然后,我们可以直接将这些新列的数据分配给df的(新的)"sum""prod""quot"列(df[["sum", "prod", "quot"]])。
有关更多信息,请参阅pandas文档

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接