Czy pandy mogą automatycznie rozpoznawać daty?

151

Dziś pozytywnie zaskoczył mnie fakt, że pandy odczytując dane z pliku danych (np.) Potrafią rozpoznać typy wartości:

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

Przykładowo można to sprawdzić w ten sposób:

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

W szczególności liczby całkowite, zmiennoprzecinkowe i łańcuchy zostały poprawnie rozpoznane. Jednak mam kolumnę, która ma dat w następującym formacie: 2013-6-4. Daty te były rozpoznawane jako ciągi znaków (a nie jako obiekty dat w języku Python). Czy istnieje sposób, aby „nauczyć się” pandy do uznanych dat?

rzymski
źródło
Proszę zawsze podawać wersję pandy, w przypadku tego rodzaju pytań zależnych od wersji. W lipcu 2013 byłaby to wersja 0.11
smci
A dtypy są ustalone dla każdej kolumny, nie musisz iterować df.iterrows()i przeglądać ich dla każdego wiersza, po prostu zrób df.info()raz.
smci

Odpowiedzi:

326

Powinieneś dodać parse_dates=True, lub parse_dates=['column name']podczas czytania, zwykle wystarczy, aby magicznie go przeanalizować. Ale zawsze są dziwne formaty, które należy zdefiniować ręcznie. W takim przypadku możesz również dodać funkcję parsera daty, co jest najbardziej elastycznym sposobem.

Załóżmy, że masz kolumnę „datetime” ze swoim ciągiem, a następnie:

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

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

W ten sposób możesz nawet połączyć wiele kolumn w jedną kolumnę z datą i godziną, co scala kolumny „data” i „godzina” w jedną kolumnę „data i godzina”:

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)

Można znaleźć dyrektyw (tj litery mają być stosowane do różnych formatów) dla strptimei strftime na tej stronie .

Rutger Kassies
źródło
8
U mnie nie działa, pojawił się następujący błąd:TypeError: strptime() argument 1 must be str, not float
Jean Paul
6
Otrzymałem ten błąd, ponieważ w mojej ramce danych były nan.
Jean Paul
czy możesz dodać element, który również NaTs jest materiałem nie podlegającym analizie lub NaN lub / Ns. bo wygląda na to, że ten parser całkowicie pomija całą kolumnę, jeśli coś takiego jest obecne
Amir
Jest opcja infer_datetime_format: „pandy będą próbowały wywnioskować format ciągów daty i godziny w kolumnach”. Można tego użyć zamiast date_parser.
Winand
1
Zauważ, że jeśli twoje daty są w ISO 8601formacie, nie powinieneś przekazywać infer_datetime_formatfunkcji parsera - jest to znacznie wolniejsze niż pozwolenie pandom na obsługę (zwłaszcza tej drugiej). Format daty w tej odpowiedzi również należy do tej kategorii
Mr_and_Mrs_D
20

Być może interfejs pandy zmienił się od czasu odpowiedzi @Rutger, ale w wersji, której używam (0.15.2), date_parserfunkcja otrzymuje listę dat zamiast pojedynczej wartości. W takim przypadku jego kod należy zaktualizować w następujący sposób:

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)
Sean
źródło
11

Metoda pandy read_csv świetnie nadaje się do analizowania dat. Pełna dokumentacja pod adresem http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

możesz nawet umieścić różne części daty w różnych kolumnach i przekazać parametr:

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

Domyślne wykrywanie dat działa świetnie, ale wydaje się być tendencyjne do północnoamerykańskich formatów dat. Jeśli mieszkasz gdzie indziej, czasami możesz dać się złapać na wynikach. O ile dobrze pamiętam, 1/6/2000 oznacza 6 stycznia w USA w przeciwieństwie do 1 czerwca, gdzie mieszkam. Jest wystarczająco sprytne, aby je obracać, jeśli używane są daty takie jak 23.06.2000. Prawdopodobnie bezpieczniej jest pozostać przy zmianach daty RRRRMMDD. Przepraszamy programistów pand, ale ostatnio nie testowałem tego z lokalnymi datami.

