Чи можуть панди автоматично розпізнавати дати?


151

Сьогодні я був позитивно здивований тим фактом, що під час читання даних із файлу даних (наприклад) панди здатні розпізнавати типи значень:

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

Наприклад, це можна перевірити таким чином:

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

Зокрема цілі числа, поплавці та рядки були розпізнані правильно. Тим НЕ менше, у мене є стовпець , який має дати в наступному форматі: 2013-6-4. Ці дати були розпізнані як рядки (а не як об'єкти дати python). Чи є спосіб "дізнатися" панди до визнаних дат?


Будь-ласка, завжди вказуйте версію pandas для цього питання, залежного від версії. У липні 2013 року це було б v0.11
smci

І типи фіксуються для кожного стовпця, вам не потрібно перебирати df.iterrows()і переглядати їх для кожного ряду, просто зробіть df.info()один раз.
smci

Відповіді:


326

Вам слід додати parse_dates=True, або, parse_dates=['column name']читаючи, що зазвичай достатньо, щоб магічно розібрати його. Але завжди є дивні формати, які потрібно визначити вручну. У такому випадку ви також можете додати функцію аналізатора дати, що є найбільш гнучким можливим способом.

Припустимо, у вас є стовпець "datetime" із рядком, а потім:

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

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

Таким чином ви навіть можете об'єднати декілька стовпців в один стовпець дати, цей об'єднує стовпець "дата" та "час" в один стовпець "дата":

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)

Ви можете знайти директиви (тобто букви, які будуть використовуватися для різних форматів) для strptimeта strftime на цій сторінці .


8
Не працювало для мене, я отримав таку помилку:TypeError: strptime() argument 1 must be str, not float
Жан Пол

6
Я отримав цю помилку, оскільки в моєму кадрі даних було нан.
Жан Пол

чи можете ви додати елемент, який також NaTs нерозбірливий матеріал, або NaN або / Ns. тому що, здається, цей аналізатор повністю пропускає всю колонку, якщо щось подібне є
Амір

Існує варіант infer_datetime_format: "панди намагатимуться виводити формат рядків часу в стовпці". Це можна використовувати замість date_parser.
Вінанд

1
Зауважте, що якщо ваші дати у ISO 8601форматі, ви не повинні проходити infer_datetime_formatабо аналізувати функцію - це набагато повільніше, ніж дозволяти пандам обробляти це (особливо останній). Формат дати у цій відповіді також підпадає під цю категорію
Mr_and_Mrs_D

20

Можливо, інтерфейс панди змінився з моменту відповіді @Rutger, але у версії, яку я використовую (0.15.2), date_parserфункція отримує список дат замість одного значення. У цьому випадку його код слід оновити так:

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

метод pandas read_csv чудово підходить для розбору дат. Повна документація на веб-сайті http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

ви навіть можете мати різні частини дати в різних стовпцях і передавати параметр:

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

Зондування дат за замовчуванням працює чудово, але, схоже, воно є упередженим щодо форматів дати північноамериканських країн. Якщо ви живете в іншому місці, час від часу ви можете бути спіймані результатами. Наскільки я пам'ятаю, 1/6/2000 означає 6 січня в США на відміну від 1 червня, де я живу. Досить розумно розмахувати ними, якщо використовуються такі дати, як 23/6/2000. Напевно, безпечніше залишатися з варіантами дати у РРРРММДД. Вибачте перед розробниками панд, ось, але останнім часом я не перевіряв це місцевими датами.

ви можете використовувати параметр date_parser для передачі функції для перетворення формату.

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
Ви можете вказати dayfirstяк True для європейських / міжнародних дат. pandas.pydata.org/pandas-docs/stable/generated/…
Буде Гордон

10

Ви можете використовувати, pandas.to_datetime()як рекомендовано в документації, для pandas.read_csv():

Якщо стовпець або індекс містить непарну дату, весь стовпець або індекс буде повернуто без змін у вигляді об'єктних даних. Для нестандартного розбору дати використовуйте pd.to_datetimeпісля pd.read_csv.

Демонстрація:

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

він перетворює й інші стовпці на сьогоднішній день, які мають тип об’єкта
ratnesh

10

Під час об'єднання двох стовпців в один стовпчик дати, прийнята відповідь створює помилку (панди версії 0.20.3), оскільки стовпці надсилаються до функції date_parser окремо.

Наступні роботи:

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
Я використовую панди 0,22 і погоджуюся, що прийнята відповідь більше не працює.
Дай

Це створює "TypeError: може об'єднувати лише str (не" float ") в str" для мене. Стовпець дати - д / м / рік, а стовпець часу - H: M: 00
IceQueeny

8

Так - відповідно до pandas.read_csv документації :

Примітка: для дат, які мають формат iso8601, існує швидкий шлях .

Отже, якщо у вашому csv є стовпець з назвою, datetimeа дати виглядають, як, 2013-01-01T01:01наприклад, запустивши це, панди (я на v0.19.2) підбирають дату та час автоматично:

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

Зауважте, що вам потрібно явно пройти parse_dates, без цього не виходить.

Перевірте:

df.dtypes

Ви повинні побачити тип даних стовпця datetime64[ns]


Я думаю, ви неправильно зрозуміли питання. Користувача цікавить, чи може бути включена опція для його формату рядка.
Arya McCarthy

@AryaMcCarthy гмм, він в основному хоче, щоб дата була розпізнана правильно, тому я згадую, як він може перетворити вихідні дані так, щоб їх природним чином розпізнали панди. Ніде він не згадує, що не може змінити формат вихідних даних.
Гаурав

1

Якщо продуктивність важлива для вас, переконайтесь, що ви:

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

відбитки:

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

Таким чином , з ISO8601-відформатованої датою ( по- %Y-%m-%d %H:%M:%Sвидимому , ISO8601 форматом дата, я припускаю , що T можна відкинути і замінити пробіл) , ви повинні НЕ вказати infer_datetime_format(що робить різниці з більш загальними або очевидно) і передаючи свій власний аналізатор просто калічить виконання. З іншого боку, все-таки date_parserмає значення не надто стандартні формати для дня. Будьте впевнені, час, перш ніж оптимізувати, як зазвичай.


1

Під час завантаження CSV-файлу містяться стовпці дати. У нас є два підходи, щоб зробити панди для розпізнавання стовпця дати, тобто

  1. Панди явно розпізнають формат за допомогою аргументу date_parser=mydateparser

  2. Панди неявно розпізнають формат по agr infer_datetime_format=True

Деякі дані стовпців дати

01.01.18

01.02.18

Тут ми не знаємо перших двох речей: це може бути місяць чи день. Тому в цьому випадку ми повинні використовувати метод 1: - Явне передавання формату

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

Спосіб 2: - Неявне або автоматичне розпізнавання формату

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.