我有一个这样的 Dataframe ,数据大小大约超过100,000行。
| 类别|值1|值2| val 3值|val 4值|
| - -|- -|- -|- -|- -|
| A级|一个|2个|三个|四个|
| A级|四个|三个|2个|一个|
| B|一个|2个|三个|四个|
| B|三个|四个|一个|2个|
| B|一个|五个|三个|一个|
我想先用Category
列分组,然后在每组中用我自己的方法进行计算。
自定义方法返回浮点值cal
。
所需的输出是带有结果的字典形式。
{
'A': { 'cal': a },
'B:' { 'cal': b },
...
}
我尝试使用pandas
的groupby
和apply
。
def my_cal(df):
ret = ...
return {'cal': ret}
df.groupby('Category').apply(lambda grp: my_cal(grp)).to_dict()
当我用timeit
在jupyter笔记本电脑上测量时间时,它需要超过1秒,这对我来说太长了。
是否有办法优化这一点并缩短执行时间?
- -------------编辑------------
已将my_cal
的参数从 Dataframe 更新为数组。
def my_cal(val1: float, val2: float, val3: float, val4: float):
ret = inner_cal(val1, val2, val3, val4) # inner_cal is in external library
return {'cal': ret}
df.groupby('Category').apply(lambda grp: my_cal(grp['val1'].to_numpy(),
grp['val2'].to_numpy(),
grp['val3'].to_numpy(),
grp['val4'].to_numpy())).to_dict()
1条答案
按热度按时间4xrmg8kj1#
以下是您可以尝试的一些方法:
numba
生成my_cal
函数的优化机器码版本。您还可以在此处找到您可能考虑尝试的其他策略:https://pandas.pydata.org/docs/user_guide/enhancingperf.html#
收缩列数据类型
下列程式码可让您将每一个数据行资料类型转换成尽可能小的表示法,以减少数据框的内存使用量。例如,如果您有一个数据行,其值储存为
int64
,程式码会尝试判断数据行的值范围是否可以表示为int8
、int16
、或int32
。此外,它还可以将数据类型为object
的值转换为category
,将int
转换为uint
。范例:
使用
numba
生成my_cal
函数的优化机器码版本要在Python环境中安装
numba
,请执行以下命令:要在panda中使用Numba,你必须定义
my_cal
,并使用@jit
对其进行修饰。你还需要将底层的grp
值作为NumPy数组传递。你可以使用to_numpy()
方法来实现这一点。下面是一个函数的示例:执行时间比较
下面的代码比较了实现
DataFrame.groupby/apply
操作的不同方法:结果摘要:
| 实施|每个循环的执行时间|
| - -|- -|
| 方案1| 18.9毫秒± 500微秒|
| 方案2| 9.96毫秒± 140微秒|
| 方案3| 6.33毫秒± 221微秒|
编辑:使用
numba
优化my_cal
函数警告
Numba最擅长加速将数值函数应用到NumPy数组的**函数。如果您尝试
@jit
一个包含不支持的Python或NumPy代码的函数,编译将恢复对象模式,这很可能不会加速您的函数。您收到的警告是因为my_cal
正在调用一个没有经过@jit
优化的内部函数,因此,numba无法优化您的代码。如果您可以访问并修改inner_cal
,那么您可以尝试在其中包含@jit
装饰器并指定其参数类型提示。这种方法的问题是,如果inner_cal
包含对其他函数的调用,在选择将所有内部函数转换为numba之前,我强烈建议您分析代码,以确定那些内部函数是否也在numpy数组上操作。否则这是浪费时间。下面给予一个示例,如果使用
numba
,则inner_cal
函数应该是这样的: