Können Pandas Daten automatisch erkennen?


150

Heute war ich positiv überrascht, dass Pandas beim Lesen von Daten aus einer Datendatei (zum Beispiel) Wertetypen erkennen kann:

df = pandas.read_csv('test.dat', delimiter=r"\s+", names=['col1','col2','col3'])

Zum Beispiel kann es folgendermaßen überprüft werden:

for i, r in df.iterrows():
    print type(r['col1']), type(r['col2']), type(r['col3'])

Insbesondere Ganzzahlen, Gleitkommazahlen und Zeichenfolgen wurden korrekt erkannt. Ich habe jedoch eine Spalte mit Datumsangaben im folgenden Format : 2013-6-4. Diese Daten wurden als Zeichenfolgen erkannt (nicht als Python-Datumsobjekte). Gibt es eine Möglichkeit, Pandas zu anerkannten Daten zu "lernen"?


Bitte geben Sie für diese Art von versionabhängiger Frage immer die Pandas-Version an. Im Juli 2013 wäre dies v0.11
smci

Und die d-Typen sind für jede Spalte festgelegt. Sie müssen sie nicht durchlaufen df.iterrows()und für jede einzelne Zeile anzeigen, sondern nur df.info()einmal.
smci

Antworten:


325

Sie sollten hinzufügen parse_dates=Trueoder parse_dates=['column name']beim Lesen, dass dies normalerweise ausreicht, um es auf magische Weise zu analysieren. Es gibt jedoch immer seltsame Formate, die manuell definiert werden müssen. In diesem Fall können Sie auch eine Datums-Parser-Funktion hinzufügen, die so flexibel wie möglich ist.

Angenommen, Sie haben eine Spalte 'datetime' mit Ihrer Zeichenfolge, dann:

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)

Auf diese Weise können Sie sogar mehrere Spalten zu einer einzigen Datum / Uhrzeit-Spalte kombinieren. Dadurch werden eine 'Datum'- und eine' Zeit'-Spalte zu einer einzigen 'Datum / Uhrzeit'-Spalte zusammengeführt:

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)

Auf strptimeund strftime auf dieser Seite finden Sie Anweisungen (dh die Buchstaben, die für verschiedene Formate verwendet werden sollen) .


8
Hat bei mir nicht funktioniert, ich habe folgenden Fehler bekommen:TypeError: strptime() argument 1 must be str, not float
Jean Paul

6
Ich habe diesen Fehler erhalten, weil sich in meinem Datenrahmen Nan befanden.
Jean Paul

Können Sie einen Artikel hinzufügen, der auch das nicht analysierbare Material oder NaN oder / Ns NaTs. denn es scheint, dass dieser Parser die gesamte Spalte komplett überspringt, wenn so etwas vorhanden ist
Amir

Es gibt eine Option infer_datetime_format: "Pandas versuchen, das Format der Datums- / Uhrzeitzeichenfolgen in den Spalten abzuleiten". Dies kann anstelle von verwendet werden date_parser.
Winand

1
Beachten Sie, dass wenn Ihre Daten im ISO 8601Format vorliegen, Sie keine infer_datetime_formatParser-Funktion übergeben sollten - dies ist viel langsamer, als wenn Pandas damit umgehen (insbesondere letzteres). Das Datumsformat in dieser Antwort fällt ebenfalls in diese Kategorie
Mr_and_Mrs_D

20

Möglicherweise hat sich die Pandas-Oberfläche geändert, seit @Rutger geantwortet hat, aber in der von mir verwendeten Version (0.15.2) date_parsererhält die Funktion eine Liste mit Datumsangaben anstelle eines einzelnen Werts. In diesem Fall sollte sein Code folgendermaßen aktualisiert werden:

dateparse = lambda dates: [pd.datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in dates]

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)

11

Die Methode pandas read_csv eignet sich hervorragend zum Parsen von Daten. Vollständige Dokumentation unter http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

Sie können sogar die verschiedenen Datumsteile in verschiedenen Spalten haben und den Parameter übergeben:

parse_dates : boolean, list of ints or names, list of lists, or dict
If True -> try parsing the index. If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a
separate date column. If [[1, 3]] -> combine columns 1 and 3 and parse as a single date
column. {‘foo : [1, 3]} -> parse columns 1, 3 as date and call result foo

Die Standarderkennung von Datumsangaben funktioniert hervorragend, scheint jedoch auf nordamerikanische Datumsformate ausgerichtet zu sein. Wenn Sie woanders wohnen, werden Sie gelegentlich von den Ergebnissen überrascht. Soweit ich mich erinnern kann, bedeutet der 06.01.2000 den 6. Januar in den USA im Gegensatz zum 1. Juni, wo ich wohne. Es ist klug genug, sie herumzuschwingen, wenn Daten wie 23/6/2000 verwendet werden. Wahrscheinlich ist es jedoch sicherer, bei JJJJMMTT-Datumsvariationen zu bleiben. Entschuldigung an Pandas-Entwickler, aber ich habe es in letzter Zeit nicht mit lokalen Daten getestet.

Mit dem Parameter date_parser können Sie eine Funktion zum Konvertieren Ihres Formats übergeben.

date_parser : function
Function to use for converting a sequence of string columns to an array of datetime
instances. The default uses dateutil.parser.parser to do the conversion.

2
Sie können dayfirstfür europäische / internationale Daten als True angeben . pandas.pydata.org/pandas-docs/stable/generated/…
Will Gordon

10

Sie können pandas.to_datetime()wie in der Dokumentation empfohlen Folgendes verwenden für pandas.read_csv():

