【问题标题】:Grouping and Aggregating on multiple time series对多个时间序列进行分组和聚合
【发布时间】:2019-12-01 01:42:40
【问题描述】:

我是 python 和 pandas 的新手,并且有一些关于如何编写一个短函数的基本问题,该函数接受一个 pd.Dataframe 并返回按月份分组的相对值。

示例数据:

import pandas as pd
from datetime import datetime
import numpy as np

date_rng = pd.date_range(start='2019-01-01', end='2019-03-31', freq='D')
df = pd.DataFrame(date_rng, columns=['date'])
df['value_in_question'] = np.random.randint(0,100,size=(len(date_rng)))
df.set_index('date',inplace=True)
df.head()

       value_in_question
date    
2019-01-01  40
2019-01-02  86
2019-01-03  46
2019-01-04  75
2019-01-05  35

def absolute_to_relative(df):
    """
    set_index before using
    """
    return df.div(df.sum(), axis=1).mul(100)

relative_df = absolute_to_relative(df)      

relative_df.head()

       value_in_question
date    
2019-01-01  0.895055
2019-01-02  1.924368
2019-01-03  1.029313
2019-01-04  1.678228
2019-01-05  0.783173

而不是取列总和然后除以每一行, 我想每个月都有总和 groupby 。最终的 df 应该具有相同的 形状和形式,但行值与月份总和有关。

旧:

             value_in_question
date
"2019-01-01" value/colum_sum * 100

新:

            value_in_question
date
"2019-01-01" value/month_sum * 100

所以我尝试了以下方法,它为 value_in_question 返回 NA:

def absolute_to_relative_agg(df, agg):
    """
    set_index before using
    """
    return df.div(df.groupby([pd.Grouper(freq=agg)]).sum(), axis=1)

relative_df = absolute_to_relative(df, 'M')

      value_in_question
date    
2019-01-01  NaN
2019-01-02  NaN
2019-01-03  NaN
2019-01-04  NaN
2019-01-05  NaN

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    使用 GroupBy.transform 代替 Series/DateFrame 的聚合,与原始 DatatimeIndex 相同,因此可以进行划分:

    def absolute_to_relative_agg(df, agg):
        """
        set_index before using
        """
        return df.div(df.groupby([pd.Grouper(freq=agg)]).transform('sum'))
    
    relative_df = absolute_to_relative_agg(df, 'M')
    

    调用函数的另一种方式是DataFrame.pipe

    relative_df = df.pipe(absolute_to_relative_agg, 'M')
    
    print (relative_df)
               value_in_question
    date                         
    2019-01-01           0.032901
    2019-01-02           0.045862
    2019-01-03           0.048853
    2019-01-04           0.008475
    2019-01-05           0.041376
                          ...
    2019-03-27           0.062049
    2019-03-28           0.002165
    2019-03-29           0.048341
    2019-03-30           0.007937
    2019-03-31           0.015152
    
    [90 rows x 1 columns]
    

    【讨论】:

      【解决方案2】:

      对于总和,您可以groupby索引月份:

      In [31]: month_sum = df.groupby(df.index.strftime('%Y%m')).sum()
          ...: month_sum
          ...:
      Out[31]:
              value_in_question
      201901               1386
      201902               1440
      201903               1358
      

      然后您可以使用 .map 将月份与 DataFrame 的正确行对齐:

      In [32]: map_sum = df.index.strftime('%Y%m').map(month_sum['value_in_question'])
          ...: map_sum
          ...:
      Out[32]:
      Int64Index([1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386,
                  1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386,
                  1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1440, 1440,
                  1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440,
                  1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440,
                  1440, 1440, 1440, 1440, 1358, 1358, 1358, 1358, 1358, 1358, 1358,
                  1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358,
                  1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358,
                  1358, 1358],
                 dtype='int64')
      

      那么你只需要做除法:

      In [33]: df['value_in_question'].div(map_sum)
      Out[33]:
      date
      2019-01-01    0.012987
      2019-01-02    0.018759
      2019-01-03    0.000000
      2019-01-04    0.056277
      2019-01-05    0.019481
                      ...
      2019-03-27    0.031664
      2019-03-28    0.007364
      2019-03-29    0.050074
      2019-03-30    0.033873
      2019-03-31    0.005155
      Name: value_in_question, Length: 90, dtype: float64
      

      【讨论】:

        【解决方案3】:

        Grouperfreq='M' 一起使用。

        代码是:

        relative_df = df.groupby(pd.Grouper(freq='M'))\
            .value_in_question.apply(lambda x: x.div(x.sum()).mul(100))
        

        它返回一个 Series,其索引与原始 DataFrame 中的索引相同 并且值等于当前月份的相对 value_in_question

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-01-10
          • 1970-01-01
          • 2019-06-12
          • 1970-01-01
          • 1970-01-01
          • 2017-02-01
          • 1970-01-01
          • 2022-01-23
          相关资源
          最近更新 更多