【问题标题】:Python de-aggregationPython 去聚合
【发布时间】:2019-01-15 16:36:00
【问题描述】:

我有一个在两个日期之间聚合的数据集,我想通过将总数除以这些日期之间的天数来每天对其进行去聚合。 作为样本

StoreID Date_Start    Date_End     Total_Number_of_sales
78       12/04/2015    17/05/2015    79089
80       12/04/2015    17/05/2015    79089

我想要的数据集是:

StoreID Date         Number_Sales 
78         12/04/2015    79089/38(as there are 38 days in between)
78         13/04/2015    79089/38(as there are 38 days in between) 
78         14/04/2015    79089/38(as there are 38 days in between)
78         ...
78         17/05/2015    79089/38(as there are 38 days in between)

任何帮助都会很有用。 谢谢

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    我不确定这是否正是你想要的,但你可以试试这个(我添加了另一个假想行):

    import datetime as dt
    df = pd.DataFrame({'date_start':['12/04/2015','17/05/2015'],
                       'date_end':['18/05/2015','10/06/2015'],
                       'sales':[79089, 1000]})
    
    df['date_start'] = pd.to_datetime(df['date_start'], format='%d/%m/%Y')
    df['date_end'] = pd.to_datetime(df['date_end'], format='%d/%m/%Y')
    df['days_diff'] = (df['date_end'] - df['date_start']).dt.days
    
    
    master_df = pd.DataFrame(None)
    for row in df.index:
        new_df = pd.DataFrame(index=pd.date_range(start=df['date_start'].iloc[row],
                              end = df['date_end'].iloc[row],
                              freq='d'))
        new_df['number_sales'] = df['sales'].iloc[row] / df['days_diff'].iloc[row]
        master_df = pd.concat([master_df, new_df], axis=0)
    

    首先将字符串日期转换为日期时间对象(这样您就可以计算范围之间的天数),然后根据日期范围创建一个新索引,然后划分销售额。该循环将数据帧的每一行粘贴到“扩展”数据帧中,然后将它们连接到一个主数据帧中。

    【讨论】:

    【解决方案2】:

    创建一个新的数据框怎么样?

    start = pd.to_datetime(df['Date_Start'].values[0], dayfirst=True)
    end = pd.to_datetime(df['Date_End'].values[0], dayfirst=True)
    idx = pd.DatetimeIndex(start=start, end=end, freq='D')
    res = pd.DataFrame(df['Total_Number_of_sales'].values[0]/len(idx), index=idx, columns=['Number_Sales'])
    

    产量

    In[42]: res.head(5)
    Out[42]: 
                Number_Sales
    2015-04-12   2196.916667
    2015-04-13   2196.916667
    2015-04-14   2196.916667
    2015-04-15   2196.916667
    2015-04-16   2196.916667
    

    如果您有多个商店(根据您的评论和编辑),那么您可以遍历所有行,计算销售额并在之后连接生成的数据框。

    df = pd.DataFrame({'Store_ID': [78, 78, 80],
        'Date_Start': ['12/04/2015', '18/05/2015', '21/06/2015'],
                       'Date_End': ['17/05/2015', '10/06/2015', '01/07/2015'],
                       'Total_Number_of_sales': [79089., 50000., 25000.]})
    
    to_concat = []
    for _, row in df.iterrows():
        start = pd.to_datetime(row['Date_Start'], dayfirst=True)
        end = pd.to_datetime(row['Date_End'], dayfirst=True)
        idx = pd.DatetimeIndex(start=start, end=end, freq='D')
        sales = [row['Total_Number_of_sales']/len(idx)] * len(idx)
        id = [row['Store_ID']] * len(idx)
        res = pd.DataFrame({'Store_ID': id, 'Number_Sales':sales}, index=idx)
        to_concat.append(res)
    
    res = pd.concat(to_concat)
    

    有定义更优雅的解决方案,看看这个thread的例子。

    【讨论】:

    • 感谢您的回答,问题是我想为所有商店 ID 执行此操作,因此需要循环所有商店,有什么想法吗?
    • 所有商店的开始日期和结束日期都相同吗?
    • 不,它们是不同的。同一个商店可以有不同的开始和结束日期,因为这些是一段时间内的聚合值,在更长的时间内,商店有多个行。
    【解决方案3】:

    考虑使用DataFrame 构造函数迭代主数据帧的每一行来构建数据帧列表。每次迭代都会扩展从 Start_Date 到范围结束的天数序列,并按天数对总销售额进行所需的销售划分:

    from io import StringIO
    import pandas as pd
    from datetime import timedelta
    
    txt = '''StoreID Date_Start    Date_End     Total_Number_of_sales
    78       12/04/2015    17/05/2015    79089
    80       12/04/2015    17/05/2015    89089'''
    
    df = pd.read_table(StringIO(txt), sep="\s+", parse_dates=[1, 2], dayfirst=True)
    df['Diff_Days'] = (df['Date_End'] - df['Date_Start']).dt.days
    
    def calc_days_sales(row): 
        long_df = pd.DataFrame({'StoreID': row['StoreID'],
                                'Date': [row['Date_Start'] + timedelta(days=i) 
                                              for i in range(row['Diff_Days']+1)],
                                'Number_Sales': row['Total_Number_of_sales'] / row['Diff_Days']})    
        return long_df
    
    df_list = [calc_days_sales(row) for i, row in df.iterrows()]
    
    final_df = pd.concat(df_list).reindex(['StoreID', 'Date', 'Number_Sales'], axis='columns')
    
    print(final_df.head(10))
    #    StoreID       Date  Number_Sales
    # 0       78 2015-04-12   2259.685714
    # 1       78 2015-04-13   2259.685714
    # 2       78 2015-04-14   2259.685714
    # 3       78 2015-04-15   2259.685714
    # 4       78 2015-04-16   2259.685714
    # 5       78 2015-04-17   2259.685714
    # 6       78 2015-04-18   2259.685714
    # 7       78 2015-04-19   2259.685714
    # 8       78 2015-04-20   2259.685714
    # 9       78 2015-04-21   2259.685714
    

    Python 3.6 不需要在末尾重新索引,因为数据框的输入字典将被排序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-09
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多