นุ่นสามารถวางแผนฮิสโตแกรมของวันที่ได้หรือไม่?


106

ฉันใช้ซีรี่ส์ของฉันและบังคับให้เป็นคอลัมน์วันที่และเวลาของ 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?


2
คุณสามารถแสดงตัวอย่างของ df ที่คุณมีได้หรือไม่?
jrjc

คำตอบ:


172

ให้ 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 วันที่เดือน

คุณสามารถแทนที่เดือนต่อปีวัน ฯลฯ ..

ตัวอย่างเช่นหากคุณต้องการแยกปีและเดือนให้ทำดังนี้

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

ซึ่งจะช่วยให้:

groupby วันที่เดือนปี

เป็นสิ่งที่คุณต้องการหรือไม่? นี่ชัดเจนไหม?

หวังว่านี่จะช่วยได้!


1
หากคุณมีข้อมูลที่ครอบคลุมหลายปีข้อมูล "มกราคม" ทั้งหมดจะรวมอยู่ในคอลัมน์เดียวกันเป็นต้นในแต่ละเดือน
drevicko

ใช้ได้ผล แต่สำหรับฉัน (แพนด้า 0.15.2) วันที่ต้องเขียนด้วยตัวพิมพ์ใหญ่ D: df.groupby (df.Date.dt.month) .count (). plot (kind = "bar")
harbun

@drevicko: ที่คาดว่าฉันเชื่อ @harbun: dateหรือDateนี่คือชื่อคอลัมน์ดังนั้นถ้าคอลัมน์ที่มีวันที่เรียกว่า foo จะเป็น:df.foo.dt.month
jrjc

@jeanrjc มองคำถามอีกครั้งฉันเดาว่าคุณพูดถูก สำหรับคนอื่น ๆ เช่นฉันที่ต้องแยกความแตกต่างตามปีมีวิธีง่ายๆgroupbyในการผสมผสานคุณสมบัติสองอย่างของข้อมูลคอลัมน์ (เช่นปีและวันที่) หรือไม่
drevicko

มีวิธีเตรียมวันที่เพื่อให้ฉันสามารถใช้ seaborn.distplot () เพื่อพล็อตฮิสโตแกรมของวันที่ในช่วงวันที่ได้หรือไม่
panc

11

ฉันคิดว่า resample อาจเป็นสิ่งที่คุณกำลังมองหา ในกรณีของคุณให้ทำ:

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

เป็นเพียงการนับไม่ใช่พล็อตดังนั้นคุณต้องสร้างพล็อตของคุณเอง

ดูโพสต์นี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับเอกสารของ resample แพนด้า resample

ฉันประสบปัญหาคล้าย ๆ กับคุณ หวังว่านี่จะช่วยได้


2
howเลิกใช้แล้ว ไวยากรณ์ใหม่คือdf.resample('1M').count()
Dan Weaver

7

ตัวอย่างที่แสดงผล

ป้อนคำอธิบายภาพที่นี่

ตัวอย่างรหัส

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

5

ฉันสามารถแก้ไขปัญหานี้ได้โดย (1) การลงจุดด้วย matplotlib แทนที่จะใช้ dataframe โดยตรงและ (2) ใช้valuesแอตทริบิวต์ ดูตัวอย่าง:

import matplotlib.pyplot as plt

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

วิธีนี้ใช้ไม่ได้ถ้าฉันไม่ใช้valuesแต่ฉันไม่รู้ว่าทำไมมันถึงได้ผล


3

นี่คือวิธีแก้ปัญหาเมื่อคุณต้องการมีฮิสโตแกรมอย่างที่คุณคาดหวัง สิ่งนี้ไม่ใช้ 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()

ฮิสโตแกรมวันที่และเวลา


1

ฉันคิดว่าในการแก้ปัญหานั้นคุณสามารถใช้รหัสนี้ได้ซึ่งจะแปลงประเภทวันที่เป็นประเภท 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()

1
นี่ไม่ได้ตอบคำถามว่าจะพล็อตฮิสโตแกรมวันที่และเวลาที่สั่งซื้อได้อย่างไร
lollercoaster

ฉันคิดว่าปัญหาของคุณในประเภทวันที่และเวลาคุณต้องทำให้เป็นปกติก่อนที่จะวางแผน

คุณสามารถดูลิงค์

1

ฉันก็มีปัญหากับเรื่องนี้เช่นกัน ฉันคิดว่าเมื่อคุณทำงานกับวันที่คุณต้องการรักษาการจัดลำดับตามลำดับเวลา (เหมือนที่ฉันทำ)

วิธีแก้ปัญหาก็คือ

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

ได้โปรดหากใครรู้วิธีที่ดีกว่านี้โปรดพูดขึ้น

แก้ไข: สำหรับยีนส์ด้านบนนี่คือตัวอย่างของข้อมูล [ฉันสุ่มตัวอย่างจากชุดข้อมูลแบบเต็มดังนั้นจึงเป็นข้อมูลฮิสโตแกรมเล็กน้อย]

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

1

คำตอบทั้งหมดนี้ดูซับซ้อนเกินไปอย่างน้อยแพนด้า 'สมัยใหม่' ก็มีสองบรรทัด

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

1
ดูเหมือนว่าจะใช้งานได้ก็ต่อเมื่อคุณมีDataFrameแต่ไม่ใช่ถ้าสิ่งที่คุณมีคือไฟล์Series. คุณจะพิจารณาเพิ่มหมายเหตุในกรณีนั้นหรือไม่
David Z
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.