熊猫能绘制出日期的直方图吗?

我将 Series 强制转换为 dtype = datetime64[ns]的日期时间列(尽管只需要日分辨率... ... 不知道如何更改)。

import pandas as pd
df = pd.read_csv('somefile.csv')
column = df['date']
column = pd.to_datetime(column, coerce=True)

但密谋是行不通的:

ipdb> column.plot(kind='hist')
*** TypeError: ufunc add cannot use operands with types dtype('<M8[ns]') and dtype('float64')

我想绘制一个只有 显示按周、月或年分列的日期计数的直方图。

pandas中肯定有办法做到这一点吧?

142935 次浏览

我认为为了解决这个问题,你可以使用这个代码,它将日期类型转换为 int 类型:

df['date'] = df['date'].astype(int)
df['date'] = pd.to_datetime(df['date'], unit='s')

为了只获取日期,可以添加以下代码:

pd.DatetimeIndex(df.date).normalize()
df['date'] = pd.DatetimeIndex(df.date).normalize()

我只是在这方面也遇到了麻烦。我可以想象,既然您处理的是日期,那么您就希望保留按时间顺序排列的顺序(就像我一样)

那么解决办法就是

import matplotlib.pyplot as plt
counts = df['date'].value_counts(sort=False)
plt.bar(counts.index,counts)
plt.show()

如果有人知道更好的办法,请说出来。

编辑: 对于上面的 jean,这里是一个数据样本[我从完整的数据集中随机抽样,因此得到了平凡的直方图数据。]

print dates
type(dates),type(dates[0])
dates.hist()
plt.show()

产出:

0    2001-07-10
1    2002-05-31
2    2003-08-29
3    2006-06-21
4    2002-03-27
5    2003-07-14
6    2004-06-15
7    2002-01-17
Name: Date, dtype: object
<class 'pandas.core.series.Series'> <type 'datetime.date'>


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-38-f39e334eece0> in <module>()
2 print dates
3 print type(dates),type(dates[0])
----> 4 dates.hist()
5 plt.show()


/anaconda/lib/python2.7/site-packages/pandas/tools/plotting.pyc in hist_series(self, by, ax, grid, xlabelsize, xrot, ylabelsize, yrot, figsize, bins, **kwds)
2570         values = self.dropna().values
2571
-> 2572         ax.hist(values, bins=bins, **kwds)
2573         ax.grid(grid)
2574         axes = np.array([ax])


/anaconda/lib/python2.7/site-packages/matplotlib/axes/_axes.pyc in hist(self, x, bins, range, normed, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, **kwargs)
5620             for xi in x:
5621                 if len(xi) > 0:
-> 5622                     xmin = min(xmin, xi.min())
5623                     xmax = max(xmax, xi.max())
5624             bin_range = (xmin, xmax)


TypeError: can't compare datetime.date to float

考虑到这个 df:

        date
0 2001-08-10
1 2002-08-31
2 2003-08-29
3 2006-06-21
4 2002-03-27
5 2003-07-14
6 2004-06-15
7 2003-08-14
8 2003-07-29

而且,如果情况还不是这样的话:

df["date"] = df["date"].astype("datetime64")

按月显示日期的计数:

df.groupby(df["date"].dt.month).count().plot(kind="bar")

.dt允许您访问日期时间属性。

这会给你:

groupby date month

你可以按年、按日、按月更换。

例如,如果你想区分年份和月份,只要做:

df.groupby([df["date"].dt.year, df["date"].dt.month]).count().plot(kind="bar")

结果是:

groupby date month year

我认为重新采样可能是你所寻找的。在你的情况下,做:

df.set_index('date', inplace=True)
# for '1M' for 1 month; '1W' for 1 week; check documentation on offset alias
df.resample('1M').count()

它只是做计数,而不是情节,所以你必须做你自己的情节。

有关重新取样的文档的更多详细信息,请参阅本文 熊猫重新样本文件

我也遇到过类似的问题,希望这能有所帮助。

我能够通过(1)使用 matplotlib 而不是直接使用数据框架进行绘图,以及(2)使用 values属性来解决这个问题。例如:

