如何在Pandas中绘制日期的核密度图?

12

我有一个Pandas数据框,每个观测值都有一个日期(作为datetime [64]格式的条目列)。这些日期分布在大约5年的时间段内。我想绘制所有观测日期的核密度图,并在x轴上标记年份。

我已经找到了一种方法,可以相对于某个参考日期创建时间差,然后创建每个观测值与参考日期之间的小时/天/年数密度图:

df['relativeDate'].astype('timedelta64[D]').plot(kind='kde')

但这不完全是我想要的:如果我转换为年份差值,则x轴正确,但我会失去年内变化。但如果我采用像小时或天这样较小的时间单位,则x轴标签更难解释。

在Pandas中实现这个最简单的方法是什么?


请看一下Seaborn中的kde-plot:http://stanford.edu/~mwaskom/software/seaborn/generated/seaborn.kdeplot.html - Moritz
2个回答

8

受 @JohnE 回答的启发,将日期转换为数字的另一种方法是使用 .toordinal() 方法。

import pandas as pd
import numpy as np

# simulate some artificial data
# ===============================
np.random.seed(0)
dates = pd.date_range('2010-01-01', periods=31, freq='D')
df = pd.DataFrame(np.random.choice(dates,100), columns=['dates'])
# use toordinal() to get datenum
df['ordinal'] = [x.toordinal() for x in df.dates]

print(df)

        dates  ordinal
0  2010-01-13   733785
1  2010-01-16   733788
2  2010-01-22   733794
3  2010-01-01   733773
4  2010-01-04   733776
5  2010-01-28   733800
6  2010-01-04   733776
7  2010-01-08   733780
8  2010-01-10   733782
9  2010-01-20   733792
..        ...      ...
90 2010-01-19   733791
91 2010-01-28   733800
92 2010-01-01   733773
93 2010-01-15   733787
94 2010-01-04   733776
95 2010-01-22   733794
96 2010-01-13   733785
97 2010-01-26   733798
98 2010-01-11   733783
99 2010-01-21   733793

[100 rows x 2 columns]    

# plot non-parametric kde on numeric datenum
ax = df['ordinal'].plot(kind='kde')
# rename the xticks with labels
x_ticks = ax.get_xticks()
ax.set_xticks(x_ticks[::2])
xlabels = [datetime.datetime.fromordinal(int(x)).strftime('%Y-%m-%d') for x in x_ticks[::2]]
ax.set_xticklabels(xlabels)

enter image description here


3
好的回答。这比我的回答更健壮,因为它可以正确处理闰年和起始日期不是1月1日的情况。我建议将其作为采纳的答案。 - JohnE

5

我想可能有更好更自动的方法来完成这个任务,但如果没有,那么这应该是一个不错的解决办法。首先,让我们设置一些样本数据:

np.random.seed(479)
start_date = '2011-1-1'
df = pd.DataFrame({ 'date':np.random.choice( 
                    pd.date_range(start_date, periods=365*5, freq='D'), 50) })

df['rel'] = df['date'] - pd.to_datetime(start_date)
df.rel = df.rel.astype('timedelta64[D]')

        date   rel
0 2014-06-06  1252
1 2011-10-26   298
2 2013-08-24   966
3 2014-09-25  1363
4 2011-12-23   356

从这里可以看出,“rel”只是距离起始日的天数。它本质上是一个整数,因此您只需要根据起始日期进行归一化即可。

df['year_as_float'] = pd.to_datetime(start_date).year + df.rel / 365.

        date   rel  year_as_float
0 2014-06-06  1252    2014.430137
1 2011-10-26   298    2011.816438
2 2013-08-24   966    2013.646575
3 2014-09-25  1363    2014.734247
4 2011-12-23   356    2011.975342

如果日期不是从1月1日开始,您需要稍微调整一下。如果您只是在5年内制作KDE图,那么忽略闰年并不是一个实际问题,但如果您想要做其他事情,这可能会有所影响。

这是绘图:

df['year_as_float']d.plot(kind='kde')

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接