【问题标题】:Pandas: Add new column with several values to groupby dataframe熊猫:将具有多个值的新列添加到 groupby 数据框
【发布时间】:2016-08-17 01:37:10
【问题描述】:

对于我的数据框,我想为另一列中的每个唯一值添加一个新列。新列包含几个日期时间条目,其他列的每个唯一值都应获取这些条目。

例子:

原始 Df:

ID  
1             
2               
3

新列 DF:

Date
2015/01/01
2015/02/01
2015/03/01

结果 Df:

ID    Date
1     2015/01/01
      2015/02/01
      2015/03/01
2     2015/01/01
      2015/02/01
      2015/03/01
3     2015/01/01
      2015/02/01
      2015/03/01

我试图坚持这个解决方案:https://stackoverflow.com/a/12394122/3856569 但它给了我以下错误:Length of values does not match length of index

有人有一个简单的解决方案吗?非常感谢!

【问题讨论】:

    标签: pandas group-by


    【解决方案1】:

    更新:复制ids 6 次:

    In [172]: %paste
    data = """\
    id
    1
    2
    3
    """
    df = pd.read_csv(io.StringIO(data))
    # repeat each ID 6 times
    df = pd.DataFrame(df['id'].tolist()*6, columns=['id'])
    
    start_date = pd.to_datetime('2015-01-01')
    
    df['date'] = start_date
    df['date'] = df.groupby('id', as_index=False)\
                   .transform(lambda x: pd.date_range(start_date,
                                                      freq='1D',
                                                      periods=len(x)))
    df.sort_values(by=['id','date'])
    ## -- End pasted text --
    Out[172]:
        id       date
    0    1 2015-01-01
    3    1 2015-01-02
    6    1 2015-01-03
    9    1 2015-01-04
    12   1 2015-01-05
    15   1 2015-01-06
    1    2 2015-01-01
    4    2 2015-01-02
    7    2 2015-01-03
    10   2 2015-01-04
    13   2 2015-01-05
    16   2 2015-01-06
    2    3 2015-01-01
    5    3 2015-01-02
    8    3 2015-01-03
    11   3 2015-01-04
    14   3 2015-01-05
    17   3 2015-01-06
    

    旧的更通用的答案:

    准备样品 DF:

    start_date = pd.to_datetime('2015-01-01')
    
    data = """\
    id
    1
    2
    2
    3
    1
    2
    3
    2
    1
    """
    df = pd.read_csv(io.StringIO(data))
    
    In [200]: df
    Out[200]:
       id
    0   1
    1   2
    2   2
    3   3
    4   1
    5   2
    6   3
    7   2
    8   1
    

    解决方案:

    In [201]: %paste
    df['date'] = start_date
    df['date'] = df.groupby('id', as_index=False)\
                   .transform(lambda x: pd.date_range(start_date,
                                                      freq='1D',
                                                      periods=len(x)))
    ## -- End pasted text --
    
    In [202]: df
    Out[202]:
       id       date
    0   1 2015-01-01
    1   2 2015-01-01
    2   2 2015-01-02
    3   3 2015-01-01
    4   1 2015-01-02
    5   2 2015-01-03
    6   3 2015-01-02
    7   2 2015-01-04
    8   1 2015-01-03
    

    排序:

    In [203]: df.sort_values(by='id')
    Out[203]:
       id       date
    0   1 2015-01-01
    4   1 2015-01-02
    8   1 2015-01-03
    1   2 2015-01-01
    2   2 2015-01-02
    5   2 2015-01-03
    7   2 2015-01-04
    3   3 2015-01-01
    6   3 2015-01-02
    

    【讨论】:

    • 感谢您的回复,但结果并不是我想要的。在您的最终数据框中,id '2' 分配了一个日期(2015-01-04),而 id '3' 缺少一个日期。有没有办法像你在多次出现id的情况下那样准备原始数据框?我在数据框中只出现了一次 id。所以我无法在分组数据框之前分配几个日期
    • @TheDude,所以您只想复制每个ID 三次,然后向它们添加三个后续日期 - 对吗?
    • 是的,我得到了后续日期(总共 6 个不同的日期),应该分配给每个 ID(约 50.000 个唯一值)。
    • @TheDude,所以你想在最后有6*50.000 = 300.000 行?
    【解决方案2】:

    一个相当简单的numpy 方法,利用repeattile

    import numpy as np
    import pandas as pd
    
    N     = 3  # arbitrary number of IDs/dates
    ID    = np.arange(N) + 1
    dates = pd.date_range('20160101', periods=N)
    
    df = pd.DataFrame({'ID'    : np.repeat(ID, N),
                       'dates' : np.tile(dates, N)})
    

    结果数据框:

    In [1]: df
    Out[1]:
       ID      dates
    0   1 2016-01-01
    1   1 2016-01-02
    2   1 2016-01-03
    3   2 2016-01-01
    4   2 2016-01-02
    5   2 2016-01-03
    6   3 2016-01-01
    7   3 2016-01-02
    8   3 2016-01-03
    

    更新

    假设您已经拥有IDs 中的DataFrame,正如MaxU 所指出的,您可以平铺IDs

    df = pd.DataFrame({'ID'    : np.tile(df['ID'], N),
                       'dates' : np.tile(dates, N)})
    # now df needs sorting
    df = df.sort_values(by=['ID', 'dates'])
    

    结果数据框:

    In [5]: df
    Out[5]:
       ID      dates
    0   1 2016-01-01
    3   1 2016-01-01
    6   1 2016-01-01
    1   2 2016-01-02
    4   2 2016-01-02
    7   2 2016-01-02
    2   3 2016-01-03
    5   3 2016-01-03
    8   3 2016-01-03
    

    【讨论】:

    • 我猜,你的解决方案会比我的快得多:)。我也会使用np.tile(df['id'],N) 而不是np.repeat(ID, N),因为 OP 已经有一个包含 ID 的 DF
    猜你喜欢
    • 2016-09-08
    • 2018-05-08
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    • 1970-01-01
    相关资源
    最近更新 更多