在特定条件下聚合数据帧中的行值

2024-03-29 08:24:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个dataframe,它有两列。我想构建所有连续行的总和,其中column 0的值是-1。你知道吗

我的dataframe看起来像这样:

 0   2
 1   3
-1   4
-1   7
 0   2
-1   0
-1   1
-1   3
 5   0

期望的输出应该是:

 0   2
 1   3
-1   11
 0   2
-1   4
 5   0

第二列中的值都等于或大于零。第一列上的值等于或大于-1,如果这有帮助的话。我的方法将是一个循环,在这里我创建第二个dataframe,然后向后推每个不等于-1的值,然后累积,当我找到一个-1时,但是我想,这种方法不会有效。 伪代码:

sum = 0
found = False
for row in dataframe:
   if row[0] != -1:
       if found:
           new_df.append([-1, sum])
           sum = 0
           found = False
       new_df.append(row)
   elif row[0] == -1:
       found = True
       sum += row[1]

是否有一个内置的python或pandas函数可以用来实现我的目标?你知道吗


Tags: 方法代码infalsedataframedfnewfor
1条回答
网友
1楼 · 发布于 2024-03-29 08:24:22

在我看来,这里有必要创建Series,以100%确定助手组的值是否与-1之外的值相同,因此将0.5添加到index以区分:

df = df.reset_index(drop=True)

m = df['a'] == -1
s = m.ne(m.shift()).cumsum()[m].reindex(df.index).fillna(df.index.to_series().add(.5))
df = df.groupby(s).agg({'a':'first', 'b':'sum'}).reset_index(drop=True)
print (df)
   a   b
0  0   2
1  1   3
2 -1  11
3 -1   4
4  0   2
5  5   0

解释:

df = pd.DataFrame({'a': [0, 1, -1, -1, 0, -1, -1, -1, 5],
                   'b': [2, 3, 4, 7, 2, 0, 1, 3, 0]})
print (df)
   a  b
0  0  2
1  1  3
2 -1  4
3 -1  7
4  0  2
5 -1  0
6 -1  1
7 -1  3
8  5  0

如果需要,请首先创建默认索引,因为在解决方案中使用了唯一的索引值:

df = df.reset_index(drop=True)

然后为-1和其他值创建连续组:

m = df['a'] == -1
print (df.assign(groups = m.ne(m.shift()).cumsum()))
   a  b  groups
0  0  2       1
1  1  3       1
2 -1  4       2
3 -1  7       2
4  0  2       3
5 -1  0       4
6 -1  1       4
7 -1  3       4
8  5  0       5

然后仅用^{}(通过掩码b)过滤-1值,另一个不匹配的值通过^{}转换为NaN

m = df['a'] == -1
print (df.assign(groups = m.ne(m.shift()).cumsum(),
                 filtered = m.ne(m.shift()).cumsum()[m].reindex(df.index)))

   a  b  groups  filtered
0  0  2       1       NaN
1  1  3       1       NaN
2 -1  4       2       2.0
3 -1  7       2       2.0
4  0  2       3       NaN
5 -1  0       4       4.0
6 -1  1       4       4.0
7 -1  3       4       4.0
8  5  0       5       NaN

然后用0.5的索引值替换缺少的值-从不在-1的组和被替换的NaN的值之间合并:

m = df['a'] == -1
print (df.assign(groups = m.ne(m.shift()).cumsum(),
                 filtered = m.ne(m.shift()).cumsum()[m].reindex(df.index),
                 idx = df.index.to_series().add(.5),
                 groups1 = m.ne(m.shift()).cumsum()[m].reindex(df.index).fillna(df.index.to_series().add(.5))))

   a  b  groups  filtered  idx  groups1
0  0  2       1       NaN  0.5      0.5
1  1  3       1       NaN  1.5      1.5
2 -1  4       2       2.0  2.5      2.0
3 -1  7       2       2.0  3.5      2.0
4  0  2       3       NaN  4.5      4.5
5 -1  0       4       4.0  5.5      4.0
6 -1  1       4       4.0  6.5      4.0
7 -1  3       4       4.0  7.5      4.0
8  5  0       5       NaN  8.5      8.5

然后将助手Series传递给groupby,并通过^{}聚合第二列的sum和第一列的first,最后通过drop=True通过^{}删除索引:

df = df.groupby(s).agg({'a':'first', 'b':'sum'}).reset_index(drop=True)
print (df)
   a   b
0  0   2
1  1   3
2 -1  11
3 -1   4
4  0   2
5  5   0

另一个更简单、性能更好的解决方案:

df = df.reset_index(drop=True)

m = df['a'] == -1
s = df.reset_index()
      .groupby(m.ne(m.shift()).cumsum()[m])
      .agg({'index':'first', 'b':'sum'})
      .set_index('index')
      .assign(a = -1)

df = df[~m].append(s, sort=True).sort_index()
print (df)
   a   b
0  0   2
1  1   3
2 -1  11
4  0   2
5 -1   4
8  5   0

解释:

首先是必要的默认索引:

df = df.reset_index(drop=True)

然后将列by-1与布尔掩码进行比较:

m = df['a'] == -1

reset_index将索引转换为不带drop参数的列:

print (df.reset_index())
   index  a  b
0      0  0  2
1      1  1  3
2      2 -1  4
3      3 -1  7
4      4  0  2
5      5 -1  0
6      6 -1  1
7      7 -1  3
8      8  5  0

创建具有shiftcumsum的连续组,并按掩码筛选-1组:

print (m.ne(m.shift()).cumsum()[m])
2    2
3    2
5    4
6    4
7    4
Name: a, dtype: int32

按索引列聚合first,按b列聚合sum

print (df.reset_index()
        .groupby(m.ne(m.shift()).cumsum()[m])
        .agg({'index':'first', 'b':'sum'}))

     index   b
a             
2.0      2  11
4.0      5   4

通过^{}index列转换为index

print(df.reset_index()
      .groupby(m.ne(m.shift()).cumsum()[m])
      .agg({'index':'first', 'b':'sum'})
      .set_index('index'))
        b
index    
2      11
5       4

通过^{}a列与常量-1相加:

s = (df.reset_index()
      .groupby(m.ne(m.shift()).cumsum()[m])
      .agg({'index':'first', 'b':'sum'})
      .set_index('index')
      .assign(a = -1))
print (s)
        b  a
index       
2      11 -1
5       4 -1

最后按^{}筛选出-1行,按~反向掩码:

print (df[~m])
  a  b
0  0  2
1  1  3
4  0  2
8  5  0

然后通过^{}将新数据添加到原始数据:

print (df[~m].append(s, sort=True))
   a   b
0  0   2
1  1   3
4  0   2
8  5   0
2 -1  11
5 -1   4

最后^{}对于相同的顺序:

print (df[~m].append(s, sort=True).sort_index())
   a   b
0  0   2
1  1   3
2 -1  11
4  0   2
5 -1   4
8  5   0

相关问题 更多 >