Bisakah Panda memplot histogram tanggal?

101

Saya telah mengambil Seri saya dan memaksanya ke kolom tanggal waktu dtype = datetime64[ns](meskipun hanya membutuhkan resolusi hari ... tidak yakin bagaimana mengubahnya).

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

tetapi merencanakan tidak berhasil:

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

Saya ingin memplot histogram yang hanya menunjukkan jumlah tanggal berdasarkan minggu, bulan, atau tahun .

Tentunya ada cara untuk melakukan ini pandas?

lollercoaster
sumber
2
dapatkah Anda menunjukkan contoh df yang Anda miliki?
jrjc

Jawaban:

164

Diberikan df ini:

        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

dan, jika belum demikian:

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

Untuk menunjukkan hitungan tanggal per bulan:

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

.dt memungkinkan Anda mengakses properti datetime.

Yang akan memberi Anda:

dikelompokkan berdasarkan tanggal bulan

Anda dapat mengganti bulan demi tahun, hari, dll.

Jika Anda ingin membedakan tahun dan bulan misalnya, lakukan saja:

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

Pemberian yang mana:

dikelompokkan berdasarkan tanggal bulan tahun

Apakah itu yang Anda inginkan? Apakah ini jelas?

Semoga ini membantu !

jrjc
sumber
1
Jika Anda memiliki data dalam rentang beberapa tahun, semua data 'januari' dimasukkan ke dalam kolom yang sama dan seterusnya untuk setiap bulan.
drevicko
Bisa, tapi bagi saya (panda 0.15.2) tanggal harus ditulis dengan huruf kapital D: df.groupby (df.Date.dt.month) .count (). Plot (kind = "bar")
harbun
@drevicko: Saya yakin itu yang diharapkan. @harbun: dateatau di Datesini adalah nama kolom, jadi jika kolom Anda dengan tanggal disebut foo, itu akan menjadi:df.foo.dt.month
jrjc
@jeanrjc Melihat lagi pertanyaan itu, saya rasa Anda benar. Untuk orang lain seperti saya yang juga perlu membedakan menurut tahun, adakah cara sederhana untuk groupbymenggunakan kombinasi dua atribut data kolom (misalnya: tahun dan tanggal)?
drevicko
Apakah ada cara untuk menyiapkan tanggal sehingga saya dapat menggunakan seaborn.distplot () untuk memplot histogram tanggal di atas tanggal?
panc
11

Saya pikir resample mungkin apa yang Anda cari. Dalam kasus Anda, lakukan:

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

Itu hanya melakukan penghitungan dan bukan plot, jadi Anda kemudian harus membuat plot sendiri.

Lihat posting ini untuk detail lebih lanjut tentang dokumentasi dokumentasi resample panda

Saya mengalami masalah yang sama seperti Anda. Semoga ini membantu.

Ethan
sumber
2
howsudah ditinggalkan. Sintaks baru adalahdf.resample('1M').count()
Dan Weaver
6

Contoh yang diberikan

masukkan deskripsi gambar di sini

Kode Contoh

#!/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)
Martin Thoma
sumber
5

Saya dapat mengatasi ini dengan (1) membuat plot dengan matplotlib daripada menggunakan dataframe secara langsung dan (2) menggunakan valuesatribut. Lihat contoh:

import matplotlib.pyplot as plt

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

Ini tidak berfungsi jika saya tidak menggunakannya values, tetapi saya tidak tahu mengapa ini berhasil.

abeboparebop
sumber
3

Berikut adalah solusi saat Anda hanya ingin memiliki histogram seperti yang Anda harapkan. Ini tidak menggunakan groupby, tetapi mengonversi nilai datetime menjadi integer dan mengubah label pada plot. Beberapa perbaikan dapat dilakukan untuk memindahkan label centang ke lokasi yang rata. Juga dengan pendekatan plot estimasi kepadatan kernel (dan plot lainnya) juga dimungkinkan.

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

Histogram waktu

JulianWgs
sumber
1

Saya pikir untuk memecahkan masalah itu, Anda dapat menggunakan kode ini, itu mengubah tipe tanggal menjadi tipe int:

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

untuk mendapatkan tanggal saja, Anda dapat menambahkan kode ini:

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

sumber
1
ini tidak menjawab pertanyaan tentang bagaimana merencanakan histogram datetime yang dipesan?
lollercoaster
Saya pikir masalah Anda pada tipe datetime, Anda harus menormalkan sebelum Anda plot
Anda juga dapat melihat tautan
1

Saya hanya mengalami masalah dengan ini juga. Saya membayangkan bahwa karena Anda bekerja dengan tanggal, Anda ingin mempertahankan urutan kronologis (seperti yang saya lakukan.)

Solusinya adalah

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

Tolong, jika ada yang tahu cara yang lebih baik, silakan angkat bicara.

EDIT: untuk jean di atas, berikut adalah contoh datanya [Saya secara acak mengambil sampel dari kumpulan data lengkap, karenanya data histogram sepele.]

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

Keluaran:

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
Direkayasa
sumber
1

Semua jawaban ini tampak terlalu rumit, paling tidak dengan panda 'modern', hanya ada dua baris.

df.set_index('date', inplace=True)
df.resample('M').size().plot.bar()
Briford Wylie
sumber
1
Ini tampaknya berfungsi hanya jika Anda memiliki DataFrame, tetapi tidak jika yang Anda miliki hanyalah a Series. Apakah Anda akan mempertimbangkan untuk menambahkan catatan tentang kasus itu?
David Z