Pandas - 将具有开始和结束日期的数据框转换为每日数据

Posted

技术标签:

【中文标题】Pandas - 将具有开始和结束日期的数据框转换为每日数据【英文标题】:Pandas - Convert dataframe with start and end date to daily data 【发布时间】:2019-12-11 12:45:03 【问题描述】:

每个 ID 有一个记录,包括开始日期和结束日期

id  age state   start_date  end_date
123 18  CA     2/17/2019    5/4/2019
223 24  AZ     1/17/2019    3/4/2019

我想在开始日和结束日之间的每一天创建一条记录,以便将每日活动数据加入其中。目标输出看起来像这样

id  age state   start_date
123 18  CA      2/17/2019
123 18  CA      2/18/2019
123 18  CA      2/19/2019
123 18  CA      2/20/2019
123 18  CA      2/21/2019
            …
123 18  CA      5/2/2019
123 18  CA      5/3/2019
123 18  CA      5/4/2019

当然,对数据集中的所有 id 及其各自的开始日期执行此操作。非常感谢任何帮助 - 谢谢!

【问题讨论】:

为什么从 2019 年 6 月 17 日开始,而不是 2019 年 2 月 17 日? 对不起,错字。固定.... 【参考方案1】:

melt, GroupBy, resample & ffill

首先,我们将melt (unpivot) 您的两个日期列合并为一个。然后我们每天resample

melt = df.melt(id_vars=['id', 'age', 'state'], value_name='date').drop('variable', axis=1)
melt['date'] = pd.to_datetime(melt['date'])

melt = melt.groupby('id').apply(lambda x: x.set_index('date').resample('d').first())\
           .ffill()\
           .reset_index(level=1)\
           .reset_index(drop=True)

输出

          date     id   age state
0   2019-02-17  123.0  18.0    CA
1   2019-02-18  123.0  18.0    CA
2   2019-02-19  123.0  18.0    CA
3   2019-02-20  123.0  18.0    CA
4   2019-02-21  123.0  18.0    CA
..         ...    ...   ...   ...
119 2019-02-28  223.0  24.0    AZ
120 2019-03-01  223.0  24.0    AZ
121 2019-03-02  223.0  24.0    AZ
122 2019-03-03  223.0  24.0    AZ
123 2019-03-04  223.0  24.0    AZ

[124 rows x 4 columns]

编辑

我不得不在一个项目中重新审视这个问题,看起来使用 DataFrame.applypd.date_rangeDataFrame.explode 几乎快 3 倍:

df["date"] = df.apply(
    lambda x: pd.date_range(x["start_date"], x["end_date"]), axis=1
)
df = (
    df.explode("date", ignore_index=True)
    .drop(columns=["start_date", "end_date"])
)

输出

      id  age state       date
0    123   18    CA 2019-02-17
1    123   18    CA 2019-02-18
2    123   18    CA 2019-02-19
3    123   18    CA 2019-02-20
4    123   18    CA 2019-02-21
..   ...  ...   ...        ...
119  223   24    AZ 2019-02-28
120  223   24    AZ 2019-03-01
121  223   24    AZ 2019-03-02
122  223   24    AZ 2019-03-03
123  223   24    AZ 2019-03-04

[124 rows x 4 columns]

【讨论】:

该死的,不错。以后会用这个。 melt = melt.set_index('date').resample('d',).first().ffill().reset_index() 这个命令减少了记录的数量(预计会爆炸它按开始日期和结束日期之间的天数计算)。上一步每个 ID 有两条记录,但在上面提到的行之后只剩下少量 Id,有些只有 1 条记录,即使它们在开始日期和结束日期之间有很多天 是的,你是对的,我忘记了每个 id 的 groupby。见编辑,这应该给出正确的输出。 @LXandor 效果很好。感谢您的帮助【参考方案2】:

对列 start_dateend_date 的值使用 listcomp 和 pd.date_range 为每个记录创建日期列表。接下来,从 listcomp 的结果构造一个新的数据框,并连接回df 的其他 3 列。最后set_indexstackreset_index返回

a = [pd.date_range(*r, freq='D') for r in df[['start_date', 'end_date']].values]
df[['id', 'age', 'state']].join(pd.DataFrame(a)).set_index(['id', 'age', 'state']) \
                          .stack().droplevel(-1).reset_index()

Out[187]:
      id  age state          0
0    123   18    CA 2019-02-17
1    123   18    CA 2019-02-18
2    123   18    CA 2019-02-19
3    123   18    CA 2019-02-20
4    123   18    CA 2019-02-21
5    123   18    CA 2019-02-22
6    123   18    CA 2019-02-23
7    123   18    CA 2019-02-24
8    123   18    CA 2019-02-25
9    123   18    CA 2019-02-26
10   123   18    CA 2019-02-27
11   123   18    CA 2019-02-28
12   123   18    CA 2019-03-01
13   123   18    CA 2019-03-02
14   123   18    CA 2019-03-03
15   123   18    CA 2019-03-04
16   123   18    CA 2019-03-05
17   123   18    CA 2019-03-06
18   123   18    CA 2019-03-07
19   123   18    CA 2019-03-08
20   123   18    CA 2019-03-09
21   123   18    CA 2019-03-10
22   123   18    CA 2019-03-11
23   123   18    CA 2019-03-12
24   123   18    CA 2019-03-13
25   123   18    CA 2019-03-14
26   123   18    CA 2019-03-15
27   123   18    CA 2019-03-16
28   123   18    CA 2019-03-17
29   123   18    CA 2019-03-18
..   ...  ...   ...        ...
94   223   24    AZ 2019-02-03
95   223   24    AZ 2019-02-04
96   223   24    AZ 2019-02-05
97   223   24    AZ 2019-02-06
98   223   24    AZ 2019-02-07
99   223   24    AZ 2019-02-08
100  223   24    AZ 2019-02-09
101  223   24    AZ 2019-02-10
102  223   24    AZ 2019-02-11
103  223   24    AZ 2019-02-12
104  223   24    AZ 2019-02-13
105  223   24    AZ 2019-02-14
106  223   24    AZ 2019-02-15
107  223   24    AZ 2019-02-16
108  223   24    AZ 2019-02-17
109  223   24    AZ 2019-02-18
110  223   24    AZ 2019-02-19
111  223   24    AZ 2019-02-20
112  223   24    AZ 2019-02-21
113  223   24    AZ 2019-02-22
114  223   24    AZ 2019-02-23
115  223   24    AZ 2019-02-24
116  223   24    AZ 2019-02-25
117  223   24    AZ 2019-02-26
118  223   24    AZ 2019-02-27
119  223   24    AZ 2019-02-28
120  223   24    AZ 2019-03-01
121  223   24    AZ 2019-03-02
122  223   24    AZ 2019-03-03
123  223   24    AZ 2019-03-04

[124 rows x 4 columns]

【讨论】:

以上是关于Pandas - 将具有开始和结束日期的数据框转换为每日数据的主要内容,如果未能解决你的问题,请参考以下文章

从一系列开始和结束日期生成熊猫数据框

将日期和列表的元组转换为 Pandas 数据框

是否可以使用 matplotlib 将 x 轴设置为仅显示开始日期和结束日期?

在给定日期时间连续性的情况下,Pandas 输出日期、开始和结束时间以及事件状态

如何使用 pandas.date_range() 在指定的开始日期和结束日期之间获取具有 n 个指定周期(相等)的时间序列

将 unix 时间转换为 pandas 数据框中的可读日期