Pandas 分组并选择除组中最后一行之外的所有行

问题描述 投票:0回答:5

我有一个pandas df,如下:

MATERIAL    DATE         HIGH    LOW
AAA       2022-01-01     10      0
AAA       2022-01-02     0       0
AAA       2022-01-03     5       2
BBB       2022-01-01     0       0
BBB       2022-01-02     10      5
BBB       2022-01-03     8       4

我想要

groupby
MATERIAL
sort_values
DATE
并选择组中除最后一行之外的所有行。 结果应该是:

MATERIAL    DATE         HIGH    LOW
AAA       2022-01-01     10      0
AAA       2022-01-02     0       0
BBB       2022-01-01     0       0
BBB       2022-01-02     10      5

我已经尝试过

df.sort_values('DATE').groupby('MATERIAL').head(-1)
,但这会导致 df 为空。
DATE
是一个
pd.datetime
对象。 谢谢!

pandas
5个回答
4
投票

Series.duplicated
keep='last'
用于所有没有最后一个值:

df = df.sort_values(['MATERIAL','DATE'])
df = df[df['MATERIAL'].duplicated(keep='last')]
print (df)
  MATERIAL        DATE  HIGH  LOW
0      AAA  2022-01-01    10    0
1      AAA  2022-01-02     0    0
3      BBB  2022-01-01     0    0
4      BBB  2022-01-02    10    5

使用 groupby 解决方案可以通过

GroupBy.cumcount
降序计数并过滤没有
0
的所有行:

df = df.sort_values(['MATERIAL','DATE'])
df = df[df.groupby('MATERIAL').cumcount(ascending=False).ne(0)]
print (df)
  MATERIAL        DATE  HIGH  LOW
0      AAA  2022-01-01    10    0
1      AAA  2022-01-02     0    0
3      BBB  2022-01-01     0    0
4      BBB  2022-01-02    10    5

2
投票

另一种方法是首先按日期排序,然后使用索引对除最后一行之外的每一行进行分组和获取:

>>> df.sort_values("DATE").groupby("MATERIAL").apply(lambda group_df: group_df.iloc[:-1])
           MATERIAL        DATE  HIGH  LOW
MATERIAL                                  
AAA      0      AAA  2022-01-01    10    0
         1      AAA  2022-01-02     0    0
BBB      3      BBB  2022-01-01     0    0
         4      BBB  2022-01-02    10    5

2
投票

您可以使用:

(df.groupby('MATERIAL', as_index=False, group_keys=False)
   .apply(lambda d: d.iloc[:len(d)-1])
)

输出:

  MATERIAL        DATE  HIGH  LOW
0      AAA  2022-01-01    10    0
1      AAA  2022-01-02     0    0
3      BBB  2022-01-01     0    0
4      BBB  2022-01-02    10    5

2
投票

另一种方法是使用

groupby+transform
并将
nth
设为 -1,并将其与 DATE 列进行比较,并仅选择与此不匹配的行:


df = df.sort_values(['MATERIAL','DATE'])
c = df['DATE'].ne(df.groupby("MATERIAL")['DATE'].transform('nth',-1))
out = df[c].copy()

print(out)

  MATERIAL        DATE  HIGH  LOW
0      AAA  2022-01-01    10    0
1      AAA  2022-01-02     0    0
3      BBB  2022-01-01     0    0
4      BBB  2022-01-02    10    5

旁注:由于您有一个日期列,您还可以使用

max
last
进行转换,但这只会限制您到最后一行,而不是例如您可能需要
nth 的倒数第二行
如上图:

c = df['DATE'].ne(df.groupby("MATERIAL")['DATE'].transform('max'))

0
投票

鸭数据库:

(
df1.sql.select("*,row_number() over(partition by MATERIAL order by date desc) rn")
 .filter("rn!=1")
)

  MATERIAL        DATE  HIGH  LOW
0      AAA  2022-01-01    10    0
1      AAA  2022-01-02     0    0
3      BBB  2022-01-01     0    0
4      BBB  2022-01-02    10    5
© www.soinside.com 2019 - 2024. All rights reserved.