Могут ли панды автоматически распознавать даты?

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). Есть ли способ «выучить» панд к признанным датам?

Римский
источник
Пожалуйста, всегда указывайте версию для панд, для такого рода зависящего от версии вопроса. В июле 2013 года , это был бы v0.11
SMCI
И dtypes фиксированы для каждого столбца, вам не нужно перебирать df.iterrows()и просматривать их для каждой отдельной строки, просто сделайте df.info()один раз.
SMCI

Ответы:

327

Вы должны добавить 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)

Таким образом, вы можете даже объединить несколько столбцов в один столбец datetime, при этом столбцы «date» и «time» объединяются в один столбец «datetime»:

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
Я получил эту ошибку, потому что в моем фрейме данных были Nan.
Жан Поль
Вы можете добавить элемент, который также NaTs непарсируемого материала или NaN или / Ns. потому что кажется, что этот парсер полностью пропускает всю колонку, если что-то подобное присутствует
Амир
Есть опция infer_datetime_format: «Панды попытаются определить формат строк даты и времени в столбцах». Это можно использовать вместо date_parser.
Winand
1
Обратите внимание, что если ваши даты в ISO 8601формате, вы не должны передавать infer_datetime_formatили функцию синтаксического анализатора - это намного медленнее, чем позволить пандам обрабатывать это (особенно последнее). Формат даты в этом ответе также попадает в эту категорию
Mr_and_Mrs_D
20

Возможно, интерфейс pandas изменился после ответа @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

Метод 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.
Joop
источник
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
Евгений Ярмаш
источник
он конвертирует и другие столбцы на сегодняшний день, которые относятся к типу объектов
ратнеш
10

При объединении двух столбцов в один столбец datetime принятый ответ генерирует ошибку (pandas версия 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» для меня. Столбец даты - д / м / г, а столбец времени - Ч: М: 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]

Gaurav
источник
Я думаю, вы неправильно поняли вопрос. Пользователю любопытно, может ли опция быть включена для его формата строки.
Арья Маккарти
@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имеет значение не столь стандартные дневные форматы. Будьте уверены, что время, прежде чем оптимизировать, как обычно.

Mr_and_Mrs_D
источник
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)
Камран Каусар
источник