基于每个组中最后一个值的内容(不包括最后一行)的列的总和和计数
Sum & count of a column based on the content of the last value in each group excluding the last row
我有一个数据框如下(这是这个问题的更新)
id val type
aa 0 C
aa 1 T
aa 2 T
aa 3 T
aa 0 M
aa 1 M
aa 2 C
aa 3 M
bbb 0 C
bbb 1 T
bbb 2 T
bbb 3 T
bbb 0 M
bbb 1 M
bbb 2 C
bbb 3 T
cccccc 0 C
cccccc 1 T
cccccc 2 T
cccccc 3 T
cccccc 0 M
cccccc 1 M
cccccc 0 C
cccccc 1 C
dddddddd 3 G
我想做一个 groupby
"ID",然后 sum
& count
"val" 列中的行,但是应该对这些行求和只有包含 "type" 的行与每个组中列 "type" 的最后一个值相同。此外,如果有多行,则不应累加或计算最后一行的值。如果最后一个值只有一行,那么最后一行应该求和并计算。
例如,组 'aa' 的最后一行有 "type" M,因此只有组中具有 "type" M 的行被求和并计算在内。但是,由于 M 不止一行,因此只应对除最后一行以外的行进行求和和计数。因此,值 0 和 1 需要相加,计数为 2。
另一种情况下,组'dddddddd'只有一行,所以总和应该是3,计数应该是1。
上述 df 的预期输出如下。输出中的列 "type" 不是强制性的,如果需要更多时间,可以将其省略。我在这里展示它只是为了明确我想要实现的目标。
id val count type
aa 1 2 M
bbb 6 3 T
cccccc 0 2 C
dddddddd 3 1 G
想法是按 DataFrame.drop_duplicates
过滤每组的最后一行,如果计数为否则减去 1
:
df1 = (df[df['type'].eq(df.groupby('id')['type'].transform('last'))]
.groupby('id').agg(val=('val', 'sum'),
count=('val', 'size'),
type=('type','last')))
print (df1)
val count type
id
aa 4 3 M
bbb 9 4 T
cccccc 1 3 C
dddddddd 3 1 G
s = df.drop_duplicates('id', keep='last').set_index('id')['val']
m = df1['count'] != 1
df1['val'] -= np.where(m, s, 0)
df1['count'] -= np.where(m, 1, 0)
print (df1)
val count type
id
aa 1 2 M
bbb 6 3 T
cccccc 0 2 C
dddddddd 3 1 G
另一个解决方案:
cols = ['val','count']
df2 = (df.drop_duplicates('id', keep='last')
.set_index('id')
.assign(count=1)[cols])
df1[cols] = df1[cols].sub(df2.where(df1['count'] != 1, 0))
print (df1)
val count type
id
aa 1 2 M
bbb 6 3 T
cccccc 0 2 C
dddddddd 3 1 G
详情:
print (df2)
val count
id
aa 3 1
bbb 3 1
cccccc 1 1
dddddddd 3 1
找到最后一个值,并从最后的总和中减去它:
last_type = df.groupby("id").tail(1).rename(columns={'val':'last_val'})
res= df.merge(last_type, on=["id", "type"], how="inner").groupby(["id", "type"]).agg(
val = ('val', 'sum'),
count = ('val', 'count'),
last_val = ('last_val', 'first')).reset_index()
multiple = res['count'] > 1
res['val'] -= multiple*res['last_val']
res['count'] -= multiple
res.drop(columns='last_val')
Output:
id type val count
0 aa M 1 2
1 bbb T 6 3
2 cccccc C 0 2
3 dddddddd G 3 1
我有一个数据框如下(这是这个问题的更新
id val type
aa 0 C
aa 1 T
aa 2 T
aa 3 T
aa 0 M
aa 1 M
aa 2 C
aa 3 M
bbb 0 C
bbb 1 T
bbb 2 T
bbb 3 T
bbb 0 M
bbb 1 M
bbb 2 C
bbb 3 T
cccccc 0 C
cccccc 1 T
cccccc 2 T
cccccc 3 T
cccccc 0 M
cccccc 1 M
cccccc 0 C
cccccc 1 C
dddddddd 3 G
我想做一个 groupby
"ID",然后 sum
& count
"val" 列中的行,但是应该对这些行求和只有包含 "type" 的行与每个组中列 "type" 的最后一个值相同。此外,如果有多行,则不应累加或计算最后一行的值。如果最后一个值只有一行,那么最后一行应该求和并计算。
例如,组 'aa' 的最后一行有 "type" M,因此只有组中具有 "type" M 的行被求和并计算在内。但是,由于 M 不止一行,因此只应对除最后一行以外的行进行求和和计数。因此,值 0 和 1 需要相加,计数为 2。
另一种情况下,组'dddddddd'只有一行,所以总和应该是3,计数应该是1。
上述 df 的预期输出如下。输出中的列 "type" 不是强制性的,如果需要更多时间,可以将其省略。我在这里展示它只是为了明确我想要实现的目标。
id val count type
aa 1 2 M
bbb 6 3 T
cccccc 0 2 C
dddddddd 3 1 G
想法是按 DataFrame.drop_duplicates
过滤每组的最后一行,如果计数为否则减去 1
:
df1 = (df[df['type'].eq(df.groupby('id')['type'].transform('last'))]
.groupby('id').agg(val=('val', 'sum'),
count=('val', 'size'),
type=('type','last')))
print (df1)
val count type
id
aa 4 3 M
bbb 9 4 T
cccccc 1 3 C
dddddddd 3 1 G
s = df.drop_duplicates('id', keep='last').set_index('id')['val']
m = df1['count'] != 1
df1['val'] -= np.where(m, s, 0)
df1['count'] -= np.where(m, 1, 0)
print (df1)
val count type
id
aa 1 2 M
bbb 6 3 T
cccccc 0 2 C
dddddddd 3 1 G
另一个解决方案:
cols = ['val','count']
df2 = (df.drop_duplicates('id', keep='last')
.set_index('id')
.assign(count=1)[cols])
df1[cols] = df1[cols].sub(df2.where(df1['count'] != 1, 0))
print (df1)
val count type
id
aa 1 2 M
bbb 6 3 T
cccccc 0 2 C
dddddddd 3 1 G
详情:
print (df2)
val count
id
aa 3 1
bbb 3 1
cccccc 1 1
dddddddd 3 1
找到最后一个值,并从最后的总和中减去它:
last_type = df.groupby("id").tail(1).rename(columns={'val':'last_val'})
res= df.merge(last_type, on=["id", "type"], how="inner").groupby(["id", "type"]).agg(
val = ('val', 'sum'),
count = ('val', 'count'),
last_val = ('last_val', 'first')).reset_index()
multiple = res['count'] > 1
res['val'] -= multiple*res['last_val']
res['count'] -= multiple
res.drop(columns='last_val')
Output:
id type val count
0 aa M 1 2
1 bbb T 6 3
2 cccccc C 0 2
3 dddddddd G 3 1