在特定条件下汇总数据框中的行值

时间:2019-09-17 10:53:32

标签: python pandas dataframe

我有一个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函数实现目标?

1 个答案:

答案 0 :(得分:1)

我认为这里有必要创建Series,以确保100%确定帮助者组的值是否永远不像-1之外的值一样,因此将0.5添加到index ti毁:

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

然后仅过滤-1个具有boolean indexing的值(通过掩码b),另一个不匹配的值被Series.reindex转换为NaN s:

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​​}}的组与替换的-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.agg聚合第二列的groupby和第一列的sum,最后由{删除索引{3}}和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) 与布尔掩码进行比较:

-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 shift创建连续的组,并按掩码过滤cumsum个组:

-1

按索引列汇总print (m.ne(m.shift()).cumsum()[m]) 2 2 3 2 5 4 6 4 7 4 Name: a, dtype: int32 ,按first列汇总sum

b

通过DataFrame.reset_indexprint (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

DataFrame.set_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 的{​​{1}}列:

a

最后用-1的反掩码过滤掉DataFrame.assigns = (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

然后通过boolean indexing将新数据添加到原始数据中:

~

最后DataFrame.append的顺序相同:

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