如何解决更快地遍历一个 DataFrame 的行以将列添加到第二个 DataFrame
我正在尝试找到一种更快的方法,将函数多次应用于 DataFrame 中的一组数据。
我有两个数据帧:
对于每组参数,我想用“func”的结果向原始DataFrame添加一列,并将列名设置为参数集名称。
目前我正在遍历参数 DataFrame 的行,但我觉得有更好的方法来做到这一点。
我正在尝试查看是否有矢量化解决方案,但到目前为止,我使用两个 DataFrame 都没有成功。
我已经尝试在这篇文章中遵循 cs95 的回答,但几乎所有矢量化或列表推导式的示例都只处理单个 DataFrame: How to iterate over rows in a DataFrame in Pandas
有没有更好的方法来做到这一点?
我觉得我可能遗漏了一些明显的东西。
import pandas as pd
def func(data,a,b,c):
return data["original"] + a + b * c
parameters = pd.DataFrame(
{
"name": ["set_1","set_2","set_3"],"a": [1,2,3],"b": [4,5,6],"c": [7,8,9],}
)
data = pd.DataFrame({"original": [10,11,12,13,14,15]})
for i,row in parameters.iterrows():
data[row["name"]] = func(data,row["a"],row["b"],row["c"])
Inputs:
Parameters DataFrame:
name a b c
0 set_1 1 4 7
1 set_2 2 5 8
2 set_3 3 6 9
Original Data DataFrame:
original
0 10
1 11
2 12
3 13
4 14
5 15
Output:
original set_1 set_2 set_3
0 10 39 52 67
2 12 41 54 69
3 13 42 55 70
4 14 43 56 71
5 15 44 57 72
解决方法
不直接使用循环(apply()
中隐含)
- 使用笛卡尔积将数据合并在一起
- 使用
apply()
进行计算 - 使用
pivot()
将其重塑为您想要的输出结构
df = pd.read_csv(io.StringIO(""" original
0 10
1 11
2 12
3 13
4 14
5 15"""),sep="\s+")
dfp = pd.read_csv(io.StringIO(""" name a b c
0 set_1 1 4 7
1 set_2 2 5 8
2 set_3 3 6 9"""),sep="\s+")
# catesian product data with params
dfm = df.assign(foo=1).merge(dfp.assign(foo=1),on="foo")
# do the calc
dfm = dfm.assign(calc=dfm.apply(lambda x: x.original + x.a + x.b * x.c,axis=1))
# reshape
dfm = dfm.pivot(index="original",columns="name",values="calc").reset_index()
原文 | set_1 | set_2 | set_3 | |
---|---|---|---|---|
0 | 10 | 39 | 52 | 67 |
1 | 11 | 40 | 53 | 68 |
2 | 12 | 41 | 54 | 69 |
3 | 13 | 42 | 55 | 70 |
4 | 14 | 43 | 56 | 71 |
5 | 15 | 44 | 57 | 72 |
您可以修改下面的代码以满足您的期望,我将第 1 行(原始 = 11)留在那里;应该很容易修改。
下面的代码避免了迭代,因为它可能很慢。它所做的是首先从参数中获取值,然后对每一列与 data['original'] 进行乘法以得到最终输出:
def func(left_df,right_df):
right_df = right_df.copy()
new_headers = right_df["name"].array
right_df = (right_df["a"] + right_df["b"] * right_df["c"]).array
right_df = dict(zip(new_headers,new))
return left_df.assign(
**{key: left_df["original"] + value for key,value in right_df.items()}
)
data.pipe(func,parameters)
original set_1 set_2 set_3
0 10 39 52 67
1 11 40 53 68
2 12 41 54 69
3 13 42 55 70
4 14 43 56 71
5 15 44 57 72
,
按如下方式定义您的函数:
def func2(dataCol,a,b,c):
return dataCol[:,np.newaxis] + a[np.newaxis,:] + b[np.newaxis,:] * c[np.newaxis,:]
差异:
- 第一个参数是源数据列,而不是整个DataFrame,
- 其余 3 个参数也是 列(取自 parameters), 而不是单个值。
然后,要获得结果,请按以下方式调用:
data[parameters.name.tolist()] = func2(data.original,parameters.a,parameters.b,parameters.c)
使用 %timeit 我检查了你和我的代码的执行时间。 我的代码执行时间约为您代码的 60%。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。