【问题标题】:Can Pandas plot a histogram of dates?Pandas 可以绘制日期直方图吗?
【发布时间】:2015-02-06 13:11:30
【问题描述】:

我已将我的系列强制转换为 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 肯定有办法做到这一点?

【问题讨论】:

  • 你能展示一个你拥有的df样本吗?

标签: python pandas matplotlib time-series


【解决方案1】:

鉴于这个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 允许您访问日期时间属性。

这会给你:

您可以逐年、逐日等替换月份。

例如,如果您想区分年份和月份,只需执行以下操作:

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

这给出了:

这是你想要的吗?这清楚吗?

希望这会有所帮助!

【讨论】:

  • 如果您的数据跨越数年,则每个月的所有“一月”数据都会放入同一列,依此类推。
  • 有效,但对我来说(pandas 0.15.2)日期必须用大写 D:df.groupby(df.Date.dt.month).count().plot(kind="酒吧")
  • @drevicko:我相信这是意料之中的。 @harbun:dateDate 这里是列名,所以如果你的日期列被称为 foo,它将是:df.foo.dt.month
  • @jeanrjc 再看问题,我想你是对的。对于像我这样也需要按年份区分的其他人,是否有一种简单的方法来groupby 对列数据的两个属性的组合(例如:年份和日期)?
  • 有没有办法准备日期,以便我可以使用 seaborn.distplot() 绘制日期的直方图?
【解决方案2】:

我认为 resample 可能是您正在寻找的。在您的情况下,请执行以下操作:

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

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

有关重采样文档的更多详细信息,请参阅此帖子 pandas resample documentation

我遇到了和你类似的问题。希望这会有所帮助。

【讨论】:

  • how 已弃用。新语法是df.resample('1M').count()
【解决方案3】:

渲染示例

示例代码

#!/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)

【讨论】:

    【解决方案4】:

    当您只想拥有一个您所期望的直方图时,这是一个解决方案。这不使用 groupby,而是将日期时间值转换为整数并更改绘图上的标签。可以进行一些改进以将刻度标签移动到均匀的位置。此外,通过方法,核密度估计图(和任何其他图)也是可能的。

    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()
    

    【讨论】:

    • labels = pd.to_datetime(labels).strftime('%-m/%-d') 可以帮助清理那些刻度标签。
    【解决方案5】:

    我能够通过 (1) 使用 matplotlib 绘图而不是直接使用数据框和 (2) 使用 values 属性来解决这个问题。见例子:

    import matplotlib.pyplot as plt
    
    ax = plt.gca()
    ax.hist(column.values)
    

    如果我不使用values,这不起作用,但我不知道为什么它会起作用。

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

      • 这似乎只在你有一个DataFrame 时才有效,但如果你只有一个Series 就不行。你会考虑在那个案例上添加注释吗?
      【解决方案7】:

      我认为为了解决这个问题,你可以使用这段代码,它将日期类型转换为 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()
      

      【讨论】:

      • 这没有回答如何绘制有序日期时间直方图的问题?
      • 我认为你的问题是日期时间类型的,你必须在绘图之前进行标准化
      • 你也可以看到这个link
      【解决方案8】:

      我也遇到了麻烦。我想,由于您正在处理日期,因此您希望保留时间顺序(就像我所做的那样。)

      那么解决方法是

      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
      

      【讨论】:

        【解决方案9】:

        我在尝试用“bar”绘制时间序列时被困了很长时间。当试图绘制具有不同索引的两个时间序列时,它会变得非常奇怪,例如每日和每月数据。然后我重新阅读了该文档,并且 matplotlib 文档确实明确指出该栏是用于分类数据的。 使用的绘图函数是step。

        【讨论】:

          【解决方案10】:

          随着最近的 matplotlib 版本,这个限制似乎被解除了。 您现在可以使用 Axes.bar 绘制时间序列。

          使用默认选项,条形以横坐标给出的日期为中心,宽度为 0.8 天。条形位置可以通过“align”参数移动,宽度可以指定为标量或与横坐标列表具有相同维度的列表。

          只需添加以下行即可获得漂亮的日期标签,无论缩放系数如何:

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

          【讨论】:

            猜你喜欢
            • 2020-04-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-11-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多