【问题标题】:Pivoting a table from date range based columns to date index将表从基于日期范围的列透视到日期索引
【发布时间】:2020-09-08 20:01:11
【问题描述】:

我有一个结构如下的表:

>>> d = {'ID': ['A','A', 'A','A','B','B'], 'sub_id': [1,2,3,4,100,110], 
'start_cycle_1':['2013-05-23','2013-05-23', '2015-06-13', '2015-09-10', '2019-01-20', '2019-04-20'],
'end_cycle_1':['2013-05-27','2013-05-27', '2015-06-16', '2015-09-13', '2019-01-23', '2019-04-25'],
'start_cycle_2':['2013-06-05','2013-06-10', '2015-07-15', '2015-09-28', '2019-04-20', '2019-06-01'],
'end_cycle_2':['2013-06-08','2013-06-13', '2015-07-18', '2015-09-30', '2019-04-23', '2019-06-03'],
'start_cycle_3':['2013-06-28','2013-07-10', '2015-07-30', '2015-10-10', '2019-05-10', '2019-08-01'],
'end_cycle_3':['2013-06-30','2013-07-14', '2015-08-02', '2015-10-13', '2019-05-12', '2019-08-04']
 }

df = pd.DataFrame(data=d)
df
  ID  sub_id start_cycle_1 end_cycle_1 start_cycle_2 end_cycle_2 start_cycle_3 end_cycle_3
0  A       1    2013-05-23  2013-05-27    2013-06-05  2013-06-08    2013-06-28  2013-06-30
1  A       2    2013-05-23  2013-05-27    2013-06-10  2013-06-13    2013-07-10  2013-07-14
2  A       3    2015-06-13  2015-06-16    2015-07-15  2015-07-18    2015-07-30  2015-08-02
3  A       4    2015-09-10  2015-09-13    2015-09-28  2015-09-30    2015-10-10  2015-10-13
4  B     100    2019-01-20  2019-01-23    2019-04-20  2019-04-23    2019-05-10  2019-05-12
5  B     110    2019-04-20  2019-04-25    2019-06-01  2019-06-03    2019-08-01  2019-08-04

从这里开始,我想构建一个以(date,ID) 为索引的表。每个 ID 都以在 df 中遇到的最小日期开头,最后一行具有在 df 中遇到的该 ID 的最大日期,中间每天一行。
在上面的示例中,ID='A' 的行从 "2013-05-23" 开始,到 '2015-10-13' 结束。
主列将是"sub_ids_affected",并且将包含当天在一个周期内(无论它是什么)的 sub_id 列表。例如,由'2013-05-26' and 'A' 索引的行将具有[1,2]。由'2019-04-22' and 'B' 索引的行将具有['100','110']

对于'ID' = 'A'筛选出"sub_ids_affected" 不是空列表的行,输出将是:

   ID        date sub_ids_affected
0   A  2013-05-23           [1, 2]
1   A  2013-05-24           [1, 2]
2   A  2013-05-25           [1, 2]
3   A  2013-05-26           [1, 2]
4   A  2013-05-27           [1, 2]
5   A  2013-06-05              [1]
6   A  2013-06-06              [1]
7   A  2013-06-07              [1]
8   A  2013-06-08              [1]
9   A  2013-06-10              [2]
10  A  2013-06-11              [2]
11  A  2013-06-12              [2]
12  A  2013-06-13              [2]
13  A  2013-06-28              [1]
14  A  2013-06-29              [1]
15  A  2013-06-30              [1]
16  A  2013-07-10              [2]
17  A  2013-07-11              [2]
18  A  2013-07-12              [2]
19  A  2013-07-13              [2]
20  A  2013-07-14              [2]
21  A  2015-06-13              [3]
22  A  2015-06-14              [3]
23  A  2015-06-15              [3]
24  A  2015-06-16              [3]
25  A  2015-07-15              [3]
26  A  2015-07-16              [3]
27  A  2015-07-17              [3]
28  A  2015-07-18              [3]
29  A  2015-07-30              [3]
30  A  2015-07-31              [3]
31  A  2015-08-01              [3]
32  A  2015-08-02              [3]
33  A  2015-09-10              [4]
34  A  2015-09-11              [4]
35  A  2015-09-12              [4]
36  A  2015-09-13              [4]
37  A  2015-09-28              [4]
38  A  2015-09-29              [4]
39  A  2015-09-30              [4]
40  A  2015-10-10              [4]
41  A  2015-10-11              [4]
42  A  2015-10-12              [4]
43  A  2015-10-13              [4]

P.S : 并非所有 sub_id 都必须具有全部 3 个周期。

谢谢!

【问题讨论】:

  • 你能解释一下为什么第 12 行是 [2,3] 吗?在原始数据中,sub_id不是只有2个吗?另外,是否所有缺失的日期都出现在 ID 单元的最大值和最小值之间?
  • 我修复了第 12 行(以及其他一些),我将 2013 年与 2015 年混合在一起。编辑应该没问题。我不确定我是否理解您的第二个问题?
  • 预期输出示例的第四行和第五行跳过了日期。问题是如果它不跳过并且日期是连续的,2013-05-28、2013-05-29和2013-05-30是否有问题。
  • 不,这不是问题!正如我所说,这是对已创建列的非空列表的仅日期的输出过滤。未过滤的输出仍应具有“2013-05-28”,第三列中带有 []。如果当天有任何 sub_id 受到影响,它也会被包括在内,所以没有问题!

标签: python pandas dataframe pivot-table


【解决方案1】:

将水平形式的数据转换为垂直形式并将值分组到值列表中。将缺失的日期和时间添加到结果数据框中并填写值。

df = df.melt(['ID','sub_id'], var_name='cycle', value_name='date')
df1 = df.groupby(['ID','date'])['sub_id'].agg(list).reset_index()
df1['date'] = pd.to_datetime(df1['date'])
df1.set_index(df1['date'], inplace=True)
df1 = df1.asfreq('1D', method='ffill')
df1.columns = ['ID', 'old_date', 'sub_id']
df1.drop('old_date', inplace=True, axis=1)

df1.head(20)
ID  sub_id
date        
2013-05-23  A   [1, 2]
2013-05-24  A   [1, 2]
2013-05-25  A   [1, 2]
2013-05-26  A   [1, 2]
2013-05-27  A   [1, 2]
2013-05-28  A   [1, 2]
2013-05-29  A   [1, 2]
2013-05-30  A   [1, 2]
2013-05-31  A   [1, 2]
2013-06-01  A   [1, 2]
2013-06-02  A   [1, 2]
2013-06-03  A   [1, 2]
2013-06-04  A   [1, 2]
2013-06-05  A   [1]
2013-06-06  A   [1]
2013-06-07  A   [1]
2013-06-08  A   [1]
2013-06-09  A   [1]
2013-06-10  A   [2]
2013-06-11  A   [2]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多