使用具有多个返回值的函数创建多个pandas DataFrame列

8
我能够帮忙翻译。以下是您需要翻译的内容:

我想把一个具有多个返回值的函数应用于 pandas DataFrame,并将结果放在该 DataFrame 的不同新列中。

因此,假设有这样的数据:

import pandas as pd

df = pd.DataFrame(data = {'a': [1, 2, 3], 'b': [4, 5, 6]})

def add_subtract(a, b):
  return (a + b, a - b)

目标是使用单个命令在“df”中调用“add_subtract”函数,对“a”和“b”进行加减操作,创建两列新列:“sum”和“difference”。我认为以下代码可能有效:
(df['sum'], df['difference']) = df.apply(
    lambda row: add_subtract(row['a'], row['b']), axis=1)

但是它会产生以下错误:
----> 9 lambda row: add_subtract(row['a'], row['b']), axis=1) ValueError:太多的值需要展开(期望2个)
编辑:除了下面的答案之外,pandas应用函数可以修改返回一个列表或Series, 可以参考此链接:pandas apply function that returns multiple values to rows in pandas dataframe
def add_subtract_list(a, b):
  return [a + b, a - b]

df[['sum', 'difference']] = df.apply(
    lambda row: add_subtract_list(row['a'], row['b']), axis=1)

或者

def add_subtract_series(a, b):
  return pd.Series((a + b, a - b))

df[['sum', 'difference']] = df.apply(
    lambda row: add_subtract_series(row['a'], row['b']), axis=1)

两者都可以使用(后者等同于Wen的已接受答案)。

2个回答

9

添加 pd.Series

df[['sum', 'difference']] = df.apply(
    lambda row: pd.Series(add_subtract(row['a'], row['b'])), axis=1)
df

产出(yields)
   a  b  sum  difference
0  1  4    5          -3
1  2  5    7          -3
2  3  6    9          -3

2
谢谢!你能解释一下为什么这里需要 pd.Series 吗? - Max Ghenis
2
@MaxGhenis 在你的函数中,返回了一个元组作为结果。因此,我们将元组传递给 pd.Series,这将重构元组列为两个 pd.Series(Dataframe)。更多信息请参见 https://dev59.com/KV0b5IYBdhLWcg3wJ-Uz - BENY
我想知道row['a']row['b']是否能够正常工作。通常这种引用在apply()内部是不起作用的。 - Federico Dorato
@FedericoDorato:只要有一个lambda函数,你可以在apply函数中使用row['a']或者row.a - undefined

2

有一种方法可以使用 pd.DataFrame.assign 来实现:

df.assign(**{k:v for k,v in zip(['sum', 'difference'], add_subtract(df.a, df.b))})

应该产生:

   a  b  difference  sum
0  1  4          -3    5
1  2  5          -3    7
2  3  6          -3    9

澄清:

zip 是一个内置函数,它返回一个元组迭代器。第 i 个元组包含每个参数序列或可迭代对象的第 i 个元素。例如,list(zip(['sum', 'difference'], [df.a + df.b], df.a - df.b)) 应该返回 [('sum', df.a + df.b), ('difference', df.a - df.b)]

** 前缀加在字典对象前面作为运算符,将 keyvalue 对一起解压。实质上,这种解压可以表示为类似于:sum=df.a + df.b, difference=df.a - df.b 的形式。

总之,当这两者组合起来时,得到以下结果:

df.assign(sum=df.a + df.b, difference=df.a - df.b)

请点击提供的链接查看zip和在字典对象前使用**操作符的更多用法,以便更好地理解这些有用的工具。


这很有趣:我对Python相对较新(主要是R用户),所以你能解释一下 **zip 在这里的作用吗?看起来像是一个有用的结构。我接受了 Wen 的答案,因为它与我的猜测最不相似,但我给这个答案点了赞,如果这样做在性能方面会更好,我可以进行更改。 - Max Ghenis
1
@MaxGhenis 在Python中,您可以将zip视为R中的列表,我们需要在R中使用unlist。以下是R的示例 :-)(附注:我也是50%的R用户:-))https://dev59.com/H2855IYBdhLWcg3woWDM - BENY
那个声明有点不足。在R中的数据结构并不像Python的数据结构那么容易翻译。我能想到的最接近zip的函数是purrr包中的transpose函数。即使这样,在所有情况下也不能完全相同。 - Abdou

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