import matplotlib.pyplot as plt


ax = plt.gca()
ax.hist(column.values)

如果我不使用 values,它就不能工作,但我不知道它为什么能工作。

演示的例子

enter image description here

示例代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-


"""Create random datetime object."""


# core modules
from datetime import datetime
import random


# 3rd party modules
import pandas as pd
import matplotlib.pyplot as plt




def visualize(df, column_name='start_date', color='#494949', title=''):
"""
Visualize a dataframe with a date column.


Parameters
----------
df : Pandas dataframe
column_name : str
Column to visualize
color : str
title : str
"""
plt.figure(figsize=(20, 10))
ax = (df[column_name].groupby(df[column_name].dt.hour)
.count()).plot(kind="bar", color=color)
ax.set_facecolor('#eeeeee')
ax.set_xlabel("hour of the day")
ax.set_ylabel("count")
ax.set_title(title)
plt.show()




def create_random_datetime(from_date, to_date, rand_type='uniform'):
"""
Create random date within timeframe.


Parameters
----------
from_date : datetime object
to_date : datetime object
rand_type : {'uniform'}


Examples
--------
>>> random.seed(28041990)
>>> create_random_datetime(datetime(1990, 4, 28), datetime(2000, 12, 31))
datetime.datetime(1998, 12, 13, 23, 38, 0, 121628)
>>> create_random_datetime(datetime(1990, 4, 28), datetime(2000, 12, 31))
datetime.datetime(2000, 3, 19, 19, 24, 31, 193940)
"""
delta = to_date - from_date
if rand_type == 'uniform':
rand = random.random()
else:
raise NotImplementedError('Unknown random mode \'{}\''
.format(rand_type))
return from_date + rand * delta




def create_df(n=1000):
"""Create a Pandas dataframe with datetime objects."""
from_date = datetime(1990, 4, 28)
to_date = datetime(2000, 12, 31)
sales = [create_random_datetime(from_date, to_date) for _ in range(n)]
df = pd.DataFrame({'start_date': sales})
return df




if __name__ == '__main__':
import doctest
doctest.testmod()
df = create_df()
visualize(df)

这里有一个解决方案,当你只是想有一个直方图一样,你期望它。这不使用 groupby,而是将 datetime 值转换为整数并更改绘图上的标签。可以做一些改进,将蜱标签移动到均匀的位置。也可以接近一个核密度估计阴谋(和任何其他阴谋)。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


df = pd.DataFrame({"datetime": pd.to_datetime(np.random.randint(1582800000000000000, 1583500000000000000, 100, dtype=np.int64))})
fig, ax = plt.subplots()
df["datetime"].astype(np.int64).plot.hist(ax=ax)
labels = ax.get_xticks().tolist()
labels = pd.to_datetime(labels)
ax.set_xticklabels(labels, rotation=90)
plt.show()

Datetime histogram

所有这些答案似乎都过于复杂,至少对于“现代”熊猫来说,这是两条线。

df.set_index('date', inplace=True)
df.resample('M').size().plot.bar()

如果你有一个 DatetimeIndex的序列,那么只要运行第二行

series.resample('M').size().plot.bar() # Just counts the rows/month
or
series.resample('M').sum().plot.bar(). # Sums up the values in the series

我花了很长时间试图用“酒吧”来绘制时间序列。当试图用不同的索引绘制两个时间序列时,就会变得非常奇怪,比如每日和每月的数据。然后我重新阅读文档,matplotlib 文档确实明确指出 bar 是用于分类数据的。 要使用的绘图函数是 step。

在最近的 matplotlib 版本中,这个限制似乎被取消了。 现在可以使用 Axes.bar 绘制时间序列。

使用默认选项,条形图以给定的断裂日期为中心,宽度为0.8天。酒吧的位置可以移动与“对齐”参数和宽度可以指定为一个标量或一个相同的维度列表作为脱落列表。

只需添加以下行,就可以拥有不同缩放因子的漂亮日期标签:

plt.rcParams['date.converter'] = 'concise'