Python Group By and Counting first in Series, 按月排序

Python Groupby & Counting first in Series, sorting by month

我有一个 pandas 数据框(这是一个例子,实际数据框要大很多):

data = [['345', 1, '2022_Jan'], ['678', 1, '2022_Jan'], ['123', 1, '2022_Feb'], ['123', 1, '2022_Feb'], ['345', 0, '2022_Mar'], ['678', 1, '2022_Mar'], ['901', 0, '2022_Mar'], ['678', 1, '2022_Mar']]

df = pd.DataFrame(data, columns = ['ID', 'Error Count', 'Year_Month'])

我要回答的问题是:有多少个ID有误?

我想要得到一个输出,该输出按 'Year_Month' 分组,并且每个月出现的每个 ID 计数为 1。换句话说,我想在一个月内为每个 ID 只计算 1。

当我按 'Year_Month' & 'ID' 分组时:df.groupby(['Year_Month', 'ID']).count()

它将给我以下输出(下面的当前输出 link)以及每个 ID 的总错误计数,但我只想对每个 ID 计数一次。我还希望 Year_Month 按时间顺序排序,不知道为什么当我的原始数据框在 Year_Month 列中按月排序时不是这样。

My current output

Desired output

这是一种方法:

(df
    .groupby(['Year_Month', 'ID']) # group by the two columns
    .sum('Error Count')['Error Count'] # aggregate the sum over error count
    .apply(lambda x: int(bool(x)))) # convert to boolean and back to int
    .to_frame('Error Count') # add name back to applied column
)

                Error Count
Year_Month ID
2022_Feb   123            1
2022_Jan   345            1
           678            1
2022_Mar   345            0
           678            1
           901            0


这些实际上是重复记录吗?您确定不想记录用户 123 在 2 月份有两次错误吗?

如果是这样,首先删除重复项,然后分组并求和Error Count.count() 方法并不像您认为的那样:

df.drop_duplicates(["ID", "Year_Month"]) \
  .groupby(["Year_Month", "ID"])["Error Count"] \
  .sum()

输出:

In [3]: counts = df.drop_duplicates(["ID", "Year_Month"]) \
   ...:            .groupby(["Year_Month", "ID"])["Error Count"] \
   ...:            .sum()

In [4]: counts
Out[4]:
Year_Month  ID
2022_Feb    123    1
2022_Jan    345    1
            678    1
2022_Mar    345    0
            678    1
            901    0
Name: Error Count, dtype: int64

就排序而言,您希望将 "Year_Month" 转换为日期时间对象,因为现在它们只是作为字符串排序:

In [5]: "2022_Feb" < "2022_Jan"
Out[5]: True

你可以这样做:

In [6]: counts.sort_index(level=0, key=lambda ym: pd.to_datetime(ym, format="%Y_%b"))
Out[6]:
Year_Month  ID
2022_Jan    345    1
            678    1
2022_Feb    123    1
2022_Mar    345    0
            678    1
            901    0
Name: Error Count, dtype: int64

这是另一种方法

使用 astype(bool) 将总和转换为布尔值 return True 或 False,基于值为 0 或 non-zero,然后使用 astype(int)


df.groupby(['Year_Month','ID'])['Error Count'].sum().astype(bool).astype(int)

Year_Month  ID 
2022_Feb    123    1
2022_Jan    345    1
            678    1
2022_Mar    345    0
            678    1
            901    0
Name: Error Count, dtype: int32

要排序,请将结果分配给数据框,然后应用 ddejohn 解决方案进行排序

counts = df.groupby(['Year_Month','ID'])['Error Count'].sum().astype(bool).astype(int)

counts.sort_index(level=0, key=lambda ym: pd.to_datetime(ym, format="%Y_%b")) # ddejohn:  answer above


Year_Month  ID 
2022_Jan    345    1
            678    1
2022_Feb    123    1
2022_Mar    345    0
            678    1
            901    0
Name: Error Count, dtype: int32