大熊猫从宽到长基于日期列

时间:2019-08-20 07:28:26

标签: python-3.x pandas dataframe

我有一个如下所示的熊猫数据框:

id val  date    period1 period2  period3  
 1  4   05/03     1         2         3  
 2  6   06/03     4         5         6  
 3  2   07/03     7         8         9  
 4  9   08/03     5         7         1  

我想根据以下日期和时间段将其从宽转换为长:

id val  date  period  data 
 1  4   05/03  06/03    1  
               07/03    2 
               08/03    3  
 2  6   06/03  07/03    4 
               08/03    5   
               09/03    6  
 3  2   07/03  08/03    7     
               09/03    8     
               10/03    9  
 4  9   08/03  09/03    5      
               10/03    7     
               11/03    1  

这是period的值,将是date + 1month(年份也可能更改)的值,依此类推,其对应的值出现在data列中,而其余的数据框则保持不变。

我该如何实现?

2 个答案:

答案 0 :(得分:2)

首先用DataFrame.set_indexDataFrame.stack重塑值。

然后将date列转换为Series.dt.to_period的日期时间和月份,以GroupBy.cumcount的方式每组添加计数器,并以Series.dt.strftime的方式更改格式:

df = (df.set_index(['id','val','date'])
        .rename_axis('period', axis=1)
        .stack()
        .reset_index(name='data'))
s = pd.to_datetime(df['date'], format='%m/%y').dt.to_period('m')
df['period'] = df.groupby(['id','val','date']).cumcount().add(s + 1).dt.strftime('%m/%y')
print (df)

    id  val   date period  data
0    1    4  05/03  06/03     1
1    1    4  05/03  07/03     2
2    1    4  05/03  08/03     3
3    2    6  06/03  07/03     4
4    2    6  06/03  08/03     5
5    2    6  06/03  09/03     6
6    3    2  07/03  08/03     7
7    3    2  07/03  09/03     8
8    3    2  07/03  10/03     9
9    4    9  08/03  09/03     5
10   4    9  08/03  10/03     7
11   4    9  08/03  11/03     1

如果最后3列需要空值,则最后一次-DataFrame.duplicated是可以的,但是混合值-带字符串的数字,因此数字函数应该失败:

df.loc[df.duplicated(['id','val','date']), ['id','val','date']] = ''
print (df)
   id val   date period  data
0   1   4  05/03  06/03     1
1                 07/03     2
2                 08/03     3
3   2   6  06/03  07/03     4
4                 08/03     5
5                 09/03     6
6   3   2  07/03  08/03     7
7                 09/03     8
8                 10/03     9
9   4   9  08/03  09/03     5
10                10/03     7
11                11/03     1

答案 1 :(得分:1)

使用wide_to_long

的解决方案
df1 = (pd.wide_to_long(df, stubnames='period', j='p', i=['id', 'val', 'date'])
         .rename(columns={'period': 'data'}).reset_index())

df1['p'] = ((pd.to_datetime(df1.date, format='%m/%y').dt.to_period('M') 
            + df1.p).dt.strftime('%m/%y'))

df1.rename(columns={'p': 'period'})


Out[193]:
    id  val   date period  data
0    1    4  05/03  06/03     1
1    1    4  05/03  07/03     2
2    1    4  05/03  08/03     3
3    2    6  06/03  07/03     4
4    2    6  06/03  08/03     5
5    2    6  06/03  09/03     6
6    3    2  07/03  08/03     7
7    3    2  07/03  09/03     8
8    3    2  07/03  10/03     9
9    4    9  08/03  09/03     5
10   4    9  08/03  10/03     7
11   4    9  08/03  11/03     1