Wenn eine Spalte oder ein Index ein nicht analysierbares Datum enthält, wird die gesamte Spalte oder der gesamte Index unverändert als Objektdatentyp zurückgegeben. Verwenden Sie für nicht standardmäßiges Parsen von Datum und Uhrzeit pd.to_datetimenach pd.read_csv.

Demo:

>>> D = {'date': '2013-6-4'}
>>> df = pd.DataFrame(D, index=[0])
>>> df
       date
0  2013-6-4
>>> df.dtypes
date    object
dtype: object
>>> df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d')
>>> df
        date
0 2013-06-04
>>> df.dtypes
date    datetime64[ns]
dtype: object

Es werden auch andere Spalten konvertiert, die vom Objekttyp sind
ratnesh

10

Beim Zusammenführen von zwei Spalten zu einer einzelnen Datums- / Uhrzeitspalte generiert die akzeptierte Antwort einen Fehler (Pandas Version 0.20.3), da die Spalten separat an die Funktion date_parser gesendet werden.

Folgendes funktioniert:

def dateparse(d,t):
    dt = d + " " + t
    return pd.datetime.strptime(dt, '%d/%m/%Y %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)

1
Ich benutze Pandas 0.22 und bin damit einverstanden, dass die akzeptierte Antwort nicht mehr funktioniert.
Dai

Dies erzeugt einen "TypeError: kann nur str (nicht" float ") mit str" für mich verketten.
Datumsspalte

8

Ja - laut pandas.read_csv Dokumentation :

Hinweis: Für iso8601-formatierte Daten existiert ein schneller Pfad .

Wenn Ihre CSV-Datei eine Spalte mit dem Namen hat datetimeund das Datum beispielsweise so aussieht 2013-01-01T01:01, werden Pandas (ich bin in Version 0.19.2) das Datum und die Uhrzeit automatisch erfassen:

df = pd.read_csv('test.csv', parse_dates=['datetime'])

Beachten Sie, dass Sie explizit übergeben müssen parse_dates, es funktioniert nicht ohne.

Überprüfen Sie mit:

df.dtypes

Sie sollten sehen, dass der Datentyp der Spalte ist datetime64[ns]


Ich denke, Sie verstehen die Frage falsch. Der Benutzer ist neugierig, ob die Option für sein Zeichenfolgenformat aktiviert werden könnte.
Arya McCarthy

@AryaMcCarthy umm, er möchte im Grunde, dass das Datum korrekt erkannt wird, daher erwähne ich, wie er die Quelldaten so transformieren kann, dass sie von Pandas natürlich erkannt werden. Nirgends erwähnt er, dass er das Format der Quelldaten nicht ändern kann.
Gaurav

1

Wenn Ihnen die Leistung wichtig ist, stellen Sie sicher, dass Sie Zeit haben:

import sys
import timeit
import pandas as pd

print('Python %s on %s' % (sys.version, sys.platform))
print('Pandas version %s' % pd.__version__)

repeat = 3
numbers = 100

def time(statement, _setup=None):
    print (min(
        timeit.Timer(statement, setup=_setup or setup).repeat(
            repeat, numbers)))

print("Format %m/%d/%y")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,07/29/15
x2,07/29/15
x3,07/29/15
x4,07/30/15
x5,07/29/15
x6,07/29/15
x7,07/29/15
y7,08/05/15
x8,08/05/15
z3,08/05/15
''' * 100)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%m/%d/%y")); data.seek(0)')

print("Format %Y-%m-%d %H:%M:%S")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,2016-10-15 00:00:43
x2,2016-10-15 00:00:56
x3,2016-10-15 00:00:56
x4,2016-10-15 00:00:12
x5,2016-10-15 00:00:34
x6,2016-10-15 00:00:55
x7,2016-10-15 00:00:06
y7,2016-10-15 00:00:01
x8,2016-10-15 00:00:00
z3,2016-10-15 00:00:02
''' * 1000)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")); data.seek(0)')

Drucke:

Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28) 
[Clang 6.0 (clang-600.0.57)] on darwin
Pandas version 0.23.4
Format %m/%d/%y
0.19123052499999993
8.20691274
8.143124389
1.2384357139999977
Format %Y-%m-%d %H:%M:%S
0.5238807110000039
0.9202787830000005
0.9832778819999959
12.002349824999996

Bei einem iso8601-formatierten Datum ( %Y-%m-%d %H:%M:%Sanscheinend ein iso8601-formatiertes Datum, ich denke, das T kann gelöscht und durch ein Leerzeichen ersetzt werden) sollten Sie also nicht angeben infer_datetime_format(was bei allgemeineren offenbar auch keinen Unterschied macht) und Ihr eigenes übergeben Parser in nur lähmt Leistung. Auf der anderen Seite date_parsermacht es einen Unterschied mit nicht so Standard-Tagesformaten. Stellen Sie sicher, dass Sie wie gewohnt Zeit haben, bevor Sie optimieren.


1

Während des Ladens enthalten CSV-Datei Datumsspalte. Wir haben zwei Ansätze, um Pandas zu machen, um Datumsspalte zu erkennen, dh

  1. Pandas erkennen das Format explizit an arg date_parser=mydateparser

  2. Pandas erkennen das Format implizit an agr infer_datetime_format=True

Einige der Datumsspalten-Daten

01/01/18

01/02/18

Hier kennen wir die ersten beiden Dinge nicht. Es kann Monat oder Tag sein. In diesem Fall müssen wir also Methode 1 verwenden: - Explizites Übergeben des Formats

    mydateparser = lambda x: pd.datetime.strptime(x, "%m/%d/%y")
    df = pd.read_csv(file_name, parse_dates=['date_col_name'],
date_parser=mydateparser)

Methode 2: - Das Format implizit oder automatisch erkennen

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.