对数据框中所有行组合求和的更快方法

mr7*_*mr7 6 python performance combinations numpy pandas

我有一个包含 10,000 行的数据框,我试图将这些行的所有可能组合相加。根据我的计算,大约有 5000 万种组合。我将举一个小例子来简化我的数据的样子:

df = Ratio     Count     Score
     1         6         11
     2         7         12
     3         8         13
     4         9         14
     5         10        15
Run Code Online (Sandbox Code Playgroud)

这是想要的结果:

results = Min Ratio     Max Ratio     Total Count     Total Score
          1             2             13              23
          1             3             21              36
          1             4             30              50
          1             5             40              65
          2             3             15              25
          2             4             24              39
          2             5             34              54
          3             4             17              27
          3             5             27              42
          4             5             19              29
Run Code Online (Sandbox Code Playgroud)

这是我想出的代码来完成计算:

for i in range(len(df)):
    j = i + 1
    while j <= len(df):
        range_to_calc = df.iloc[i:j]
        total_count = range_to_calc['Count'].sum()
        total_score = range_to_calc['Score'].sum()
        new_row = {'Min Ratio': range_to_calc.at[range_to_calc.first_valid_index(),'Ratio'],
                   'Max Ratio': range_to_calc.at[range_to_calc.last_valid_index(),'Ratio'],
                   'Total Count': total_count,
                   'Total Score': total_score}
        results = results.append(new_row, ignore_index=True)
        j = j + 1
Run Code Online (Sandbox Code Playgroud)

这段代码有效,但根据我运行几分钟后的估计,它需要 200 小时才能完成。我知道使用 numpy 会快很多,但我无法理解如何构建多个数组以相加。(我认为如果我只做 1+2、2+3、3+4 等会很容易,但要困难得多,因为我需要 1+2、1+2+3、1+2+3 +4 等)是否有更有效的方法来完成此计算,以便它可以在合理的时间内运行?谢谢!

PS:如果你想知道我想用一个 5000 万行的数据框做什么,我的最终结果实际上并不需要它。我最终希望将结果中每一行的总分除以其总计数以获得每个总计数的总分值,然后显示每个总计数的 1,000 个最高总分,以及每个相关的最小比率、最大值比率、总计数和总分。

Ami*_*ngh 3

经过这些改进后,运行 10k 行大约需要2 分钟。

  1. 对于求和计算,您可以预先计算cumulative sum(cumsum)并保存它。sum(i to j)等于sum(0 to j) - sum(0 to i-1). 现在sum(0 to j)是,现在cumsum[j]也是sum(0 to i - 1)cumsum[i-1]所以sum(i to j) = cumsum[j] - cumsum[i - 1]。这使得每次不同组合的计算总和有了显着的改进。

  2. 对数组的操作numpy比对 pandas 系列的操作更快,因此将每个列转换为 numpy 数组,然后对其进行计算。

  3. (来自其他答案):不要追加到列表中,而是初始化一个大小为空的 numpy 数组((n*(n+1)//2) -n , 4)并使用它来保存结果。

使用:

count_cumsum = np.cumsum(df.Count.values)
score_cumsum = np.cumsum(df.Score.values)
ratios = df.Ratio.values
n = len(df)
rowInCombination = (n * (n + 1) // 2) - n
arr = np.empty(shape = (rowInCombination, 4), dtype = int)
k = 0
for i in range(len(df)):
    for j in range(i + 1, len(df)):
        arr[k, :] = ([
              count_cumsum[j] - count_cumsum[i-1] if i > 0 else count_cumsum[j], 
              score_cumsum[j] - score_cumsum[i-1] if i > 0 else score_cumsum[j],
              ratios[i],
              ratios[j]])
        k = k + 1
out = pd.DataFrame(arr, columns = ['Total_Count', 'Total_Score', 
                    'Min_Ratio', 'Max_Ratio'])
Run Code Online (Sandbox Code Playgroud)

输入:

df = pd.DataFrame({'Ratio': [1, 2, 3, 4, 5], 
                   'Count': [6, 7, 8, 9, 10],
                   'Score': [11, 12, 13, 14, 15]})
Run Code Online (Sandbox Code Playgroud)

输出:

>>>out

  Min_Ratio Max_Ratio   Total_Count Total_Score
0   1     2              13                 23
1   1     3              21                 36
2   1     4              30                 50
3   1     5              40                 65
4   2     3              15                 25
5   2     4              24                 39
6   2     5              34                 54
7   3     4              17                 27
8   3     5              27                 42
9   4     5              19                 29
Run Code Online (Sandbox Code Playgroud)