根据各组中除最后一行以外的最后一个值的内容,对列的总和和计数

时间:2019-12-20 10:12:26

标签: python pandas python-3.6 pandas-groupby

我有一个如下数据框(这是问题here的更新)

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”,然后再做sumcount列“ val”中的行,但是应该加起来的行只是包含以下内容的行“类型”与每个组中“类型”列的最后一个值相同。另外,如果有多于一行,则不应对最后一行的值求和或计数。如果最后一个值只有一行,那么应该对最后一行进行求和计数。

例如,组“ aa”的最后一行具有“类型” M,因此仅对组中具有“类型” M的行进行求和和计数。但是,由于带有M的行多于一个,因此仅对最后一行以外的行进行求和计数。因此,需要将值0和1相加并且计数为2。

在另一种情况下,组“ dddddddd”只有一行,因此总和应为3,计数应为1。

上述df的预期输出如下。输出中的“类型”列不是必需的,如果花费更多时间可以将其忽略。我在这里展示它只是为了让我更清楚地说明要实现的目标。

id        val  count   type
aa          1  2       M
bbb         6  3       T
cccccc      0  2       C
dddddddd    3  1       G

2 个答案:

答案 0 :(得分:2)

想法是按DataFrame.drop_duplicates过滤每组的最后一行,如果count不为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

答案 1 :(得分:2)

找到最后一个值,然后从末尾的总和中减去它:

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