Können Pandas ein Histogramm von Daten zeichnen?

100

Ich habe meine Serie genommen und sie in eine Datums- / Uhrzeitspalte von dtype = gezwungen datetime64[ns](obwohl ich nur eine Tagesauflösung benötige ... nicht sicher, wie ich sie ändern soll).

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

aber das Plotten funktioniert nicht:

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

Ich möchte ein Histogramm zeichnen, das nur die Anzahl der Daten nach Woche, Monat oder Jahr anzeigt .

Sicher gibt es eine Möglichkeit, dies zu tun pandas?

Lollercoaster
quelle
2
Kannst du ein Beispiel deines df zeigen?
jrjc

Antworten:

164

Angesichts dieser 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

und wenn es nicht schon der Fall ist:

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

So zeigen Sie die Anzahl der Daten pro Monat an:

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

.dt Ermöglicht den Zugriff auf die datetime-Eigenschaften.

Welches wird Ihnen geben:

Gruppiert nach Datum Monat

Sie können Monat für Jahr, Tag usw. ersetzen.

Wenn Sie beispielsweise Jahr und Monat unterscheiden möchten, gehen Sie einfach wie folgt vor:

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

Welches gibt:

Gruppiert nach Datum Monat Jahr

War es was du wolltest? Ist das klar?

Hoffe das hilft !

jrjc
quelle
1
Wenn Sie Daten über mehrere Jahre haben, werden alle Januar-Daten für jeden Monat in dieselbe Spalte usw. eingefügt.
Drevicko
Funktioniert, aber für mich (Pandas 0.15.2) müssen Daten mit Großbuchstaben D geschrieben werden: df.groupby (df.Date.dt.month) .count (). Plot (kind = "bar")
harbun
@drevicko: Das wird erwartet, glaube ich. @harbun: dateoder Datehier sind Spaltennamen. Wenn Ihre Spalte mit Datumsangaben also foo heißt, wäre dies:df.foo.dt.month
jrjc
@jeanrjc Wenn Sie sich die Frage noch einmal ansehen, haben Sie wohl Recht. Gibt es für andere wie mich, die auch nach Jahren unterscheiden müssen, eine einfache Möglichkeit, groupbyKombinationen aus zwei Attributen von Spaltendaten (z. B. Jahr und Datum) zu erstellen?
Drevicko
Gibt es eine Möglichkeit, die Daten so vorzubereiten, dass ich mit seaborn.distplot () das Histogramm der Daten über Daten zeichnen kann?
Panc
11

Ich denke, Resample könnte das sein, wonach Sie suchen. In Ihrem Fall tun Sie:

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

Es wird nur gezählt und nicht die Handlung, also müssen Sie Ihre eigenen Handlungen erstellen.

In diesem Beitrag finden Sie weitere Informationen zur Dokumentation der Resample- Pandas-Resample-Dokumentation

Ich bin auf ähnliche Probleme gestoßen wie Sie. Hoffe das hilft.

Ethan
quelle
2
howist veraltet. Die neue Syntax istdf.resample('1M').count()
Dan Weaver
6

Beispiel gerendert

Geben Sie hier die Bildbeschreibung ein

Beispielcode

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

Ich konnte dies umgehen, indem ich (1) mit matplotlib plottete, anstatt den Datenrahmen direkt zu verwenden, und (2) das valuesAttribut verwendete. Siehe Beispiel:

import matplotlib.pyplot as plt

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

Das funktioniert nicht, wenn ich es nicht benutze values, aber ich weiß nicht, warum es funktioniert.

abeboparebop
quelle
2

Hier ist eine Lösung, wenn Sie nur ein Histogramm haben möchten, wie Sie es erwarten. Dies verwendet nicht groupby, sondern konvertiert datetime-Werte in Ganzzahlen und ändert die Beschriftungen im Plot. Es könnten einige Verbesserungen vorgenommen werden, um die Häkchenbeschriftungen an gleichmäßige Stellen zu verschieben. Auch bei Annäherung ist ein Kernel-Dichteschätzungsdiagramm (und jedes andere Diagramm) möglich.

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-Histogramm

JulianWgs
quelle
1

Ich denke, um dieses Problem zu lösen, können Sie diesen Code verwenden. Er konvertiert den Datumstyp in int-Typen:

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

Um nur das Datum zu erhalten, können Sie diesen Code hinzufügen:

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

quelle
1
Dies beantwortet nicht die Frage, wie ein geordnetes Datum / Uhrzeit-Histogramm gezeichnet werden soll.
Lollercoaster
Ich denke, Ihr Problem bei datetime Typ, müssen Sie normalisieren, bevor Sie zeichnen
Sie können diesen Link
1

Ich hatte auch nur Probleme damit. Ich stelle mir vor, dass Sie, da Sie mit Daten arbeiten, die chronologische Reihenfolge beibehalten möchten (wie ich).

Die Problemumgehung ist dann

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

Bitte, wenn jemand einen besseren Weg kennt, sprechen Sie bitte.

BEARBEITEN: Für Jean oben ist hier eine Auswahl der Daten [Ich habe zufällig aus dem vollständigen Datensatz eine Stichprobe gezogen, daher die trivialen Histogrammdaten.]

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

Ausgabe:

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
EngineeredE
quelle
1

Alle diese Antworten scheinen zu komplex zu sein, zumindest bei "modernen" Pandas sind es zwei Zeilen.

df.set_index('date', inplace=True)
df.resample('M').size().plot.bar()
Briford Wylie
quelle
1
Dies scheint nur zu funktionieren, wenn Sie eine haben DataFrame, aber nicht, wenn Sie nur eine haben Series. Würden Sie in Betracht ziehen, einen Hinweis zu diesem Fall hinzuzufügen?
David Z