I Panda possono tracciare un istogramma di date?


101

Ho preso la mia serie e l'ho costretta a una colonna datetime di dtype = datetime64[ns](anche se ho solo bisogno della risoluzione del giorno ... non sono sicuro di come cambiare).

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

ma la stampa non funziona:

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

Vorrei tracciare un istogramma che mostri solo il conteggio delle date per settimana, mese o anno .

Sicuramente c'è un modo per farlo pandas?


2
puoi mostrare un campione del df che hai?
jrjc

Risposte:


164

Dato questo 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

e, se non è già il caso:

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

Per mostrare il conteggio delle date per mese:

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

.dt ti permette di accedere alle proprietà datetime.

Che ti darà:

groupby data mese

Puoi sostituire mese per anno, giorno, ecc.

Ad esempio, se vuoi distinguere anno e mese, fai semplicemente:

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

Che dà:

groupby data mese anno

Era quello che volevi? È chiaro?

Spero che questo ti aiuti !


1
Se si dispone di dati che coprono diversi anni, tutti i dati di "gennaio" vengono inseriti nella stessa colonna e così via per ogni mese.
drevicko

Funziona, ma per me (pandas 0.15.2) le date devono essere scritte con la D maiuscola: df.groupby (df.Date.dt.month) .count (). Plot (kind = "bar")
harbun

@drevicko: questo è previsto, credo. @harbun: dateo Datequi ci sono i nomi delle colonne, quindi se la tua colonna con le date si chiama foo, sarebbe:df.foo.dt.month
jrjc

@ jeanrjc Guardando di nuovo la domanda, immagino che tu abbia ragione. Per altri come me che hanno bisogno di distinguere anche per anni, esiste un modo semplice per groupbycombinare due attributi di dati di una colonna (ad esempio: anno e data)?
drevicko

C'è un modo per preparare le date in modo da poter usare seaborn.distplot () per tracciare l'istogramma delle date rispetto alle date?
pancetta

11

Penso che il ricampionamento potrebbe essere quello che stai cercando. Nel tuo caso, fai:

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

Sta solo facendo il conteggio e non la trama, quindi devi creare le tue trame.

Vedi questo post per maggiori dettagli sulla documentazione del ricampionamento panda ricampionati

Ho riscontrato problemi simili a te. Spero che questo ti aiuti.


2
howè deprecato. La nuova sintassi èdf.resample('1M').count()
Dan Weaver

6

Esempio di rendering

inserisci qui la descrizione dell'immagine

Codice di esempio

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

Sono stato in grado di aggirare questo problema (1) tracciando con matplotlib invece di utilizzare direttamente il dataframe e (2) utilizzando l' valuesattributo. Vedi esempio:

import matplotlib.pyplot as plt

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

Questo non funziona se non lo uso values, ma non so perché funziona.


3

Ecco una soluzione per quando vuoi solo avere un istogramma come te lo aspetti. Questo non usa groupby, ma converte i valori datetime in numeri interi e cambia le etichette sul grafico. È possibile apportare alcuni miglioramenti per spostare le etichette di spunta in posizioni pari. Inoltre, con l'approccio è possibile anche un grafico di stima della densità del kernel (e qualsiasi altro grafico).

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

Istogramma data / ora


1

Penso che per risolvere questo problema, puoi usare questo codice, converte il tipo di data in tipi int:

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

solo per ottenere la data, puoi aggiungere questo codice:

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

1
questo non risponde alla domanda su come tracciare un istogramma datetime ordinato?
lollercoaster

Penso che il tuo problema con il tipo datetime, devi normalizzare prima di tracciare

Puoi anche vedere questo link

1

Avevo problemi anche con questo. Immagino che dal momento che stai lavorando con le date vuoi preservare l'ordine cronologico (come ho fatto io).

La soluzione è quindi

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

Per favore, se qualcuno conosce un modo migliore per favore, parli.

EDIT: per jean sopra, ecco un campione dei dati [Ho campionato in modo casuale dal set di dati completo, da qui i dati banali dell'istogramma.]

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

Produzione:

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

Tutte queste risposte sembrano eccessivamente complesse, almeno con i panda "moderni" sono due righe.

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

1
Questo sembra funzionare solo se hai un DataFrame, ma non se tutto ciò che hai è un Series. Prenderesti in considerazione l'aggiunta di una nota su quel caso?
David Z
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.