【问题标题】:Large Dataframe Column multiplication大型数据框列乘法
【发布时间】:2016-03-29 15:13:29
【问题描述】:

我有一个非常大的数据框

in>> all_data.shape
out>> (228714, 436)

我想要有效地做的是将许多列相乘。我从 for 循环和列列表开始——我发现最有效的方法是

from itertools import combinations
newcolnames=list(all_data.columns.values) 
newcolnames=newcolnames[0:87]
#make cross products (the columns I want to operate on are the first 87)
for c1, c2 in combinations(newcolnames, 2):
    all_data['{0}*{1}'.format(c1,c2)] = all_data[c1] * all_data[c2]

可能有人猜到的问题是我有 87 列,这将提供大约 3800 个新列(是的,这就是我的意图)。我的 jupyter notebook 和 ipython shell 都在这个计算中窒息。我需要想出一个更好的方法来进行这种乘法。

是否有更有效的矢量化和/或处理方式?也许使用 numpy 数组(我的数据框已经过处理,现在只包含数字和 NAN,它从分类变量开始)。

【问题讨论】:

    标签: python pandas memory vectorization


    【解决方案1】:

    正如您在问题中提到的 NumPy,这可能是一个可行的选择,特别是因为您可能希望在 NumPy 的 2D 空间中工作,而不是使用 pandas 进行 1D 柱状处理。首先,您可以通过调用np.array 将数据帧转换为 NumPy 数组,就像这样 -

    arr = np.array(df) # df is the input dataframe
    

    现在,您可以获取列 ID 的成对组合,然后对列进行索引并执行列乘法,所有这些都将以矢量化方式完成,就像这样 -

    idx = np.array(list(combinations(newcolnames, 2)))
    out = arr[:,idx[:,0]]*arr[:,idx[:,1]]
    

    示例运行 -

    In [117]: arr = np.random.randint(0,9,(4,8))
         ...: newcolnames = [1,4,5,7]
         ...: for c1, c2 in combinations(newcolnames, 2):
         ...:     print arr[:,c1] * arr[:,c2]
         ...:     
    [16  2  4 56]
    [64  2  6 16]
    [56  3  0 24]
    [16  4 24 14]
    [14  6  0 21]
    [56  6  0  6]
    
    In [118]: idx = np.array(list(combinations(newcolnames, 2)))
         ...: out = arr[:,idx[:,0]]*arr[:,idx[:,1]]
         ...: 
    
    In [119]: out.T
    Out[119]: 
    array([[16,  2,  4, 56],
           [64,  2,  6, 16],
           [56,  3,  0, 24],
           [16,  4, 24, 14],
           [14,  6,  0, 21],
           [56,  6,  0,  6]])
    

    最后,您可以使用属性列标题(如果需要)创建输出数据框,就像这样 -

    >>> headers = ['{0}*{1}'.format(idx[i,0],idx[i,1]) for i in range(len(idx))]
    >>> out_df = pd.DataFrame(out,columns = headers)
    >>> df
       0  1  2  3  4  5  6  7
    0  6  1  1  6  1  5  6  3
    1  6  1  2  6  4  3  8  8
    2  5  1  4  1  0  6  5  3
    3  7  2  0  3  7  0  5  7
    >>> out_df
       1*4  1*5  1*7  4*5  4*7  5*7
    0    1    5    3    5    3   15
    1    4    3    8   12   32   24
    2    0    6    3    0    0   18
    3   14    0   14    0   49    0
    

    【讨论】:

      【解决方案2】:

      你可以试试df.eval()方法:

      for c1, c2 in combinations(newcolnames, 2):
          all_data['{0}*{1}'.format(c1,c2)] = all_data.eval('{} * {}'.format(c1, c2))
      

      【讨论】:

      • 这似乎没有太大变化——它仍然需要几个小时和我所有的系统内存 (8GB)。很奇怪,如果我将过程分成块(比如前 5 列)。随着我的继续,这个过程变慢了,尽管需要做更少的计算。第 1 列的第一个“回合”应该进行 86 列计算,而大约 40 列应该减少到 40 列。事实上,第一部分在几秒钟内完成,而第 40-45 列则需要一个多小时。很奇怪。
      • 恐怕 228714 行和 3800+ 列的数据帧会用完你的 8GB 内存,假设你的 df 中有 16 位双倍,228714*3800*16/1024**3 = 12.95 GB跨度>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-03
      • 1970-01-01
      • 2017-09-28
      • 1970-01-01
      • 1970-01-01
      • 2018-12-14
      • 1970-01-01
      相关资源
      最近更新 更多