【问题标题】:Pandas: Transpose a list in column into rows熊猫:将列中的列表转换为行
【发布时间】:2017-05-26 19:16:21
【问题描述】:

所以我有如下熊猫数据框 df_dates。

   PERSON_ID   MIN_DATE   MAX_DATE
0  000099-48 2016-02-01 2017-03-20
1     000184 2016-02-05 2017-01-19
2  000461-48 2016-03-07 2017-03-20
3  000791-48 2016-02-01 2017-03-07
4  000986-48 2016-02-01 2017-03-17
5     001617 2016-02-01 2017-02-20
6  001768-48 2016-02-01 2017-03-20
7     001937 2016-02-01 2017-03-17
8  002223-48 2016-02-04 2017-03-16
9  002481-48 2016-02-05 2017-03-17

我正在尝试将 Min 和 Max 之间的所有日期添加为每个 Person_ID 的行。这是尝试过的。

df_dates.groupby('PERSON_ID').apply(lambda x: pd.date_range(x['MIN_DATE'].values[0], x['MAX_DATE'].values[0]))

但是我得到的是,有没有办法将该系列转换为每个 Person_ID 的行?还是有其他更好的方法?

PERSON_ID
0-L2ID        DatetimeIndex(['2016-08-05', '2016-08-06', '20...
0-LlID        DatetimeIndex(['2016-02-03', '2016-02-04', '20...
000099-48     DatetimeIndex(['2016-02-01', '2016-02-02', '20...
000184        DatetimeIndex(['2016-02-05', '2016-02-06', '20...
000276        DatetimeIndex(['2016-02-01', '2016-02-02', '20...
000461-48     DatetimeIndex(['2016-03-07', '2016-03-08', '20...
000493-48     DatetimeIndex(['2016-02-01', '2016-02-02', '20...
000615-48     DatetimeIndex(['2016-02-02', '2016-02-03', '20...
000791-48     DatetimeIndex(['2016-02-01', '2016-02-02', '20...
000986-48     DatetimeIndex(['2016-02-01', '2016-02-02', '20...
dtype: object

这是我正在努力实现的目标:

PERSON_ID   Date
000099-48   2/1/2016
000099-48   2/2/2016
000099-48   2/3/2016
000099-48   2/4/2016
:
:
000099-48   3/18/2016
000099-48   3/19/2016
000099-48   3/20/2016
000184  2/5/2016
000184  2/6/2016
000184  2/7/2016
:
:
000184  1/17/2017
000184  1/18/2017
000184  1/19/2017

【问题讨论】:

    标签: python pandas transpose date-range


    【解决方案1】:

    您可以使用melt 进行整形,然后执行groupbyresample

    # Reshape via melt to get in the proper format for a resample.
    df = df.melt(id_vars=['PERSON_ID'], value_vars=['MIN_DATE', 'MAX_DATE'], value_name='DATE')
    
    # Set the index and drop unnecessary columns.
    df = df.set_index('DATE').drop('variable', axis=1)
    
    # Perform a groupby and resample.
    df = df.groupby('PERSON_ID', group_keys=False).resample('D').ffill().reset_index()
    

    结果输出:

               DATE  PERSON_ID
    0    2016-02-01  000099-48
    1    2016-02-02  000099-48
    2    2016-02-03  000099-48
    3    2016-02-04  000099-48
    ...         ...        ...
    3976 2017-03-14  002481-48
    3977 2017-03-15  002481-48
    3978 2017-03-16  002481-48
    3979 2017-03-17  002481-48
    

    【讨论】:

    • 貌似最新的melt函数不能直接在DataFrame上调用,但是需要将dataframe作为参数传递给它。所以我修改如下`df = pd.melt(df_dates, id_vars=['PERSON_ID'], value_vars=['MIN_DATE', 'MAX_DATE'], value_name='DATE')`
    • 看起来melt 是在 0.20.0 版本中作为 DataFrame 方法引入的。正如您所描述的,旧版本的 pandas 将需要 pd.melt
    【解决方案2】:

    选项 1

    d = pd.concat({
            p: pd.Series(pd.date_range(s, e)) for i, p, s, e in df.itertuples()
        })
    
    d.rename_axis(
        ['PERSON_ID', None]
    ).reset_index('PERSON_ID', name='Date').reset_index(drop=True)
    
          PERSON_ID       Date
    0     000099-48 2016-02-01
    1     000099-48 2016-02-02
    ...
    414      000184 2016-02-05
    415      000184 2016-02-06
    ...
    764   000461-48 2016-03-07
    765   000461-48 2016-03-08
    ...
    1143  000791-48 2016-02-01
    1144  000791-48 2016-02-02
    ...
    1544  000986-48 2016-02-01
    1545  000986-48 2016-02-02
    ...
    1955     001617 2016-02-01
    1956     001617 2016-02-02
    ...
    2341  001768-48 2016-02-01
    2342  001768-48 2016-02-02
    ...
    2755     001937 2016-02-01
    2756     001937 2016-02-02
    ...
    

    选项 2

    lol = [pd.date_range(t.MIN_DATE, t.MAX_DATE).tolist() for t in df.itertuples()]
    lns = [len(l) for l in lol]
    pd.DataFrame(dict(
            PERSON_ID=df.PERSON_ID.values.repeat(lns), Date=np.concatenate(lol)
        ))[['PERSON_ID', 'Date']]
    
          PERSON_ID       Date
    0     000099-48 2016-02-01
    1     000099-48 2016-02-02
    ...
    414      000184 2016-02-05
    415      000184 2016-02-06
    ...
    764   000461-48 2016-03-07
    765   000461-48 2016-03-08
    ...
    1143  000791-48 2016-02-01
    1144  000791-48 2016-02-02
    ...
    1544  000986-48 2016-02-01
    1545  000986-48 2016-02-02
    ...
    1955     001617 2016-02-01
    1956     001617 2016-02-02
    ...
    2341  001768-48 2016-02-01
    2342  001768-48 2016-02-02
    ...
    2755     001937 2016-02-01
    2756     001937 2016-02-02
    ...
    

    【讨论】:

      【解决方案3】:

      你也可以继续你之前已经在做的事情,但是将 datetimeindex 转换成一个字符串,然后使用str.split 来创建新的行

      例如:

      df = df.groupby('PERSON_ID').apply(lambda x: pd.date_range(x['MIN_DATE'].values[0], x['MAX_DATE'].values[0])).reset_index()
      df_dates = df.rename(columns={0: 'Dates'})
      

      创建要转换为字符串的函数。

      def get_date_string(x):
           return ", ".join([d.strftime('%Y-%m-%d') for d in x])
      
      df_dates['Dates'] = df_dates['Dates'].apply(get_date_string)
      

      将字符串拆分为新行。

      s = df_dates['Dates'].str.split(", ").apply(pd.Series, 1).stack()
      s.index = s.index.droplevel(-1)
      s.name = 'Dates'
      

      加入 PERSON_ID 列。

      del df[0]
      print(df.join(s))
      

      【讨论】:

        猜你喜欢
        • 2017-04-08
        • 1970-01-01
        • 1970-01-01
        • 2019-10-12
        • 1970-01-01
        • 2021-08-08
        • 1970-01-01
        • 2014-03-05
        • 1970-01-01
        相关资源
        最近更新 更多