首页 > 解决方案 > 如何将大量数据框列传递给 numpy 向量化作为参数

问题描述

我有一个正好有 31 列的数据框,例如 100 行。

我需要创建一个包含 100 个字典的列表,这些字典的值来自不同的 31 列。

我目前正在使用apply()函数来执行此操作:

my_df.apply(lambda row: _build_data(row, param1, param2, param3), axis=1)

但现在我想探索 numpy 的vectorize()可能性。问题是,从我正在阅读的内容来看,我应该将每一列作为单独的参数传递给它:

np.vectorize(_build_data)(my_df[col1], my_df[col2], ..., my_df[col31], param1, param2, param3)

这看起来不像 pythonic,我也不想定义一个有 34 个参数的函数。

你知道是否有另一种方法可以做到这一点?

非常感谢你的帮忙!

标签: python-3.xpandasnumpyvectorizationapply

解决方案


我怀疑您正在尝试使用np.vectorize,因为您读到 numpy 'vectorization' 是一种加速pandas代码的方式。

In [29]: df = pd.DataFrame(np.arange(12).reshape(4,3), columns=['A','B','C'])                  
In [30]: df                                                                                    
Out[30]: 
   A   B   C
0  0   1   2
1  3   4   5
2  6   7   8
3  9  10  11

缓慢的逐行取行方法意味着:

In [31]: df.apply(lambda row: np.mean(row), axis=1)                                            
Out[31]: 
0     1.0
1     4.0
2     7.0
3    10.0
dtype: float64

快速的numpy方法:

In [32]: df.to_numpy()                                                                         
Out[32]: 
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
In [33]: df.to_numpy().mean(axis=1)                                                            
Out[33]: array([ 1.,  4.,  7., 10.])

也就是说,我们得到一个数据帧值的数组,并使用快速编译的方法来计算行均值。

但是要为每一行制作像字典一样的东西:

In [35]: df.apply(lambda row: {str(k):k for k in row}, axis=1)                                 
Out[35]: 
0        {'0': 0, '1': 1, '2': 2}
1        {'3': 3, '4': 4, '5': 5}
2        {'6': 6, '7': 7, '8': 8}
3    {'9': 9, '10': 10, '11': 11}
dtype: object

我们必须迭代数组行,就像我们对 dataframe 所做的那样apply

In [36]: [{str(k):k for k in row} for row in df.to_numpy()]                                    
Out[36]: 
[{'0': 0, '1': 1, '2': 2},
 {'3': 3, '4': 4, '5': 5},
 {'6': 6, '7': 7, '8': 8},
 {'9': 9, '10': 10, '11': 11}]

数组方法更快:

In [37]: timeit df.apply(lambda row: {str(k):k for k in row}, axis=1)                          
1.13 ms ± 702 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [38]: timeit [{str(k):k for k in row} for row in df.to_numpy()]                             
40.8 µs ± 157 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

但是该apply方法返回一个数据框,而不是一个列表。我怀疑大部分额外的时间都在这一步。

np.vectorize(and np.frompyfunc) 也可用于迭代数组,但默认是迭代元素,而不是行或列。一般来说,它们比更显式的迭代要慢(就像我在 [36] 中所做的那样)。

从列表中制作数据框的笨拙方法:

In [53]: %%timeit 
    ...: df1 = pd.DataFrame(['one','two','three','four'],columns=['d'])   
    ...: df1['d'] =[{str(k):k for k in row} for row in df.to_numpy()]                                                                                       
572 µs ± 18.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

推荐阅读