如何对数据框的每一行应用函数?
- 2025-04-01 09:56:00
- admin 原创
- 29
问题描述:
我是 Python 新手,不确定如何解决以下问题。
我有一个功能:
def EOQ(D,p,ck,ch):
Q = math.sqrt((2*D*ck)/(ch*p))
return Q
假设我有数据框
df = pd.DataFrame({"D": [10,20,30], "p": [20, 30, 10]})
D p
0 10 20
1 20 30
2 30 10
ch=0.2
ck=5
和ch
是ck
浮点类型。现在我想将公式应用于数据框上的每一行并将其作为额外行“Q”返回。一个示例(不起作用)是:
df['Q']= map(lambda p, D: EOQ(D,p,ck,ch),df['p'], df['D'])
(仅返回“地图”类型)
我的项目中将更需要这种类型的处理,并且我希望能找到一些可行的方法。
解决方案 1:
以下应该有效:
def EOQ(D,p,ck,ch):
Q = math.sqrt((2*D*ck)/(ch*p))
return Q
ch=0.2
ck=5
df['Q'] = df.apply(lambda row: EOQ(row['D'], row['p'], ck, ch), axis=1)
df
如果您所做的只是计算某个结果的平方根,那么请使用np.sqrt
矢量化的方法,这样速度会快得多:
In [80]:
df['Q'] = np.sqrt((2*df['D']*ck)/(ch*df['p']))
df
Out[80]:
D p Q
0 10 20 5.000000
1 20 30 5.773503
2 30 10 12.247449
时间安排
对于 30k 行 df:
In [92]:
import math
ch=0.2
ck=5
def EOQ(D,p,ck,ch):
Q = math.sqrt((2*D*ck)/(ch*p))
return Q
%timeit np.sqrt((2*df['D']*ck)/(ch*df['p']))
%timeit df.apply(lambda row: EOQ(row['D'], row['p'], ck, ch), axis=1)
1000 loops, best of 3: 622 µs per loop
1 loops, best of 3: 1.19 s per loop
您可以看到 np 方法快了约 1900 倍
解决方案 2:
还有其他几种方法可以对 DataFrame 的每一行应用函数。
(1) 您可以EOQ
稍微修改一下,让它接受一行(Series 对象)作为参数,并使用函数内的列名访问相关元素。此外,您可以apply
使用其关键字传递参数,例如ch
or ck
:
def EOQ1(row, ck, ch):
Q = math.sqrt((2*row['D']*ck)/(ch*row['p']))
return Q
df['Q1'] = df.apply(EOQ1, ck=ck, ch=ch, axis=1)
(2) 事实证明,这apply
通常比列表推导慢(在下面的基准测试中,它慢了 20 倍)。要使用列表推导,您可以进一步修改,以便通过其索引访问元素。然后在转换为列表的行EOQ
上循环调用该函数:df
def EOQ2(row, ck, ch):
Q = math.sqrt((2*row[0]*ck)/(ch*row[1]))
return Q
df['Q2a'] = [EOQ2(x, ck, ch) for x in df[['D','p']].to_numpy().tolist()]
(3) 事实上,如果目标是迭代调用函数,map
通常比列表推导更快。因此,您可以将函数转换df
为列表;然后将结果解包到列表中:map
df['Q2b'] = [*map(EOQ2, df[['D','p']].to_numpy().tolist(), [ck]*len(df), [ch]*len(df))]
(4) 正如@EdChum 所言,如果可能的话,最好使用矢量化方法,而不是逐行应用函数。Pandas 提供的矢量化方法可与 numpy 相媲美。EOQ
例如,在 的情况下math.sqrt
,您可以使用 pandas 的pow
方法代替 (在下面的基准测试中,使用 pandas 矢量化方法比使用 numpy 快约 20%):
df['Q_pd'] = df['D'].mul(2*ck).div(ch*df['p']).pow(0.5)
输出:
D p Q Q_np Q1 Q2a Q2b Q_pd
0 10 20 5.000000 5.000000 5.000000 5.000000 5.000000 5.000000
1 20 30 5.773503 5.773503 5.773503 5.773503 5.773503 5.773503
2 30 10 12.247449 12.247449 12.247449 12.247449 12.247449 12.247449
时间安排:
df = pd.DataFrame({"D": [10,20,30], "p": [20, 30, 10]})
df = pd.concat([df]*10000)
>>> %timeit df['Q'] = df.apply(lambda row: EOQ(row['D'], row['p'], ck, ch), axis=1)
623 ms ± 22.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>> %timeit df['Q1'] = df.apply(EOQ1, ck=ck, ch=ch, axis=1)
615 ms ± 39.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
>>> %timeit df['Q2a'] = [EOQ2(x, ck, ch) for x in df[['D','p']].to_numpy().tolist()]
31.3 ms ± 479 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit df['Q2b'] = [*map(EOQ2, df[['D','p']].to_numpy().tolist(), [ck]*len(df), [ch]*len(df))]
26.9 ms ± 306 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit df['Q_np'] = np.sqrt((2*df['D']*ck)/(ch*df['p']))
1.19 ms ± 53.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit df['Q_pd'] = df['D'].mul(2*ck).div(ch*df['p']).pow(0.5)
966 µs ± 27 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD