如何在Seaborn distplot中绘制Pandas datetime系列?

时间:2016-07-25 12:07:37

标签: python pandas seaborn

我有一个带有datetime列的pandas数据帧。我想根据日期列绘制行的分布,但我现在得到一个无用的错误。我有:

df['Date'] = pd.to_datetime(df['Date'], errors='raise')
s = sns.distplot(df['Date'])

抛出错误:

TypeError: ufunc add cannot use operands with types dtype('<M8[ns]') and dtype('<M8[ns]')

如果我更改列我正在绘制数字数据,那么一切正常。如何让datetime列表现得很好?我真的找不到我认为我需要的文档。任何和所有帮助表示赞赏。

以下是df.head(2)的结果,出于安全原因我删除了一些列:

               Date                 
2812         2016-03-05
2813         2016-03-05

显然,该列(作为系列拍摄时)具有属性

Name: Date, dtype: datetime64[ns]

2 个答案:

答案 0 :(得分:1)

我自己遇到相同问题时遇到了这个问题。如评论中所述,似乎seaborn的distplot不支持使用日期。不幸的是,我在官方文档中找不到任何证据来支持这种说法。

我找到了两种方法来解决此问题。它们都不是完美的,但这是我发现的最好的。

选项1:将日期转换为数字

转换为一些数字指标并使用该指标。 displot适用于数字,因此,如果每个日期都由数字表示,则可以。日期和数字之间的映射有点像使用MinMax Scaler。例如,我们可以将“ 2017-01-01”设置为0,将“ 2020-06-06”设置为1,并将它们之间的所有日期映射到[0,1]范围内的值。

要使用的数字范围取决于您的数据范围,可能是天/月/年等。

我将通过这个玩具示例来演示这种方法。

import pandas as pd
import datetime as dt

original_dates = ["2016-03-05", "2016-03-05", "2016-02-05", "2016-02-05", "2016-02-05", "2014-03-05"]
dates_list = [dt.datetime.strptime(date, '%Y-%m-%d').date() for date in original_dates]

df = pd.DataFrame({"Date":dates_list})

现在数据帧如下:

         Date
0  2016-03-05
1  2016-03-05
2  2016-02-05
3  2016-02-05
4  2016-02-05
5  2014-03-05

(当然,这不是将日期输入到数据框的最佳方法,但这并不重要)。

现在,我创建一个新列,该列将保留最短日期之间的天数差异:

df["NewDate"] = df["Date"] - dt.date(2014,3,5)
df["NewDate"] = df["NewDate"].apply(lambda x: x.days)

结果:

         Date  NewDate
0  2016-03-05      731
1  2016-03-05      731
2  2016-02-05      702
3  2016-02-05      702
4  2016-02-05      702
5  2014-03-05        0

请注意,我“硬编码”了最小日期。您可以使用更好的方法来查找最小值,而不是对其进行硬编码。我只是想尽快获得这一部分。

现在我们可以在新列上使用displot

import seaborn as sns
sns.set()
ax = sns.distplot(df['NewDate'])

输出:

Seaborn displot with dates

如您所见,它显示的是日期而不是日期。对于我的个人问题,可以这样显示。如果要将其显示为日期,则需要执行一些额外的步骤:Show xticks which are function of x-axis, not directly the data it self. Example with dates (pandas, matplotlib)

正如我之前所说,我使用了按天数差异进行缩放,但是您可以对数月或数年进行缩放。取决于数据。

选择2:直接使用直方图,无需seaborn的显示

在这个问题中:Can Pandas plot a histogram of dates?有一个答案,如何使用熊猫的groupby用日期绘制直方图。

它与displot不同,但是它可以是足够接近的解决方案(因为分配最终基于matplotlib的历史记录)。

答案 1 :(得分:0)

您可以将日期转换为“分类”类型,并绘制结果代码(整数)。然后,用日期(作为类别)标记x-ticks。

import pandas as pd
import seaborn as sns

original_dates = [
    "2016-03-05", "2016-03-05", "2016-02-05",
    "2016-02-05", "2016-02-05", "2014-03-05"]
dates_list = pd.to_datetime(original_dates)

df = pd.DataFrame({"Date": dates_list})
df['date-as-cat'] = df['Date'].astype('category')  # new 
df['codes'] = df['date-as-cat'].cat.codes          # new 

print(df)
print(df.dtypes)

        Date date-as-cat  codes
0 2016-03-05  2016-03-05      2
1 2016-03-05  2016-03-05      2
2 2016-02-05  2016-02-05      1
3 2016-02-05  2016-02-05      1
4 2016-02-05  2016-02-05      1
5 2014-03-05  2014-03-05      0

Date           datetime64[ns]
date-as-cat          category
codes                    int8
dtype: object 

像这样获取日期为代码和类别为日期的信息:

x = df[['codes', 'date-as-cat']].drop_duplicates().sort_values('codes')
print(x)

   codes date-as-cat
5      0  2014-03-05
2      1  2016-02-05
0      2  2016-03-05