możesz użyć parametru date_parser, aby przekazać funkcję konwertującą twój format.

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.
Joop
źródło
2
Możesz określić dayfirstjako Prawda dla dat europejskich / międzynarodowych. pandas.pydata.org/pandas-docs/stable/generated/…
Will Gordon
10

Możesz użyć pandas.to_datetime()zgodnie z zaleceniami w dokumentacji dla pandas.read_csv():

Jeśli kolumna lub indeks zawiera nierozdzielną datę, cała kolumna lub indeks zostanie zwrócona niezmieniona jako typ danych obiektu. W przypadku niestandardowego analizowania daty i godziny użyj pd.to_datetimepo pd.read_csv.

Próbny:

>>> 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
Eugene Yarmash
źródło
konwertuje również inne kolumny do tej pory, które są typu obiektowego
ratnesh
10

Przy scalaniu dwóch kolumn w jedną kolumnę datetime, zaakceptowana odpowiedź generuje błąd (pandy w wersji 0.20.3), ponieważ kolumny są wysyłane osobno do funkcji date_parser.

Następujące prace:

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)
Jestem morsem
źródło
1
Używam pandy 0.22 i zgadzam się, że zaakceptowana odpowiedź już nie działa.
Dai
Tworzy to „TypeError: może łączyć tylko str (nie„ float ”) do str”. Kolumna daty to d / m / r, a kolumna czasu to H: M: 00
IceQueeny
8

Tak - zgodnie z pandas.read_csv dokumentacją :

Uwaga: istnieje skrócona ścieżka dla dat w formacie iso8601 .

Więc jeśli twój csv ma ​​kolumnę o nazwie, datetimea daty wyglądają jak 2013-01-01T01:01na przykład, uruchomienie tego spowoduje, że pandy (jestem na v0.19.2) automatycznie pobiorą datę i godzinę:

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

Zauważ, że musisz wyraźnie przejść parse_dates, to nie działa bez.

Zweryfikuj za pomocą:

df.dtypes

Powinieneś zobaczyć typ danych kolumny datetime64[ns]

Gaurav
źródło
Myślę, że źle zrozumiałeś pytanie. Użytkownik jest ciekawy, czy można włączyć tę opcję dla jego formatu łańcucha.
Arya McCarthy,
@AryaMcCarthy umm, po prostu chce, aby data była poprawnie rozpoznawana, więc wspominam, jak może przekształcić dane źródłowe, aby były naturalnie rozpoznawane przez pandy. Nigdzie nie wspomina, że ​​nie może zmienić formatu danych źródłowych.
Gaurav
1

Jeśli wydajność ma dla Ciebie znaczenie, upewnij się, że masz czas:

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

wydruki:

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

Więc z ISO8601 sformatowany daty ( %Y-%m-%d %H:%M:%Sto widocznie data ISO8601 sformatowany, myślę T mogą zostać usunięte i zastąpione spacją) należy nie podać infer_datetime_format(co nie robi różnicy z bardziej pospolitych albo widocznie) i przekazywanie własnych parser tylko paraliżuje wydajność. Z drugiej strony date_parserrobi różnicę w przypadku niezbyt standardowych formatów dni. Pamiętaj, aby jak zwykle czas przed optymalizacją.

Mr_and_Mrs_D
źródło
1

Podczas wczytywania pliku csv zawiera kolumnę z datą. Mamy dwa sposoby, aby pandy rozpoznawały kolumnę z datą, tj

  1. Pandy jawnie rozpoznają format po arg date_parser=mydateparser

  2. Pandy niejawnie rozpoznają format przez agr infer_datetime_format=True

Niektóre dane z kolumny daty

01/01/18

01/02/18

Tutaj nie znamy pierwszych dwóch rzeczy. Może to być miesiąc lub dzień. Więc w tym przypadku musimy użyć metody 1: - Jawne przekazanie formatu

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

Metoda 2: - Niejawne lub automatyczne rozpoznawanie formatu

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
kamran kausar
źródło