python - 在特定条件下聚合 Dataframe 中的行值
问题描述
我有一个dataframe
有两列的。我想构建 value 为的所有连续行的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
。我的方法将是一个循环,当我发现 a 时,我创建第二个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 函数来实现我的目标吗?
解决方案
在我看来,这里有必要创建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
然后仅使用(by mask )过滤-1
值,另一个不匹配的值通过以下方式转换为s :boolean indexing
b
NaN
Series.reindex
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
- 永远不会在组 for-1
和被替换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),
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
第一列GroupBy.agg
,最后通过DataFrame.reset_index
with删除索引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)
然后将 column 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
使用 和创建连续的组,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
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
by 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
添加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
行by :boolean indexing
~
print (df[~m])
a b
0 0 2
1 1 3
4 0 2
8 5 0
然后通过以下方式将新数据添加到原始数据DataFrame.append
:
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
最后DataFrame.sort_index
是相同的顺序:
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
推荐阅读
- sql - SQL 在连接中返回单行
- python - Kivy/Python 如何将一个对象传递给另一个类?
- c++ - 将像素设置为 OLED 显示器 128x64 时出现问题
- azure - 无法在创建知识库向导中选择 QnA 服务
- php - Ifinite/lazy Scrolling in PHP using Ajax 显示了对 XMLHttpRequest 的访问
- android - 想要一个动态大小的ImageView Android
- c# - Listview中的按钮命令未触发
- flutter - 如何根据 Firebase Auth 错误消息在 Flutter 中显示自定义警报对话框?
- python-3.x - POST 不适用于带有 vue 前端的 python 烧瓶应用程序(预检)
- javascript - 基本身份验证而不是 AAD(Azure Active Directory)身份验证