【问题标题】:How to calculate sum of events between two dates [duplicate]如何计算两个日期之间的事件总和[重复]
【发布时间】:2019-11-04 05:37:16
【问题描述】:

我有一个 DataFrame,我需要在其中计算每个人两个日期之间的事件数。

在下面的 DataFrame 中,对于每个 A 类日期,我需要计算每个人在上一个 A 类日期之前 B 类日期的数量。每个人有多少个 A 类和 B 类日期没有限制。

我想避免 for 循环,因为它们很慢。

数据帧

Person Date     Type 
1      01/01/19 A  
1      01/05/19 B 
1      02/01/19 A
1      03/01/19 A
2      01/01/19 A
2      01/07/19 B
2      01/25/19 B
2      02/01/19 A
2      02/05/19 B
2      04/01/19 A
3      03/01/19 A
3      04/01/19 A

期望的输出

Person Date   Count
1      2/1/19 1
1      3/1/19 0
2      2/2/19 2
2      4/1/19 1
3      4/1/19 0

【问题讨论】:

  • 这是一个很好的例子,说明您可能需要外部循环,因为您需要维护状态。每个人都会告诉你,“不要使用 for 循环,因为那是反熊猫”,但是你最终会遇到这样的问题,因为它本质上是有状态的,所以问题变得难以/不可能解决。你有多少行?你确定这不是过早的优化吗?
  • 我有大约 12k 行。

标签: python pandas


【解决方案1】:

你可以在没有for-loop 的情况下解决这个问题。不过,我的解决方案需要进行大量预处理,并且最终结果与您想要的输出并不完全,但非常接近(并且正确)。为清楚起见,我将其拆分为多个步骤 - 如果您喜欢这类事情,您可以将这些步骤压缩为更少。

import pandas as pd
import numpy as np

# Making dummy data
d = {"Person":[1,1,1,1,2,2,2,2,2,2,3,3],
     "Date":["01/01/19", "01/05/19", "02/01/19", "03/01/19", "01/01/19", "01/07/19", "01/25/19", 
             "02/01/19", "02/05/19", "04/01/19", "03/01/19", "04/01/19"],
     "Type":["A", "B", "A", "A", "A", "B", "B", "A", "B", "A", "A", "A"]}

df = pd.DataFrame(d)

df["isB"] = df["Type"] == "B"
df["step1"] = df["isB"].astype(int).diff().fillna(0)
df["step2"] = df["step1"]
df["step2"][df["isB"]] = 1
df["step3"] = (df["step2"] == -1).cumsum()
grouped = df.groupby(["Person", "step3"])

result = pd.DataFrame({"Date":grouped.last()["Date"], "Count":grouped["isB"].sum()})
result.index = result.index.droplevel(1)
result = result.reset_index()

print(result)

输出:

   Person      Date  Count
0       1  01/05/19    1.0
1       1  03/01/19    0.0
2       2  01/25/19    2.0
3       2  02/05/19    1.0
4       2  04/01/19    0.0
5       3  04/01/19    0.0

您想要的输出的两个不同之处是:

  • 第 2 个人有一个额外的条目。这是由于我的分组方式,它导致第 2 个人的最后一个“A”条目是它自己的组,因此产生的计数为 0。
  • 显示的日期是最后一个“B”条目的日期,而不是下一个第一个“A”条目的日期。不确定这是否值得费心解决,所以我没有。

我希望这会有所帮助,或者至少能提供灵感。

【讨论】:

  • 感谢您的洞察力。
【解决方案2】:

感谢 molybdenum42 提供的见解。我不知道差异。这让我对在类型 A 上过滤的索引上使用 diff 有了一个想法。我不知道如何在索引本身上执行此操作,因此我将其复制到另一列。数据框已按人员和日期排序,但我将其包含在下面的代码中。

d = {"Person":[1,1,1,1,2,2,2,2,2,2,3,3],
     "Date":["01/01/19", "01/05/19", "02/01/19", "03/01/19", "01/01/19", "01/07/19", "01/25/19", 
             "02/01/19", "02/05/19", "04/01/19", "03/01/19", "04/01/19"],
     "Type":["A", "B", "A", "A", "A", "B", "B", "A", "B", "A", "A", "A"]}

df = pd.DataFrame(d)
df.Date = pd.to_datetime(df.Date)
df_sorted = df.sort_values(by=['Person', 'Date'])
df_sorted.reset_index(drop=True, inplace=True)
df_sorted['_index'] = df_sorted.index.values

group_a = df_sorted[df_sorted.Type == 'A'].groupby('Person')
df_sorted['Count'] = group_a['_index'].diff()-1
df_sorted[df_sorted.Count.notna()]

Person  Date    Type    _index  Count
1   02/01/19    A       2       1.0
1   03/01/19    A       3       0.0
2   02/01/19    A       7       2.0
2   04/01/19    A       9       1.0
3   04/01/19    A       11      0.0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 1970-01-01
    相关资源
    最近更新 更多