我有一个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函数实现目标?
答案 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_index
将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
在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.assign
的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
然后通过boolean indexing
将新数据添加到原始数据中:
~
最后DataFrame.append
的顺序相同:
print (df[~m])
a b
0 0 2
1 1 3
4 0 2
8 5 0