首页 > 解决方案 > Python:在数据框中查找特定列值总和为 0 的所有行

问题描述

我想提取数据框中的所有行,其中这些分组行的特定列的总和为 0。

例如:如果我有以下行:

Row 1 1000
Row 2 -1000
Row 3 6000
Row 4 8000

我会将第 1 行和第 2 行分组,因为该列的总和为 0(+1000-1000=0) 如何在 python 中执行此操作?我怎样才能使用 numpy 来实现这一点?

标签: pythonnumpy

解决方案


为了获得更有启发性的结果,我将您的示例 DataFrame 扩展为:

   Id  Amount
0   1    1000
1   2   -1000
2   3   -5000
3   4    6000
4   5    8000
5   6   -2000
6   7   -4000
7   8   -2000
8   9    1500
9  10     500

您可以通过以下方式生成“边框行索引对”:

result = []
# Starting from each row, except the last
for i in range(df.index.size - 1):
    # Compute expanding sum
    s = df.iloc[i:].expanding().Amount.sum()
    # Find indices of zeroes
    ind = s[s == 0].index
    # Append "start == i, end == j" to the result
    result.extend([ [i, j] for j in ind ])

结果是:

[[0, 1], [1, 3], [1, 7], [4, 7], [7, 9]]

要检索、打印和检查显示的行“范围”,请运行:

for i, j in result:
    print(f'From {i} to {j}:')
    print(df.iloc[i:j+1])
    print(f'Sum: {df.iloc[i:j+1].Amount.sum()}\n')

结果是:

From 0 to 1:
   Id  Amount
0   1    1000
1   2   -1000
Sum: 0

From 1 to 3:
   Id  Amount
1   2   -1000
2   3   -5000
3   4    6000
Sum: 0

From 1 to 7:
   Id  Amount
1   2   -1000
2   3   -5000
3   4    6000
4   5    8000
5   6   -2000
6   7   -4000
7   8   -2000
Sum: 0

From 4 to 7:
   Id  Amount
4   5    8000
5   6   -2000
6   7   -4000
7   8   -2000
Sum: 0

From 7 to 9:
   Id  Amount
7   8   -2000
8   9    1500
9  10     500
Sum: 0

根据 12:52Z 的评论进行编辑

如果您想要“叶级”范围(不包括在更广泛的范围内),那么在找到一些零索引(在滚动总和中)之后,您应该只报告第一个范围,因为其他范围只包括已经报告的范围。

所以代码应该改成:

result = []
# Starting from each row, except the last
for i in range(df.index.size - 1):
    # Compute expanding sum
    s = df.iloc[i:].expanding().Amount.sum()
    # Find indices of zeroes
    ind = s[s == 0].index   
    if ind.size > 0:        # Something found
        result.append([i, ind[0]])  # Append "from i to the first 'zero row'"

注意:

  • 如果没有找到“零和”,我添加了if以避免“索引超出范围”异常,
  • extend更改为append,因为:
    • 在以前的版本中,我希望“分解”对列表,并将每对单独添加到结果中,
    • 现在我只添加了一应该“分解”。

这次的结果是:

[[0, 1], [1, 3], [4, 7], [7, 9]]

并注意没有添加范围[1, 7](存在于第一个解决方案中)。

所以现在你只有不包括其他范围的范围。


推荐阅读