【问题标题】:Rolling groupby nunique count based on start and end dates根据开始和结束日期滚动 groupby nunique 计数
【发布时间】:2020-02-05 04:11:02
【问题描述】:

我有一个具有唯一 ID、开始日期和结束日期的数据框。在一年的时间里,ID 可以启动、停止和重新启动。

我想在一年的过程中获得一个 groupby nunique 的 ID 计数。 目前,我可以计算 ID 开始日期的唯一值,但我如何准确地合并结束日期?

fun = pd.DataFrame({'ZIP_KEY': ['A', 'B','C', 'A', 'B', 'A'],
                   'start_month': [1, 2, 2, 6, 8, 10],
                   'end_month': [4, 3, 7, 7, 12, 12]})

fun.groupby('start_month')['ZIP_KEY'].nunique()

start_month
1     1
2     2
3     0
4     0
5     0
6     1
7     0
8     1
9     0
10    1
11    0
12    0

基本上,如果一个 ID 在 1 月开始并在 3 月结束,我希望它包含在 2 月和 3 月的计数中,而不仅仅是 1 月,这是我当前方法的操作方式。

期望的输出:

    start_month
1     1
2     3
3     3
4     2
5     1
6     2
7     2
8     1
9     1
10    2
11    2
12    2

非常感谢任何提示或帮助!

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    也许你可以列出开始和结束之间的所有月份,爆炸并最终计数

    import pandas as pd
    
    df = pd.DataFrame({'ZIP_KEY': ['A', 'B','C', 'A', 'B', 'A'],
                       'start_month': [1, 2, 2, 6, 8, 10],
                       'end_month': [4, 3, 7, 7, 12, 12]})
    
    df["list"] = df.apply(lambda x: list(range(x["start_month"], x["end_month"]+1)), 
                          axis=1)
    
    df = df.explode("list")
    
    df.groupby("list")["ZIP_KEY"].nunique()
    

    【讨论】:

      【解决方案2】:

      一种选择是重新创建 DataFrame,您可以在其中将范围扩展到该范围内的所有月份,并在每一行中复制键。然后你可以使用普通的groupby

      df = pd.concat([pd.DataFrame({'month': range(st, en+1), 'key': k}) 
                      for k, st, en in zip(fun['ZIP_KEY'], fun['start_month'], fun['end_month'])])
      
      df.groupby('month').key.nunique()
      #month
      #1     1
      #2     3
      #3     3
      #4     2
      #5     1
      #6     2
      #7     2
      #8     1
      #9     1
      #10    2
      #11    2
      #12    2
      #Name: key, dtype: int64
      

      【讨论】:

        【解决方案3】:

        在 pandas 1.0.0 中使用 pd.IntervalIndex 有点有趣。

        ii = pd.IntervalIndex.from_arrays(fun['start_month'], fun['end_month'], closed='both')
        monthrange = np.arange(1,13)
        pd.Series(monthrange, index=monthrange).apply(lambda x: sum(ii.contains(x)))\
          .rename_axis('months').rename('count')
        

        输出:

        months
        1     1
        2     3
        3     3
        4     2
        5     1
        6     2
        7     2
        8     1
        9     1
        10    2
        11    2
        12    2
        Name: count, dtype: int64
        

        【讨论】:

          猜你喜欢
          • 2020-10-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多