Инструменты Ввода-Вывода (Текст, CSV, HDF5, ...)
API pandas для ввода-вывода — это набор функций верхнего уровня reader доступных как pd.read_csv(), которые, как правило, возвращают объект pandas.
- read_csv
- read_excel
- read_hdf
- read_sql
- read_json
- read_msgpack (экспериментальная)
- read_html
- read_gbq (экспериментальная)
- read_stata
- read_sas
- read_clipboard
- read_pickle
Соответствующие writer функции — это методы объектов, к которым обращаются как df.to_csv().
- to_csv
- to_excel
- to_hdf
- to_sql
- to_json
- to_msgpack (экспериментальная)
- to_html
- to_gbq (экспериментальная)
- to_stata
- to_clipboard
- to_pickle
Здесь представлено сравнение производительности некоторых из этих методов ввода-вывода.
Примечание
Для примеров, использующих класс StringIO, убедитесь, что вы импортировали его в соответствии с вашей версией Python, т.е. from StringIO import StringIO для Python 2 и from io import StringIO для Python 3.
Файлы CSV и текстовые файлы
Двумя основными функциями для чтения текстовых файлов (также известных как плоские файлы) являются read_csv() и read_table(). Они оба используют один и тот же код разбора для интеллектуального преобразования табличных данных в объект DataFrame. См. справочник для некоторых расширенных стратегий.
Параметры разбора
read_csv() и read_table() принимают следующие аргументы:
Основные
- filepath_or_buffer : различные
- Путь к файлу (строка
str,pathlib.Pathилиpy._path.local.LocalPath), URL (включая http, ftp и расположения S3) или любой объект с методомread()(таким как открытый файл илиStringIO). - sep : строка, по умолчанию
- Разделитель. Если sep —
None, попытается автоматически определить его. Разделители длиной более 1 символа и отличные от'\s+'будут интерпретироваться как регулярные выражения, заставят использовать анализатор Python и проигнорируют кавычки в данных. Пример регулярного выражения:'\\r\\t'. - delimiter : строка, по умолчанию
- Альтернативное имя аргумента для sep.
- delim_whitespace : логическое значение, по умолчанию False
-
Указывает, использовать ли пробелы (например,
' 'или'\t') в качестве разделителя. Эквивалентно установкеsep='\s+'. Если этот параметр установлен в True, параметрdelimiterне должен передаваться.Добавлена в версии 0.18.1: поддержка парсера Python.
',' для read_csv(), \t для read_table()NoneРасположение и имена столбцов и индексов
- header : целое число или список целых чисел, по умолчанию
- Номер(а) строки(ок) для использования в качестве имен столбцов и начала данных. По умолчанию ведет себя так, как если бы
header=0если не переданnames, иначе как если быheader=None. Явно передайтеheader=0для возможности замены существующих имен. Заголовок может быть списком целых чисел, которые указывают местоположения строк для многоуровневого индекса столбцов, например,[0,1,3]. Промежуточные строки, которые не указаны, будут пропущены (например, 2 в этом примере пропущена). Обратите внимание, что этот параметр игнорирует прокомментированные строки и пустые строки, еслиskip_blank_lines=True, поэтому header=0 обозначает первую строку данных, а не первую строку файла. - names : массив-подобный объект, по умолчанию
- Список имен столбцов для использования. Если файл не содержит строки заголовка, необходимо явно передать
header=None. Дубликаты в этом списке не допускаются, еслиmangle_dupe_cols=True, что является значением по умолчанию. - index_col : целое число или последовательность или
- Столбец для использования в качестве меток строк DataFrame. Если задана последовательность, используется многоуровневый индекс. Если у вас есть повреждённый файл с разделителями в конце каждой строки, рассмотрите возможность
index_col=Falseчтобы заставить pandas не использовать первый столбец в качестве индекса (имен строк). - usecols : массив-подобный объект, по умолчанию
- Возвращает подмножество столбцов. Все элементы этого массива должны быть либо позиционными (т. е. целочисленными индексами столбцов документа), либо строками, соответствующими именам столбцов, предоставленных пользователем в
namesили полученных из строки(ок) заголовка документа. Например, допустимым параметромusecolsбудет [0, 1, 2] или [‘foo’, ‘bar’, ‘baz’]. Использование этого параметра приводит к значительно более быстрому парсингу и меньшей потребности в памяти. - as_recarray : логическое значение, по умолчанию
-
УСТАРЕЛО: этот аргумент будет удален в будущих версиях. Пожалуйста, используйте
pd.read_csv(...).to_records()вместо этого.Возвращает массив NumPy recarray вместо DataFrame после парсинга данных. Если установлено
True, этот параметр имеет приоритет над параметромsqueeze. Кроме того, поскольку индексы строк недоступны в таком формате, параметрindex_colбудет проигнорирован. - squeeze : логическое значение, по умолчанию
- Если прочитанные данные содержат только один столбец, возвращает Series.
- prefix : строка, по умолчанию
- Префикс, добавляемый к номерам столбцов, когда нет заголовка, например, «X» для X0, X1, ...
- mangle_dupe_cols : логическое значение, по умолчанию
- Дублирующие столбцы будут указаны как «X.0»…«X.N», а не «X»…«X». Передача False приведет к перезаписи данных, если в столбцах есть дублирующие имена.
'infer'NoneFalse, по умолчанию NoneNoneFalseFalseNoneTrueОбщие настройки парсинга
- dtype : Имя типа или словарь столбец -> тип, по умолчанию
- Тип данных для данных или столбцов. Например,
{'a': np.float64, 'b': np.int32}(не поддерживается сengine='python'). Используйтеstrилиobject, чтобы сохранить и не интерпретировать dtype. - engine : {
- Двигатель парсера для использования. Двигатель C быстрее, а двигатель Python в настоящее время более функционален.
- converters : словарь, по умолчанию
- Словарь функций для преобразования значений в определённых столбцах. Ключи могут быть целыми числами или метками столбцов.
- true_values : список, по умолчанию
- Значения, которые следует рассматривать как
True. - false_values : список, по умолчанию
- Значения, которые следует рассматривать как
False. - skipinitialspace : булево, по умолчанию
- Пропустить пробелы после разделителя.
- skiprows : подобный списку или целое число, по умолчанию
- Номера строк для пропуска (индексация с 0) или количество строк для пропуска (целое число) в начале файла.
- skipfooter : целое число, по умолчанию
- Количество строк внизу файла для пропуска (не поддерживается с engine='c').
- skip_footer : целое число, по умолчанию
- УСТАРЕВШЕЕ: используйте вместо этого параметр
skipfooter, так как они идентичны - nrows : целое число, по умолчанию
- Количество строк файла для чтения. Полезно для чтения фрагментов больших файлов.
- low_memory : булево, по умолчанию
- Внутренне обрабатывает файл частями, что приводит к меньшему использованию памяти во время анализа, но, возможно, смешанному выводу типа. Чтобы гарантировать отсутствие смешанных типов, либо задайте
False, либо укажите тип с параметромdtype. Обратите внимание, что весь файл читается в один DataFrame независимо, используйте параметрchunksizeилиiterator, чтобы вернуть данные частями. (Действительно только с парсером C) - buffer_lines : целое число, по умолчанию None
- УСТАРЕВШЕЕ: этот аргумент будет удален в будущей версии, потому что его значение не учитывается парсером
- compact_ints : булево, по умолчанию False
-
УСТАРЕВШЕЕ: этот аргумент будет удален в будущей версии
Если
compact_intsравноTrue, то для любого столбца целочисленного типа парсер попытается преобразовать его в наименьший возможный целочисленныйdtypeтип, либо со знаком, либо без знака, в зависимости от спецификации из параметраuse_unsigned. - use_unsigned : булево, по умолчанию False
-
УСТАРЕВШЕЕ: этот аргумент будет удален в будущей версии
Если целочисленные столбцы сжимаются (т. е.
compact_ints=True), укажите, должен ли столбец быть сжат до наименьшего целочисленного типа со знаком или без знака. - memory_map : булево, по умолчанию False
- Если для
filepath_or_bufferуказан путь к файлу, отобразить файл непосредственно в памяти и получить доступ к данным напрямую из него. Использование этого параметра может повысить производительность, потому что теперь нет накладных расходов на ввод-вывод.
None'c', 'python'}NoneNoneNoneFalseNone00NoneTrueОбработка NA и пропущенных данных
- na_values : скаляр, строка, список-подобный объект или словарь, по умолчанию
- Дополнительные строки для распознавания NA/NaN. Если передан словарь, то для каждого столбца. По умолчанию следующие значения интерпретируются как NaN:
'-1.#IND', '1.#QNAN', '1.#IND', '-1.#QNAN', '#N/A N/A', '#N/A', 'N/A', 'NA', '#NA', 'NULL', 'NaN', '-NaN', 'nan', '-nan', ''. - keep_default_na : булево, по умолчанию
- Если заданы na_values и keep_default_na равно
False, значения NaN по умолчанию перезаписываются, иначе они добавляются. - na_filter : булево, по умолчанию
- Обнаружение маркеров пропущенных значений (пустые строки и значение na_values). При данных без NA, передача
na_filter=Falseможет улучшить производительность чтения большого файла. - verbose : булево, по умолчанию
- Указать количество значений NA, помещённых в нечисловые столбцы.
- skip_blank_lines : булево, по умолчанию
- Если
True, пропустить пустые строки, а не интерпретировать их как значения NaN.
NoneTrueTrueFalseTrueОбработка дат и времени
- parse_dates : булево или список целых чисел или имён или список списков или словарь, по умолчанию
-
- Если
True-> попытка парсинга индекса. - Если
[1, 2, 3]-> попытка парсинга столбцов 1, 2, 3 как отдельных столбцов дат. - Если
[[1, 3]]-> объединение столбцов 1 и 3 и парсинг как одного столбца дат. - Если
{'foo' : [1, 3]}-> парсинг столбцов 1, 3 как дат и присвоение результата 'foo'. Быстрый путь существует для дат в формате iso8601.
- Если
- infer_datetime_format : булево, по умолчанию
- Если
Trueи parse_dates включён для столбца, попытаться определить формат даты и времени для ускорения обработки. - keep_date_col : булево, по умолчанию
- Если
Trueи parse_dates определяет объединение нескольких столбцов, то сохранить исходные столбцы. - date_parser : функция, по умолчанию
- Функция для преобразования последовательности столбцов строк в массив экземпляров datetime. По умолчанию используется
dateutil.parser.parserдля преобразования. Pandas попытается вызвать date_parser тремя различными способами, переходя к следующему, если произойдёт исключение: 1) Передать один или несколько массивов (как определено parse_dates) в качестве аргументов; 2) конкатенировать (по строкам) строковые значения из столбцов, определённых parse_dates, в один массив и передать его; и 3) вызвать date_parser один раз для каждой строки, используя одну или несколько строк (соответствующих столбцам, определённым parse_dates) в качестве аргументов. - dayfirst : булево, по умолчанию
- Даты в формате ДД/ММ, международный и европейский формат.
False. FalseFalseNoneFalseИтерация
- iterator : булево, по умолчанию
- Возвратить объект для итерации или получения фрагментов с
get_chunk(). - chunksize : целое число, по умолчанию
- Возвращает объект для итерации. См. Итерация и фрагментация ниже.
FalseNoneЦитаты, сжатие и формат файла
- compression : {
-
Для декомпрессии данных на диске в режиме реального времени. Если ‘infer’, то использовать gzip, bz2, zip или xz, если filepath_or_buffer является строкой, заканчивающейся на ‘.gz’, ‘.bz2’, ‘.zip’ или ‘.xz’ соответственно, и без декомпрессии в противном случае. Если используется ‘zip’, архив ZIP должен содержать только один файл данных для чтения. Установите в
Noneдля отключения декомпрессии.Введено в версии 0.18.1: поддержка сжатия ‘zip’ и ‘xz’.
- thousands : str, default
- Разделитель тысяч.
- decimal : str, default
- Символ, распознаваемый как десятичная точка. Например, используйте
','для европейских данных. - float_precision : string, default None
- Указывает, какой конвертер должен использовать C движок для значений с плавающей точкой. Доступные варианты:
Noneдля обычного конвертера,highдля конвертера высокой точности иround_tripдля конвертера обратного преобразования. - lineterminator : str (длина 1), default
- Символ для разделения файла на строки. Действителен только с C парсером.
- quotechar : str (длина 1)
- Символ, используемый для обозначения начала и конца цитируемого элемента. Цитируемые элементы могут включать разделитель, и он будет проигнорирован.
- quoting : int or
- Управление поведением цитирования полей по константам
csv.QUOTE_*. Используйте один изQUOTE_MINIMAL(0),QUOTE_ALL(1),QUOTE_NONNUMERIC(2) илиQUOTE_NONE(3). - doublequote : boolean, default
- Когда указан
quotechar, иquotingнеQUOTE_NONE, указывает, следует ли интерпретировать два последовательных элементаquotecharвнутри поля как один элементquotechar. - escapechar : str (длина 1), default
- Строка длиной в один символ, используемая для экранирования разделителя, когда цитирование
QUOTE_NONE. - comment : str, default
- Указывает, что оставшаяся часть строки не должна анализироваться. Если он находится в начале строки, строка будет проигнорирована полностью. Этот параметр должен быть одиночным символом. Как и пустые строки (пока
skip_blank_lines=True), полностью комментированные строки игнорируются параметромheader, но неskiprows. Например, еслиcomment='#', парсинг ‘#empty\na,b,c\n1,2,3’ сheader=0приведет к тому, что ‘a,b,c’ будет обработана как заголовок. - encoding : str, default
- Кодировка UTF для чтения/записи (например,
'utf-8'). Список стандартных кодировок Python. - dialect : str or
- Если
Noneпо умолчанию использует диалект Excel. Игнорируется, если sep длиннее 1 символа. См.csv.Dialectдля получения дополнительной информации. - tupleize_cols : boolean, default
- Оставить список кортежей в столбцах без изменений (по умолчанию преобразовать в MultiIndex для столбцов).
'infer', 'gzip', 'bz2', 'zip', 'xz', None}, default 'infer'None'.'Nonecsv.QUOTE_* instance, default 0TrueNoneNoneNonecsv.Dialect instance, default NoneFalseОбработка ошибок
- error_bad_lines : boolean, default
- Строки с слишком многими полями (например, строка CSV со слишком многими запятыми) по умолчанию вызовут исключение, и DataFrame не будет возвращён. Если
False, то эти «плохие строки» будут удалены из возвращаемого DataFrame (действительно только с C парсером). См. плохие строки ниже. - warn_bad_lines : boolean, default
- Если error_bad_lines
False, и warn_bad_linesTrue, для каждой «плохой строки» будет выведено предупреждение (действительно только с C парсером).
TrueTrueРассмотрим типичный CSV-файл, содержащий в данном случае некоторые временные ряды:
In [1]: print(open('foo.csv').read())
date,A,B,C
20090101,a,1,2
20090102,b,3,4
20090103,c,4,5
По умолчанию read_csv создаёт DataFrame с простыми пронумерованными строками:
In [2]: pd.read_csv('foo.csv')
Out[2]:
date A B C
0 20090101 a 1 2
1 20090102 b 3 4
2 20090103 c 4 5
В случае индексированных данных вы можете передать номер или имя столбца, который вы хотите использовать в качестве индекса:
In [3]: pd.read_csv('foo.csv', index_col=0)
Out[3]:
A B C
date
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
In [4]: pd.read_csv('foo.csv', index_col='date')
Out[4]:
A B C
date
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
Вы также можете использовать список столбцов для создания иерархического индекса:
In [5]: pd.read_csv('foo.csv', index_col=[0, 'A'])
Out[5]:
B C
date A
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
Ключевое слово dialect обеспечивает большую гибкость в указании формата файла. По умолчанию используется диалект Excel, но вы можете указать имя диалекта или экземпляр csv.Dialect.
Предположим, у вас есть данные с незакрытыми кавычками:
In [6]: print(data) label1,label2,label3 index1,"a,c,e index2,b,d,f
По умолчанию read_csv использует диалект Excel и обрабатывает двойную кавычку как символ кавычки, что приводит к сбою при обнаружении новой строки перед обнаружением закрывающей двойной кавычки.
Мы можем обойти это с помощью dialect
In [7]: dia = csv.excel()
In [8]: dia.quoting = csv.QUOTE_NONE
In [9]: pd.read_csv(StringIO(data), dialect=dia)
Out[9]:
label1 label2 label3
index1 "a c e
index2 b d f
Все параметры диалекта могут быть указаны по отдельности в качестве ключевых аргументов:
In [10]: data = 'a,b,c~1,2,3~4,5,6' In [11]: pd.read_csv(StringIO(data), lineterminator='~') Out[11]: a b c 0 1 2 3 1 4 5 6
Еще один распространенный параметр диалекта — skipinitialspace, чтобы пропустить любые пробелы после разделителя:
In [12]: data = 'a, b, c\n1, 2, 3\n4, 5, 6' In [13]: print(data) a, b, c 1, 2, 3 4, 5, 6 In [14]: pd.read_csv(StringIO(data), skipinitialspace=True) Out[14]: a b c 0 1 2 3 1 4 5 6
Парсеры делают все возможное, чтобы «делать правильные вещи» и не быть слишком хрупкими. Вывод типов — очень важная вещь. Поэтому, если столбец можно привести к целочисленному типу без изменения содержимого, он это сделает. Любые нечисленные столбцы будут представлены как тип «объект», как и все остальные объекты pandas.
Указание типов данных столбцов
Начиная с версии 0.10, вы можете указать тип данных для всего DataFrame или отдельных столбцов:
In [15]: data = 'a,b,c\n1,2,3\n4,5,6\n7,8,9'
In [16]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [17]: df = pd.read_csv(StringIO(data), dtype=object)
In [18]: df
Out[18]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9
In [19]: df['a'][0]
Out[19]: '1'
In [20]: df = pd.read_csv(StringIO(data), dtype={'b': object, 'c': np.float64})
In [21]: df.dtypes
Out[21]:
a int64
b object
c float64
dtype: object
К счастью, pandas предлагает более одного способа, чтобы гарантировать, что ваши столбцы содержат только один dtype. Если вы не знакомы с этими концепциями, вы можете ознакомиться здесь, чтобы узнать больше о типах данных, и здесь, чтобы узнать больше о object преобразовании в pandas.
Например, вы можете использовать аргумент converters функции read_csv():
In [22]: data = "col_1\n1\n2\n'A'\n4.22"
In [23]: df = pd.read_csv(StringIO(data), converters={'col_1':str})
In [24]: df
Out[24]:
col_1
0 1
1 2
2 'A'
3 4.22
In [25]: df['col_1'].apply(type).value_counts()
Out[25]:
<type 'str'> 4
Name: col_1, dtype: int64
Или вы можете использовать функцию to_numeric() для принудительного преобразования типов после чтения данных,
In [26]: df2 = pd.read_csv(StringIO(data)) In [27]: df2['col_1'] = pd.to_numeric(df2['col_1'], errors='coerce') In [28]: df2 Out[28]: col_1 0 1.00 1 2.00 2 NaN 3 4.22 In [29]: df2['col_1'].apply(type).value_counts() Out[29]: <type 'float'> 4 Name: col_1, dtype: int64
что приведет к преобразованию всех допустимых разборов в числа с плавающей точкой, а недопустимые разборы останутся как NaN.
В конечном счете, как вы будете обрабатывать чтение столбцов, содержащих типы данных смешанного типа, зависит от ваших конкретных потребностей. В случае выше, если вы хотите NaN выбросить аномалии данных, то to_numeric() является, вероятно, вашим лучшим вариантом. Однако, если вы хотите, чтобы все данные были приведены к нужному типу независимо от типа, то использование аргумента converters функции read_csv() определенно стоит попробовать.
Примечание
Опция dtype в настоящее время поддерживается только C движком. Указание dtype с engine отличным от ‘c’ приводит к исключению ValueError.
Примечание
В некоторых случаях чтение аномальных данных со столбцами, содержащими типы данных смешанного типа, приведёт к несогласованному набору данных. Если вы полагаетесь на pandas для вывода типов ваших столбцов, движок парсинга будет определять типы для разных фрагментов данных, а не для всего набора данных сразу. В результате вы можете получить столбец(ы) со смешанными типами данных. Например,
In [30]: df = pd.DataFrame({'col_1':range(500000) + ['a', 'b'] + range(500000)})
In [31]: df.to_csv('foo')
In [32]: mixed_df = pd.read_csv('foo')
In [33]: mixed_df['col_1'].apply(type).value_counts()
Out[33]:
<type 'int'> 737858
<type 'str'> 262144
Name: col_1, dtype: int64
In [34]: mixed_df['col_1'].dtype
Out[34]: dtype('O')
приведёт к mixed_df содержащему тип данных int для некоторых фрагментов столбца, и str для других из-за смешанных типов данных в считанных данных. Важно отметить, что общий столбец будет помечен с dtype object, используемый для столбцов со смешанными типами данных.
Указание типа Categorical
Введено в версии 0.19.0.
Столбцы Categorical могут быть прочитаны непосредственно, указав dtype='category'
In [35]: data = 'col1,col2,col3\na,b,1\na,b,2\nc,d,3' In [36]: pd.read_csv(StringIO(data)) Out[36]: col1 col2 col3 0 a b 1 1 a b 2 2 c d 3 In [37]: pd.read_csv(StringIO(data)).dtypes Out[37]: col1 object col2 object col3 int64 dtype: object In [38]: pd.read_csv(StringIO(data), dtype='category').dtypes Out[38]: col1 category col2 category col3 category dtype: object
Индивидуальные столбцы могут быть прочитаны как Categorical с помощью спецификации словаря
In [39]: pd.read_csv(StringIO(data), dtype={'col1': 'category'}).dtypes
Out[39]:
col1 category
col2 object
col3 int64
dtype: object
Примечание
Полученные категории всегда будут анализироваться как строки (тип данных объект). Если категории являются числовыми, их можно преобразовать с помощью функции to_numeric() или, при необходимости, другого преобразователя, например, to_datetime().
In [40]: df = pd.read_csv(StringIO(data), dtype='category') In [41]: df.dtypes Out[41]: col1 category col2 category col3 category dtype: object In [42]: df['col3'] Out[42]: 0 1 1 2 2 3 Name: col3, dtype: category Categories (3, object): [1, 2, 3] In [43]: df['col3'].cat.categories = pd.to_numeric(df['col3'].cat.categories) In [44]: df['col3'] Out[44]: 0 1 1 2 2 3 Name: col3, dtype: category Categories (3, int64): [1, 2, 3]
Именование и использование столбцов
Обработка имён столбцов
Файл может или не может иметь строку заголовка. pandas предполагает, что первая строка должна использоваться в качестве имён столбцов:
In [45]: data = 'a,b,c\n1,2,3\n4,5,6\n7,8,9' In [46]: print(data) a,b,c 1,2,3 4,5,6 7,8,9 In [47]: pd.read_csv(StringIO(data)) Out[47]: a b c 0 1 2 3 1 4 5 6 2 7 8 9
Указав аргумент names в сочетании с header, вы можете указать другие имена для использования и то, нужно ли удалять строку заголовка (если она есть):
In [48]: print(data) a,b,c 1,2,3 4,5,6 7,8,9 In [49]: pd.read_csv(StringIO(data), names=['foo', 'bar', 'baz'], header=0) Out[49]: foo bar baz 0 1 2 3 1 4 5 6 2 7 8 9 In [50]: pd.read_csv(StringIO(data), names=['foo', 'bar', 'baz'], header=None) Out[50]: foo bar baz 0 a b c 1 1 2 3 2 4 5 6 3 7 8 9
Если заголовок находится в строке, отличной от первой, передайте номер строки в header. Это пропустит предшествующие строки:
In [51]: data = 'skip this skip it\na,b,c\n1,2,3\n4,5,6\n7,8,9' In [52]: pd.read_csv(StringIO(data), header=1) Out[52]: a b c 0 1 2 3 1 4 5 6 2 7 8 9
Обработка дублирующихся имён
Если файл или заголовок содержат дублирующиеся имена, pandas по умолчанию дедуплицирует эти имена, чтобы предотвратить перезапись данных:
In [53]: data = 'a,b,a\n0,1,2\n3,4,5' In [54]: pd.read_csv(StringIO(data)) Out[54]: a b a.1 0 0 1 2 1 3 4 5
Больше нет дублирующихся данных, потому что mangle_dupe_cols=True по умолчанию, что изменяет серию дублирующихся столбцов ‘X’...’X’ на ‘X.0’...’X.N’. Если mangle_dupe_cols
=False, дублирующиеся данные могут возникнуть:
In [2]: data = 'a,b,a\n0,1,2\n3,4,5' In [3]: pd.read_csv(StringIO(data), mangle_dupe_cols=False) Out[3]: a b a 0 2 1 2 1 5 4 5
Чтобы предотвратить столкновение с этой проблемой дублирующихся данных, возникает исключение ValueError, если mangle_dupe_cols != True:
In [2]: data = 'a,b,a\n0,1,2\n3,4,5' In [3]: pd.read_csv(StringIO(data), mangle_dupe_cols=False) ... ValueError: Setting mangle_dupe_cols=False is not supported yet
Фильтрация столбцов (usecols)
Аргумент usecols позволяет вам выбрать любой подмножество столбцов в файле, используя имена столбцов или номера позиций:
In [55]: data = 'a,b,c,d\n1,2,3,foo\n4,5,6,bar\n7,8,9,baz' In [56]: pd.read_csv(StringIO(data)) Out[56]: a b c d 0 1 2 3 foo 1 4 5 6 bar 2 7 8 9 baz In [57]: pd.read_csv(StringIO(data), usecols=['b', 'd']) Out[57]: b d 0 2 foo 1 5 bar 2 8 baz In [58]: pd.read_csv(StringIO(data), usecols=[0, 2, 3]) Out[58]: a c d 0 1 3 foo 1 4 6 bar 2 7 9 baz
Комментарии и пустые строки
Игнорирование комментариев в строках и пустых строк
Если указан параметр comment, то полностью закомментированные строки будут проигнорированы. По умолчанию также игнорируются полностью пустые строки. Оба эти изменения являются изменениями API, введенными в версии 0.15.
In [59]: data = '\na,b,c\n \n# commented line\n1,2,3\n\n4,5,6' In [60]: print(data) a,b,c 1,2,3 4,5,6 # commented line In [61]: pd.read_csv(StringIO(data), comment='#') Out[61]: a b c 0 1 2 3 1 4 5 6
Если skip_blank_lines=False, то read_csv не будет игнорировать пустые строки:
In [62]: data = 'a,b,c\n\n1,2,3\n\n\n4,5,6'
In [63]: pd.read_csv(StringIO(data), skip_blank_lines=False)
Out[63]:
a b c
0 NaN NaN NaN
1 1.0 2.0 3.0
2 NaN NaN NaN
3 NaN NaN NaN
4 4.0 5.0 6.0
Предупреждение
Наличие пропущенных строк может создать неоднозначность с номерами строк; параметр header использует номера строк (игнорируя закомментированные/пустые строки), в то время как skiprows использует номера строк (включая закомментированные/пустые строки):
In [64]: data = '#comment\na,b,c\nA,B,C\n1,2,3' In [65]: pd.read_csv(StringIO(data), comment='#', header=1) Out[65]: A B C 0 1 2 3 In [66]: data = 'A,B,C\n#comment\na,b,c\n1,2,3' In [67]: pd.read_csv(StringIO(data), comment='#', skiprows=2) Out[67]: a b c 0 1 2 3
Если оба header и skiprows указаны, header будет относиться к концу skiprows. Например:
In [68]: data = '# empty\n# second empty line\n# third empty' \
In [68]: 'line\nX,Y,Z\n1,2,3\nA,B,C\n1,2.,4.\n5.,NaN,10.0'
In [69]: print(data)
# empty
# second empty line
# third emptyline
X,Y,Z
1,2,3
A,B,C
1,2.,4.
5.,NaN,10.0
In [70]: pd.read_csv(StringIO(data), comment='#', skiprows=4, header=1)
Out[70]:
A B C
0 1.0 2.0 4.0
1 5.0 NaN 10.0
Комментарии
Иногда в файл могут быть включены комментарии или метаданные:
In [71]: print(open('tmp.csv').read())
ID,level,category
Patient1,123000,x # really unpleasant
Patient2,23000,y # wouldn't take his medicine
Patient3,1234018,z # awesome
По умолчанию парсер включает комментарии в выходные данные:
In [72]: df = pd.read_csv('tmp.csv')
In [73]: df
Out[73]:
ID level category
0 Patient1 123000 x # really unpleasant
1 Patient2 23000 y # wouldn't take his medicine
2 Patient3 1234018 z # awesome
Мы можем подавить комментарии, используя ключевое слово comment:
In [74]: df = pd.read_csv('tmp.csv', comment='#')
In [75]: df
Out[75]:
ID level category
0 Patient1 123000 x
1 Patient2 23000 y
2 Patient3 1234018 z
Работа с данными Unicode
Аргумент encoding должен использоваться для данных с кодировкой Unicode, что приведет к декодированию байтовых строк в Unicode в результате:
In [76]: data = b'word,length\nTr\xc3\xa4umen,7\nGr\xc3\xbc\xc3\x9fe,5'.decode('utf8').encode('latin-1')
In [77]: df = pd.read_csv(BytesIO(data), encoding='latin-1')
In [78]: df
Out[78]:
word length
0 Träumen 7
1 Grüße 5
In [79]: df['word'][1]
Out[79]: u'Gr\xfc\xdfe'
Некоторые форматы, которые кодируют все символы в виде нескольких байт, как UTF-16, не будут правильно анализироваться без указания кодировки. Полный список стандартных кодировок Python
Столбцы индекса и завершающие разделители
Если в файле есть один или более столбцов данных, чем количество имён столбцов, первый столбец будет использован в качестве имён строк DataFrame:
In [80]: data = 'a,b,c\n4,apple,bat,5.7\n8,orange,cow,10'
In [81]: pd.read_csv(StringIO(data))
Out[81]:
a b c
4 apple bat 5.7
8 orange cow 10.0
In [82]: data = 'index,a,b,c\n4,apple,bat,5.7\n8,orange,cow,10'
In [83]: pd.read_csv(StringIO(data), index_col=0)
Out[83]:
a b c
index
4 apple bat 5.7
8 orange cow 10.0
Обычно вы можете добиться этого поведения с помощью параметра index_col.
Существуют некоторые исключительные случаи, когда файл был подготовлен с разделителями в конце каждой строки данных, что сбивает с толку парсер. Чтобы явно отключить вывод столбца индекса и удалить последний столбец, передайте index_col=False:
In [84]: data = 'a,b,c\n4,apple,bat,\n8,orange,cow,'
In [85]: print(data)
a,b,c
4,apple,bat,
8,orange,cow,
In [86]: pd.read_csv(StringIO(data))
Out[86]:
a b c
4 apple bat NaN
8 orange cow NaN
In [87]: pd.read_csv(StringIO(data), index_col=False)
Out[87]:
a b c
0 4 apple bat
1 8 orange cow
Обработка дат
Указание столбцов дат
Для лучшей работы с данными типа datetime, read_csv() и read_table() используют ключевые аргументы parse_dates и date_parser для возможности указывать различные столбцы и форматы дат/времени для преобразования входных текстовых данных в объекты datetime.
Простейший случай — просто передать parse_dates=True:
# Use a column as an index, and parse it as dates.
In [88]: df = pd.read_csv('foo.csv', index_col=0, parse_dates=True)
In [89]: df
Out[89]:
A B C
date
2009-01-01 a 1 2
2009-01-02 b 3 4
2009-01-03 c 4 5
# These are python datetime objects
In [90]: df.index
Out[90]: DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], dtype='datetime64[ns]', name=u'date', freq=None)
Часто требуется хранить данные дат и времени отдельно или хранить различные поля дат отдельно. Ключевое слово parse_dates может использоваться для указания комбинации столбцов для анализа дат и/или времени.
Вы можете указать список списков столбцов для parse_dates, результирующие столбцы дат будут добавлены в начало результата (чтобы не повлиять на существующий порядок столбцов), а новые имена столбцов будут конкатенацией имён компонентов столбцов:
In [91]: print(open('tmp.csv').read())
KORD,19990127, 19:00:00, 18:56:00, 0.8100
KORD,19990127, 20:00:00, 19:56:00, 0.0100
KORD,19990127, 21:00:00, 20:56:00, -0.5900
KORD,19990127, 21:00:00, 21:18:00, -0.9900
KORD,19990127, 22:00:00, 21:56:00, -0.5900
KORD,19990127, 23:00:00, 22:56:00, -0.5900
In [92]: df = pd.read_csv('tmp.csv', header=None, parse_dates=[[1, 2], [1, 3]])
In [93]: df
Out[93]:
1_2 1_3 0 4
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
По умолчанию парсер удаляет составные столбцы дат, но вы можете выбрать их сохранение с помощью ключевого слова keep_date_col:
In [94]: df = pd.read_csv('tmp.csv', header=None, parse_dates=[[1, 2], [1, 3]],
....: keep_date_col=True)
....:
In [95]: df
Out[95]:
1_2 1_3 0 1 2 \
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 19990127 19:00:00
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 19990127 20:00:00
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD 19990127 21:00:00
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD 19990127 21:00:00
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD 19990127 22:00:00
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD 19990127 23:00:00
3 4
0 18:56:00 0.81
1 19:56:00 0.01
2 20:56:00 -0.59
3 21:18:00 -0.99
4 21:56:00 -0.59
5 22:56:00 -0.59
Обратите внимание, что если вы хотите объединить несколько текстовых столбцов в один столбец дат, должен использоваться вложенный список. Другими словами, parse_dates=[1, 2] означает, что второй и третий столбцы должны анализироваться как отдельные столбцы дат, а parse_dates=[[1, 2]] означает, что два столбца должны анализироваться в один столбец.
Вы также можете использовать словарь для указания пользовательских имён столбцов:
In [96]: date_spec = {'nominal': [1, 2], 'actual': [1, 3]}
In [97]: df = pd.read_csv('tmp.csv', header=None, parse_dates=date_spec)
In [98]: df
Out[98]:
nominal actual 0 4
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
Важно помнить, что если несколько текстовых столбцов анализируются в один столбец дат, то добавляется новый столбец данных. Спецификация index_col основана на этом новом наборе столбцов, а не на исходных столбцах данных:
In [99]: date_spec = {'nominal': [1, 2], 'actual': [1, 3]}
In [100]: df = pd.read_csv('tmp.csv', header=None, parse_dates=date_spec,
.....: index_col=0) #index is the nominal column
.....:
In [101]: df
Out[101]:
actual 0 4
nominal
1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
Примечание
read_csv имеет быстрый путь для анализа строк datetime в формате iso8601, например “2000-01-01T00:01:02+00:00” и аналогичных вариаций. Если вы можете организовать хранение данных datetime в этом формате, время загрузки значительно ускорится, наблюдалось увеличение в ~20 раз.
Примечание
При передаче словаря в качестве аргумента parse_dates, порядок добавленных столбцов не гарантируется, поскольку объекты dict не накладывают порядок на свои ключи. В Python 2.7+ вы можете использовать collections.OrderedDict вместо обычного dict, если это важно для вас. По этой причине при использовании словаря для 'parse_dates' в сочетании с аргументом index_col, лучше указать index_col в качестве имени столбца, а не в качестве индекса результирующей таблицы.
Функции анализа дат
Наконец, парсер позволяет указать пользовательскую функцию date_parser для максимального использования гибкости API анализа дат:
In [102]: import pandas.io.date_converters as conv
In [103]: df = pd.read_csv('tmp.csv', header=None, parse_dates=date_spec,
.....: date_parser=conv.parse_date_time)
.....:
In [104]: df
Out[104]:
nominal actual 0 4
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD 0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD 0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD -0.59
Pandas попытается вызвать функцию date_parser тремя различными способами. Если возникает исключение, будет предпринята следующая попытка:
-
date_parserсначала вызывается с одним или несколькими массивами в качестве аргументов, как определено с помощьюparse_dates(например,date_parser(['2013', '2013'], ['1', '2'])) - Если #1 завершается ошибкой,
date_parserвызывается со всеми столбцами, склеенными построчно в один массив (например,date_parser(['2013 1', '2013 2'])) - Если #2 завершается ошибкой,
date_parserвызывается один раз для каждой строки с одним или несколькими строковыми аргументами из столбцов, указанных с помощьюparse_dates(например,date_parser('2013', '1')для первой строки,date_parser('2013', '2')для второй и т. д.)
Обратите внимание, что с точки зрения производительности вы должны попробовать эти методы анализа дат в указанном порядке:
- Попробуйте определить формат с помощью
infer_datetime_format=True(см. раздел ниже) - Если вы знаете формат, используйте
pd.to_datetime():date_parser=lambda x: pd.to_datetime(x, format=...) - Если у вас действительно нестандартный формат, используйте пользовательскую функцию
date_parser. Для оптимальной производительности она должна быть векторизованной, т. е. принимать массивы в качестве аргументов.
Вы можете изучить функциональность анализа дат в date_converters.py и добавить свои собственные. Мы с удовольствием превратим этот модуль в поддерживаемую сообществом коллекцию парсеров дат/времени. Для начала date_converters.py содержит функции для анализа столбцов дат и времени, столбцов год/месяц/день и столбцов год/месяц/день/час/минута/секунда. Он также содержит функцию generic_parser, чтобы вы могли использовать её с функцией, которая работает с одной датой, а не со всем массивом.
Определение формата даты и времени
Если параметр parse_dates включён для некоторых или всех столбцов, и все строки datetime имеют одинаковый формат, вы можете значительно ускорить процесс, установив infer_datetime_format=True. При установленном значении pandas попытается угадать формат строк datetime и использовать более быстрый способ анализа строк. Наблюдалось ускорение анализа в 5-10 раз. Pandas вернётся к обычному анализу, если формат не может быть угадан или формат, который был угадан, не может правильно обработать весь столбец строк. Таким образом, в целом, infer_datetime_format не должно иметь никаких негативных последствий при включении.
Вот несколько примеров строк datetime, которые можно угадать (все представляют 30 декабря 2011 г. в 00:00:00):
- “20111230”
- “2011/12/30”
- “20111230 00:00:00”
- “12/30/2011 00:00:00”
- “30/Dec/2011 00:00:00”
- “30/Декабря/2011 00:00:00”
infer_datetime_format чувствителен к dayfirst. При dayfirst=True, он будет угадывать “01/12/2011” как 1 декабря. При dayfirst=False (по умолчанию) он будет угадывать “01/12/2011” как 12 января.
# Try to infer the format for the index column
In [105]: df = pd.read_csv('foo.csv', index_col=0, parse_dates=True,
.....: infer_datetime_format=True)
.....:
In [106]: df
Out[106]:
A B C
date
2009-01-01 a 1 2
2009-01-02 b 3 4
2009-01-03 c 4 5
Международные форматы дат
Хотя форматы дат США обычно имеют вид MM/DD/YYYY, многие международные форматы используют DD/MM/YYYY вместо этого. Для удобства предоставляется ключевое слово dayfirst:
In [107]: print(open('tmp.csv').read())
date,value,cat
1/6/2000,5,a
2/6/2000,10,b
3/6/2000,15,c
In [108]: pd.read_csv('tmp.csv', parse_dates=[0])
Out[108]:
date value cat
0 2000-01-06 5 a
1 2000-02-06 10 b
2 2000-03-06 15 c
In [109]: pd.read_csv('tmp.csv', dayfirst=True, parse_dates=[0])
Out[109]:
date value cat
0 2000-06-01 5 a
1 2000-06-02 10 b
2 2000-06-03 15 c
Указание метода преобразования чисел с плавающей точкой
Параметр float_precision может быть задан для использования конкретного преобразователя чисел с плавающей точкой во время разбора с помощью движка C. Доступны обычный преобразователь, преобразователь высокой точности и преобразователь с обратным преобразованием (который гарантирует обратное преобразование значений после записи в файл). Например:
In [110]: val = '0.3066101993807095471566981359501369297504425048828125'
In [111]: data = 'a,b,c\n1,2,{0}'.format(val)
In [112]: abs(pd.read_csv(StringIO(data), engine='c', float_precision=None)['c'][0] - float(val))
Out[112]: 1.1102230246251565e-16
In [113]: abs(pd.read_csv(StringIO(data), engine='c', float_precision='high')['c'][0] - float(val))
Out[113]: 5.5511151231257827e-17
In [114]: abs(pd.read_csv(StringIO(data), engine='c', float_precision='round_trip')['c'][0] - float(val))
Out[114]: 0.0
Разделители тысяч
Для больших чисел, записанных с разделителем тысяч, можно установить ключевое слово thousands в строку длиной 1, чтобы целые числа анализировались корректно:
По умолчанию числа с разделителем тысяч будут анализироваться как строки
In [115]: print(open('tmp.csv').read())
ID|level|category
Patient1|123,000|x
Patient2|23,000|y
Patient3|1,234,018|z
In [116]: df = pd.read_csv('tmp.csv', sep='|')
In [117]: df
Out[117]:
ID level category
0 Patient1 123,000 x
1 Patient2 23,000 y
2 Patient3 1,234,018 z
In [118]: df.level.dtype
Out[118]: dtype('O')
Ключевое слово thousands позволяет корректно анализировать целые числа
In [119]: print(open('tmp.csv').read())
ID|level|category
Patient1|123,000|x
Patient2|23,000|y
Patient3|1,234,018|z
In [120]: df = pd.read_csv('tmp.csv', sep='|', thousands=',')
In [121]: df
Out[121]:
ID level category
0 Patient1 123000 x
1 Patient2 23000 y
2 Patient3 1234018 z
In [122]: df.level.dtype
Out[122]: dtype('int64')
Значения NA
Для управления значениями, которые анализируются как пропущенные значения (обозначаемые NaN), укажите строку в na_values. Если вы указываете список строк, все значения в нём считаются пропущенными. Если вы указываете число (например, float, как 5.0 или integer, как 5), соответствующие эквивалентные значения также будут означать пропущенное значение (в этом случае эффективно [5.0,5] распознаются как NaN).
Для полной перезаписи значений по умолчанию, распознаваемых как пропущенные, укажите keep_default_na=False. По умолчанию NaN значения, распознаваемые как ['-1.#IND', '1.#QNAN', '1.#IND', '-1.#QNAN', '#N/A','N/A', 'NA',
'#NA', 'NULL', 'NaN', '-NaN', 'nan', '-nan']. Хотя строка длиной 0 '' не включена в список значений по умолчанию NaN, она всё ещё обрабатывается как пропущенное значение.
read_csv(path, na_values=[5])
значения по умолчанию, помимо 5, 5.0, при интерпретации как числа, распознаются как NaN
read_csv(path, keep_default_na=False, na_values=[""])
только пустое поле будет NaN
read_csv(path, keep_default_na=False, na_values=["NA", "0"])
только NA и 0 в качестве строк будут NaN
read_csv(path, na_values=["Nope"])
значения по умолчанию, помимо строки "Nope", распознаются как NaN
Бесконечность
inf подобные значения будут анализироваться как np.inf (положительная бесконечность), а -inf как -np.inf (отрицательная бесконечность). Эти значения игнорируют регистр, поэтому Inf, также будет анализироваться как np.inf.
Возврат рядов
Используя ключевое слово squeeze, парсер вернёт вывод с одним столбцом как Series:
In [123]: print(open('tmp.csv').read())
level
Patient1,123000
Patient2,23000
Patient3,1234018
In [124]: output = pd.read_csv('tmp.csv', squeeze=True)
In [125]: output
Out[125]:
Patient1 123000
Patient2 23000
Patient3 1234018
Name: level, dtype: int64
In [126]: type(output)
Out[126]: pandas.core.series.Series
Булевы значения
Общие значения True, False, TRUE, и FALSE распознаются как булевы. Иногда нужно распознать другие значения как булевы. Для этого используйте опции true_values и false_values:
In [127]: data= 'a,b,c\n1,Yes,2\n3,No,4' In [128]: print(data) a,b,c 1,Yes,2 3,No,4 In [129]: pd.read_csv(StringIO(data)) Out[129]: a b c 0 1 Yes 2 1 3 No 4 In [130]: pd.read_csv(StringIO(data), true_values=['Yes'], false_values=['No']) Out[130]: a b c 0 1 True 2 1 3 False 4
Обработка «плохих» строк
В некоторых файлах могут быть строки с неправильным форматом, имеющие слишком мало или слишком много полей. Строки с недостаточным количеством полей будут заполнены значениями NA в последующих полях. Строки с избыточным количеством полей вызовут ошибку по умолчанию:
In [27]: data = 'a,b,c\n1,2,3\n4,5,6,7\n8,9,10' In [28]: pd.read_csv(StringIO(data)) --------------------------------------------------------------------------- CParserError Traceback (most recent call last) CParserError: Error tokenizing data. C error: Expected 3 fields in line 3, saw 4
Можно выбрать пропуск таких строк:
In [29]: pd.read_csv(StringIO(data), error_bad_lines=False) Skipping line 3: expected 3 fields, saw 4 Out[29]: a b c 0 1 2 3 1 8 9 10
Кавычки и управляющие символы
Кавычки (и другие управляющие символы) встраиваемых полей могут обрабатываться различными способами. Одним из способов является использование обратных слэшей; для корректного анализа этих данных необходимо передать опцию escapechar:
In [131]: data = 'a,b\n"hello, \\"Bob\\", nice to see you",5'
In [132]: print(data)
a,b
"hello, \"Bob\", nice to see you",5
In [133]: pd.read_csv(StringIO(data), escapechar='\\')
Out[133]:
a b
0 hello, "Bob", nice to see you 5
Файлы с колонками фиксированной ширины
Хотя read_csv считывает данные с разделителями, функция read_fwf() работает с файлами данных, имеющими известную и фиксированную ширину столбцов. Параметры функции read_fwf в значительной степени аналогичны read_csv с двумя дополнительными параметрами:
-
colspecs: Список пар (кортежей), задающих границы столбцов фиксированной ширины каждой строки в виде полуоткрытых интервалов (т.е., [от, до[). Строковое значение 'infer' может быть использовано для указания парсеру попытаться определить спецификации столбцов по первыми 100 строкам данных. По умолчанию используется инференс, если не указано иное. -
widths: Список ширин полей, который может быть использован вместо 'colspecs', если интервалы являются непрерывными.
Рассмотрим типичный файл данных с фиксированной шириной столбцов:
In [134]: print(open('bar.csv').read())
id8141 360.242940 149.910199 11950.7
id1594 444.953632 166.985655 11788.4
id1849 364.136849 183.628767 11806.2
id1230 413.836124 184.375703 11916.8
id1948 502.953953 173.237159 12468.3
Для анализа этого файла в DataFrame, нам просто нужно предоставить спецификации столбцов функции read_fwf вместе с именем файла:
#Column specifications are a list of half-intervals
In [135]: colspecs = [(0, 6), (8, 20), (21, 33), (34, 43)]
In [136]: df = pd.read_fwf('bar.csv', colspecs=colspecs, header=None, index_col=0)
In [137]: df
Out[137]:
1 2 3
0
id8141 360.242940 149.910199 11950.7
id1594 444.953632 166.985655 11788.4
id1849 364.136849 183.628767 11806.2
id1230 413.836124 184.375703 11916.8
id1948 502.953953 173.237159 12468.3
Обратите внимание, как парсер автоматически выбирает имена столбцов X.<номер столбца> при указании аргумента header=None. В качестве альтернативы, можно указать только ширины столбцов для непрерывных столбцов:
#Widths are a list of integers
In [138]: widths = [6, 14, 13, 10]
In [139]: df = pd.read_fwf('bar.csv', widths=widths, header=None)
In [140]: df
Out[140]:
0 1 2 3
0 id8141 360.242940 149.910199 11950.7
1 id1594 444.953632 166.985655 11788.4
2 id1849 364.136849 183.628767 11806.2
3 id1230 413.836124 184.375703 11916.8
4 id1948 502.953953 173.237159 12468.3
Парсер учтёт дополнительные пробелы вокруг столбцов, поэтому дополнительные пробелы между столбцами в файле допустимы.
Новая функция в версии 0.13.0.
По умолчанию read_fwf попытается определить разделители файла colspecs с помощью первых 100 строк файла. Это возможно только в случаях, когда столбцы выровнены и правильно разделены указанным delimiter (разделитель по умолчанию - пробел).
In [141]: df = pd.read_fwf('bar.csv', header=None, index_col=0)
In [142]: df
Out[142]:
1 2 3
0
id8141 360.242940 149.910199 11950.7
id1594 444.953632 166.985655 11788.4
id1849 364.136849 183.628767 11806.2
id1230 413.836124 184.375703 11916.8
id1948 502.953953 173.237159 12468.3
Индексы
Файлы с «неявным» столбцом индекса
Рассмотрим файл с одной строкой заголовка меньше, чем число столбцов данных:
In [143]: print(open('foo.csv').read())
A,B,C
20090101,a,1,2
20090102,b,3,4
20090103,c,4,5
В этом особом случае read_csv предполагает, что первый столбец будет использоваться в качестве индекса DataFrame:
In [144]: pd.read_csv('foo.csv')
Out[144]:
A B C
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
Обратите внимание, что даты не были автоматически обработаны. В этом случае вам нужно действовать так же, как и раньше:
In [145]: df = pd.read_csv('foo.csv', parse_dates=True)
In [146]: df.index
Out[146]: DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], dtype='datetime64[ns]', freq=None)
Чтение индекса с MultiIndex
Предположим, у вас есть данные, индексированные по двум столбцам:
In [147]: print(open('data/mindex_ex.csv').read())
year,indiv,zit,xit
1977,"A",1.2,.6
1977,"B",1.5,.5
1977,"C",1.7,.8
1978,"A",.2,.06
1978,"B",.7,.2
1978,"C",.8,.3
1978,"D",.9,.5
1978,"E",1.4,.9
1979,"C",.2,.15
1979,"D",.14,.05
1979,"E",.5,.15
1979,"F",1.2,.5
1979,"G",3.4,1.9
1979,"H",5.4,2.7
1979,"I",6.4,1.2
Аргумент index_col для read_csv и read_table может принимать список номеров столбцов, чтобы преобразовать несколько столбцов в MultiIndex для индекса возвращаемого объекта:
In [148]: df = pd.read_csv("data/mindex_ex.csv", index_col=[0,1])
In [149]: df
Out[149]:
zit xit
year indiv
1977 A 1.20 0.60
B 1.50 0.50
C 1.70 0.80
1978 A 0.20 0.06
B 0.70 0.20
C 0.80 0.30
D 0.90 0.50
E 1.40 0.90
1979 C 0.20 0.15
D 0.14 0.05
E 0.50 0.15
F 1.20 0.50
G 3.40 1.90
H 5.40 2.70
I 6.40 1.20
In [150]: df.ix[1978]
Out[150]:
zit xit
indiv
A 0.2 0.06
B 0.7 0.20
C 0.8 0.30
D 0.9 0.50
E 1.4 0.90
Чтение столбцов с MultiIndex
Указав список расположений строк для аргумента header, можно прочитать MultiIndex для столбцов. Указание несмежных строк пропустит промежуточные строки. Для сохранения поведения до версии 0.13 по преобразованию столбцов в кортежи, укажите tupleize_cols=True.
In [151]: from pandas.util.testing import makeCustomDataframe as mkdf
In [152]: df = mkdf(5,3,r_idx_nlevels=2,c_idx_nlevels=4)
In [153]: df.to_csv('mi.csv')
In [154]: print(open('mi.csv').read())
C0,,C_l0_g0,C_l0_g1,C_l0_g2
C1,,C_l1_g0,C_l1_g1,C_l1_g2
C2,,C_l2_g0,C_l2_g1,C_l2_g2
C3,,C_l3_g0,C_l3_g1,C_l3_g2
R0,R1,,,
R_l0_g0,R_l1_g0,R0C0,R0C1,R0C2
R_l0_g1,R_l1_g1,R1C0,R1C1,R1C2
R_l0_g2,R_l1_g2,R2C0,R2C1,R2C2
R_l0_g3,R_l1_g3,R3C0,R3C1,R3C2
R_l0_g4,R_l1_g4,R4C0,R4C1,R4C2
In [155]: pd.read_csv('mi.csv',header=[0,1,2,3],index_col=[0,1])
Out[155]:
C0 C_l0_g0 C_l0_g1 C_l0_g2
C1 C_l1_g0 C_l1_g1 C_l1_g2
C2 C_l2_g0 C_l2_g1 C_l2_g2
C3 C_l3_g0 C_l3_g1 C_l3_g2
R0 R1
R_l0_g0 R_l1_g0 R0C0 R0C1 R0C2
R_l0_g1 R_l1_g1 R1C0 R1C1 R1C2
R_l0_g2 R_l1_g2 R2C0 R2C1 R2C2
R_l0_g3 R_l1_g3 R3C0 R3C1 R3C2
R_l0_g4 R_l1_g4 R4C0 R4C1 R4C2
Начиная с версии 0.13.0, read_csv сможет интерпретировать более распространённый формат многостолбцовых индексов.
In [156]: print(open('mi2.csv').read())
,a,a,a,b,c,c
,q,r,s,t,u,v
one,1,2,3,4,5,6
two,7,8,9,10,11,12
In [157]: pd.read_csv('mi2.csv',header=[0,1],index_col=0)
Out[157]:
a b c
q r s t u v
one 1 2 3 4 5 6
two 7 8 9 10 11 12
Примечание: Если index_col не указан (например, у вас нет индекса или вы его не указали с df.to_csv(..., index=False), все names индекса столбцов будут утеряны.
Автоматическое «определение» разделителя
read_csv способно определять файлы с разделителями (не обязательно запятыми), так как pandas использует класс csv.Sniffer модуля csv. Для этого необходимо указать sep=None.
In [158]: print(open('tmp2.sv').read())
:0:1:2:3
0:0.469112299907:-0.282863344329:-1.50905850317:-1.13563237102
1:1.21211202502:-0.173214649053:0.119208711297:-1.04423596628
2:-0.861848963348:-2.10456921889:-0.494929274069:1.07180380704
3:0.721555162244:-0.70677113363:-1.03957498511:0.271859885543
4:-0.424972329789:0.567020349794:0.276232019278:-1.08740069129
5:-0.673689708088:0.113648409689:-1.47842655244:0.524987667115
6:0.40470521868:0.57704598592:-1.71500201611:-1.03926848351
7:-0.370646858236:-1.15789225064:-1.34431181273:0.844885141425
8:1.07576978372:-0.10904997528:1.64356307036:-1.46938795954
9:0.357020564133:-0.67460010373:-1.77690371697:-0.968913812447
In [159]: pd.read_csv('tmp2.sv', sep=None, engine='python')
Out[159]:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
4 4 -0.424972 0.567020 0.276232 -1.087401
5 5 -0.673690 0.113648 -1.478427 0.524988
6 6 0.404705 0.577046 -1.715002 -1.039268
7 7 -0.370647 -1.157892 -1.344312 0.844885
8 8 1.075770 -0.109050 1.643563 -1.469388
9 9 0.357021 -0.674600 -1.776904 -0.968914
Итерация по файлам по частям
Предположим, вы хотите выполнить итерацию по файлу (возможно, очень большому) лениво, вместо чтения всего файла в память, как в следующем примере:
In [160]: print(open('tmp.sv').read())
|0|1|2|3
0|0.469112299907|-0.282863344329|-1.50905850317|-1.13563237102
1|1.21211202502|-0.173214649053|0.119208711297|-1.04423596628
2|-0.861848963348|-2.10456921889|-0.494929274069|1.07180380704
3|0.721555162244|-0.70677113363|-1.03957498511|0.271859885543
4|-0.424972329789|0.567020349794|0.276232019278|-1.08740069129
5|-0.673689708088|0.113648409689|-1.47842655244|0.524987667115
6|0.40470521868|0.57704598592|-1.71500201611|-1.03926848351
7|-0.370646858236|-1.15789225064|-1.34431181273|0.844885141425
8|1.07576978372|-0.10904997528|1.64356307036|-1.46938795954
9|0.357020564133|-0.67460010373|-1.77690371697|-0.968913812447
In [161]: table = pd.read_table('tmp.sv', sep='|')
In [162]: table
Out[162]:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
4 4 -0.424972 0.567020 0.276232 -1.087401
5 5 -0.673690 0.113648 -1.478427 0.524988
6 6 0.404705 0.577046 -1.715002 -1.039268
7 7 -0.370647 -1.157892 -1.344312 0.844885
8 8 1.075770 -0.109050 1.643563 -1.469388
9 9 0.357021 -0.674600 -1.776904 -0.968914
Указав chunksize для read_csv или read_table, возвращаемое значение будет итерируемым объектом типа TextFileReader:
In [163]: reader = pd.read_table('tmp.sv', sep='|', chunksize=4)
In [164]: reader
Out[164]: <pandas.io.parsers.TextFileReader at 0x7ff27e15a450>
In [165]: for chunk in reader:
.....: print(chunk)
.....:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
Unnamed: 0 0 1 2 3
4 4 -0.424972 0.567020 0.276232 -1.087401
5 5 -0.673690 0.113648 -1.478427 0.524988
6 6 0.404705 0.577046 -1.715002 -1.039268
7 7 -0.370647 -1.157892 -1.344312 0.844885
Unnamed: 0 0 1 2 3
8 8 1.075770 -0.10905 1.643563 -1.469388
9 9 0.357021 -0.67460 -1.776904 -0.968914
Указание iterator=True также вернёт объект TextFileReader:
In [166]: reader = pd.read_table('tmp.sv', sep='|', iterator=True)
In [167]: reader.get_chunk(5)
Out[167]:
Unnamed: 0 0 1 2 3
0 0 0.469112 -0.282863 -1.509059 -1.135632
1 1 1.212112 -0.173215 0.119209 -1.044236
2 2 -0.861849 -2.104569 -0.494929 1.071804
3 3 0.721555 -0.706771 -1.039575 0.271860
4 4 -0.424972 0.567020 0.276232 -1.087401
Указание движка парсера
Внутри pandas используется быстрый и эффективный парсер, реализованный на C, а также реализация на Python, которая в настоящее время более полна функциями. Где это возможно, pandas использует парсер C (указанный как engine='c'), но может перейти на Python, если указаны неподдерживаемые опции C. В настоящее время неподдерживаемые опции C включают:
-
sepкроме одного символа (например, разделители с использованием регулярных выражений) skipfooter-
sep=Noneсdelim_whitespace=False
Указание любой из вышеперечисленных опций приведет к ParserWarning, если явно не выбран движок Python с помощью engine='python'.
Запись данных
Запись в формате CSV
Объекты Series и DataFrame имеют метод to_csv, который позволяет сохранить содержимое объекта как файл значений, разделённых запятыми. Функция принимает несколько аргументов. Только первый аргумент является обязательным.
-
path_or_buf: Путь к файлу для записи или объект StringIO -
sep: Разделитель полей в выходном файле (по умолчанию „,”) -
na_rep: Строковое представление отсутствующего значения (по умолчанию ‘’) -
float_format: Форматная строка для чисел с плавающей точкой -
cols: Столбцы для записи (по умолчанию None) -
header: Нужно ли записывать названия столбцов (по умолчанию True) -
index: Нужно ли записывать имена строк (индексы) (по умолчанию True) -
index_label: Метка(и) столбца(ов) для столбца(ов) индекса, если нужно. Если None (по умолчанию), иheaderиindexравны True, используются имена индекса. (Последовательность должна быть указана, если DataFrame использует MultiIndex). -
mode: Режим записи в Python, по умолчанию ‘w’ -
encoding: Строка, представляющая кодировку, которую следует использовать, если содержимое не ASCII, для версий Python до 3 -
line_terminator: Последовательность символов, обозначающая конец строки (по умолчанию ‘\n’) -
quoting: Установка правил цитирования, как в модуле csv (по умолчанию csv.QUOTE_MINIMAL). Обратите внимание, что если вы установилиfloat_format, то числа с плавающей точкой преобразуются в строки, и csv.QUOTE_NONNUMERIC будет обрабатывать их как нечисловые -
quotechar: Символ, используемый для цитирования полей (по умолчанию ‘”’) -
doublequote: Управление цитированиемquotecharв полях (по умолчанию True) -
escapechar: Символ, используемый для экранированияsepиquotecharпри необходимости (по умолчанию None) -
chunksize: Количество строк для записи за один раз -
tupleize_cols: Если False (по умолчанию), записывается как список кортежей, в противном случае записывается в расширенном формате строки, подходящем дляread_csv -
date_format: Форматная строка для объектов datetime
Запись отформатированной строки
Объект DataFrame имеет метод to_string, который позволяет управлять строковым представлением объекта. Все аргументы необязательны:
-
bufпо умолчанию None, например, объект StringIO -
columnsпо умолчанию None, какие столбцы записывать -
col_spaceпо умолчанию None, минимальная ширина каждого столбца. -
na_repпо умолчаниюNaN, представление значения NA -
formattersпо умолчанию None, словарь (по столбцам) функций, каждая из которых принимает один аргумент и возвращает отформатированную строку -
float_formatпо умолчанию None, функция, которая принимает один (вещественный) аргумент и возвращает отформатированную строку; применяется к числам с плавающей точкой в DataFrame. -
sparsifyпо умолчанию True, установить в False для DataFrame с иерархическим индексом, чтобы печатать каждый ключ многоуровневого индекса в каждой строке. -
index_namesпо умолчанию True, выводит имена индексов -
indexпо умолчанию True, выводит индекс (т. е. метки строк) -
headerпо умолчанию True, выводит метки столбцов -
justifyпо умолчаниюleft, выводит заголовки столбцов выровненными влево или вправо
Объект Series также имеет метод to_string, но только с аргументами buf, na_rep, float_format. Также есть аргумент length, который, если установлен в True, дополнительно выведет длину Series.
JSON
Чтение и запись файлов и строк в формате JSON.
Запись JSON
DataFrame или Series можно преобразовать в строку JSON. Используйте to_json с необязательными параметрами:
-
path_or_buf: путь к файлу или буфер для записи вывода. Может быть объектомNone, в этом случае возвращается строка JSON -
orient:- Series :
-
- по умолчанию
index - допустимые значения {
split,records,index}
- по умолчанию
- DataFrame
-
- по умолчанию
columns - допустимые значения {
split,records,index,columns,values}
- по умолчанию
Формат строки JSON
splitПохожий на словарь {индекс -> [индекс], столбцы -> [столбцы], данные -> [значения]} recordsСписок вида [{столбец -> значение}, ... , {столбец -> значение}] indexСловарь вида {индекс -> {столбец -> значение}} columnsСловарь вида {столбец -> {индекс -> значение}} valuesТолько массив значений -
date_format: строка, тип преобразования даты, ‘epoch’ для временных меток, ‘iso’ для ISO8601. -
double_precision: количество десятичных знаков для кодирования чисел с плавающей точкой, по умолчанию 10. -
force_ascii: принудительное преобразование закодированной строки в ASCII, по умолчанию True. -
date_unit: единица времени для кодирования, управляет точностью временных меток и ISO8601. Одно из ‘s’, ‘ms’, ‘us’ или ‘ns’ для секунд, миллисекунд, микросекунд и наносекунд соответственно. По умолчанию ‘ms’. -
default_handler: обработчик, вызываемый, если объект не может быть преобразован в подходящий для JSON формат. Принимает один аргумент — объект для преобразования и возвращает сериализуемый объект. -
lines: Еслиrecordsorient, то записывает каждую запись в строку как json.
Обратите внимание, что NaN‘ы, NaT‘ы и None будут преобразованы в null , а datetime будут преобразованы в зависимости от параметров date_format и date_unit.
In [168]: dfj = pd.DataFrame(randn(5, 2), columns=list('AB'))
In [169]: json = dfj.to_json()
In [170]: json
Out[170]: '{"A":{"0":-1.2945235903,"1":0.2766617129,"2":-0.0139597524,"3":-0.0061535699,"4":0.8957173022},"B":{"0":0.4137381054,"1":-0.472034511,"2":-0.3625429925,"3":-0.923060654,"4":0.8052440254}}'
Варианты orient
Существует несколько вариантов формата результирующего файла/строки JSON. Рассмотрим следующие DataFrame и Series:
In [171]: dfjo = pd.DataFrame(dict(A=range(1, 4), B=range(4, 7), C=range(7, 10)),
.....: columns=list('ABC'), index=list('xyz'))
.....:
In [172]: dfjo
Out[172]:
A B C
x 1 4 7
y 2 5 8
z 3 6 9
In [173]: sjo = pd.Series(dict(x=15, y=16, z=17), name='D')
In [174]: sjo
Out[174]:
x 15
y 16
z 17
Name: D, dtype: int64
Ориентированный на столбцы (по умолчанию для DataFrame) сериализует данные как вложенные объекты JSON, где метки столбцов являются основным индексом:
In [175]: dfjo.to_json(orient="columns")
Out[175]: '{"A":{"x":1,"y":2,"z":3},"B":{"x":4,"y":5,"z":6},"C":{"x":7,"y":8,"z":9}}'
Ориентированный на индексы (по умолчанию для Series) аналогично ориентированному на столбцы, но теперь метки индексов являются основными:
In [176]: dfjo.to_json(orient="index")
Out[176]: '{"x":{"A":1,"B":4,"C":7},"y":{"A":2,"B":5,"C":8},"z":{"A":3,"B":6,"C":9}}'
In [177]: sjo.to_json(orient="index")
Out[177]: '{"x":15,"y":16,"z":17}'
Ориентированный на записи сериализует данные в массив JSON записей столбец -> значение, метки индекса не включаются. Это полезно для передачи данных DataFrame в библиотеки визуализации, например, в JavaScript библиотеку d3.js:
In [178]: dfjo.to_json(orient="records")
Out[178]: '[{"A":1,"B":4,"C":7},{"A":2,"B":5,"C":8},{"A":3,"B":6,"C":9}]'
In [179]: sjo.to_json(orient="records")
Out[179]: '[15,16,17]'
Ориентированный на значения — базовый вариант, который сериализует только массив вложенных JSON значений, метки столбцов и индексов не включаются:
In [180]: dfjo.to_json(orient="values") Out[180]: '[[1,4,7],[2,5,8],[3,6,9]]'
Ориентированный на разделы сериализует в объект JSON, содержащий отдельные записи для значений, индексов и столбцов. Имя также включено для Series:
In [181]: dfjo.to_json(orient="split")
Out[181]: '{"columns":["A","B","C"],"index":["x","y","z"],"data":[[1,4,7],[2,5,8],[3,6,9]]}'
In [182]: sjo.to_json(orient="split")
Out[182]: '{"name":"D","index":["x","y","z"],"data":[15,16,17]}'
Примечание
Любой вариант orient, который кодирует в объект JSON, не сохранит порядок меток индекса и столбцов во время обратного сериализации. Если вы хотите сохранить порядок меток, используйте вариант split , так как он использует упорядоченные контейнеры.
Обработка дат
Запись в формате даты ISO
In [183]: dfd = pd.DataFrame(randn(5, 2), columns=list('AB'))
In [184]: dfd['date'] = pd.Timestamp('20130101')
In [185]: dfd = dfd.sort_index(1, ascending=False)
In [186]: json = dfd.to_json(date_format='iso')
In [187]: json
Out[187]: '{"date":{"0":"2013-01-01T00:00:00.000Z","1":"2013-01-01T00:00:00.000Z","2":"2013-01-01T00:00:00.000Z","3":"2013-01-01T00:00:00.000Z","4":"2013-01-01T00:00:00.000Z"},"B":{"0":2.5656459463,"1":1.3403088498,"2":-0.2261692849,"3":0.8138502857,"4":-0.8273169356},"A":{"0":-1.2064117817,"1":1.4312559863,"2":-1.1702987971,"3":0.4108345112,"4":0.1320031703}}'
Запись в формате даты ISO с микросекундами
In [188]: json = dfd.to_json(date_format='iso', date_unit='us')
In [189]: json
Out[189]: '{"date":{"0":"2013-01-01T00:00:00.000000Z","1":"2013-01-01T00:00:00.000000Z","2":"2013-01-01T00:00:00.000000Z","3":"2013-01-01T00:00:00.000000Z","4":"2013-01-01T00:00:00.000000Z"},"B":{"0":2.5656459463,"1":1.3403088498,"2":-0.2261692849,"3":0.8138502857,"4":-0.8273169356},"A":{"0":-1.2064117817,"1":1.4312559863,"2":-1.1702987971,"3":0.4108345112,"4":0.1320031703}}'
Временные метки эпохи, в секундах
In [190]: json = dfd.to_json(date_format='epoch', date_unit='s')
In [191]: json
Out[191]: '{"date":{"0":1356998400,"1":1356998400,"2":1356998400,"3":1356998400,"4":1356998400},"B":{"0":2.5656459463,"1":1.3403088498,"2":-0.2261692849,"3":0.8138502857,"4":-0.8273169356},"A":{"0":-1.2064117817,"1":1.4312559863,"2":-1.1702987971,"3":0.4108345112,"4":0.1320031703}}'
Запись в файл с индексом даты и столбцом даты
In [192]: dfj2 = dfj.copy()
In [193]: dfj2['date'] = pd.Timestamp('20130101')
In [194]: dfj2['ints'] = list(range(5))
In [195]: dfj2['bools'] = True
In [196]: dfj2.index = pd.date_range('20130101', periods=5)
In [197]: dfj2.to_json('test.json')
In [198]: open('test.json').read()
Out[198]: '{"A":{"1356998400000":-1.2945235903,"1357084800000":0.2766617129,"1357171200000":-0.0139597524,"1357257600000":-0.0061535699,"1357344000000":0.8957173022},"B":{"1356998400000":0.4137381054,"1357084800000":-0.472034511,"1357171200000":-0.3625429925,"1357257600000":-0.923060654,"1357344000000":0.8052440254},"date":{"1356998400000":1356998400000,"1357084800000":1356998400000,"1357171200000":1356998400000,"1357257600000":1356998400000,"1357344000000":1356998400000},"ints":{"1356998400000":0,"1357084800000":1,"1357171200000":2,"1357257600000":3,"1357344000000":4},"bools":{"1356998400000":true,"1357084800000":true,"1357171200000":true,"1357257600000":true,"1357344000000":true}}'
Поведение по умолчанию
Если JSON-сериализатор не может напрямую обработать содержимое контейнера, он откажется от обработки следующим образом:
- если тип данных не поддерживается (например,
np.complex) тоdefault_handler, если предоставлен, будет вызван для каждого значения, иначе генерируется исключение. - если объект не поддерживается, будет выполнена попытка:
- проверить, определен ли метод
toDictи вызвать его. МетодtoDictдолжен возвращатьdict, который затем будет сериализован в JSON. - вызвать
default_handler, если он был предоставлен. - преобразовать объект в
dictпутем обхода его содержимого. Однако это часто завершитсяOverflowErrorили даст неожиданные результаты.
- проверить, определен ли метод
В общем случае лучший подход к работе с недопустимыми объектами или типами данных — предоставить default_handler. Например:
DataFrame([1.0, 2.0, complex(1.0, 2.0)]).to_json() # raises RuntimeError: Unhandled numpy dtype 15
с этим можно справиться, указав простой default_handler:
In [199]: pd.DataFrame([1.0, 2.0, complex(1.0, 2.0)]).to_json(default_handler=str)
Out[199]: '{"0":{"0":"(1+0j)","1":"(2+0j)","2":"(1+2j)"}}'
Чтение JSON
Чтение строки JSON в объект pandas может принять ряд параметров. Парсер попытается проанализировать DataFrame, если typ не указан или равен None. Чтобы явно принудить к парсингу Series, передайте typ=series
-
filepath_or_buffer: a VALID JSON string or file handle / StringIO. The string could be a URL. Valid URL schemes include http, ftp, S3, and file. For file URLs, a host is expected. For instance, a local file could be file ://localhost/path/to/table.json -
typ: type of object to recover (series or frame), default ‘frame’ -
orient:- Series :
-
- default is
index - allowed values are {
split,records,index}
- default is
- DataFrame
-
- default is
columns - allowed values are {
split,records,index,columns,values}
- default is
The format of the JSON string
splitdict like {index -> [index], columns -> [columns], data -> [values]} recordslist like [{column -> value}, ... , {column -> value}] indexdict like {index -> {column -> value}} columnsdict like {column -> {index -> value}} valuesjust the values array -
dtype: if True, infer dtypes, if a dict of column to dtype, then use those, if False, then don’t infer dtypes at all, default is True, apply only to the data -
convert_axes: boolean, try to convert the axes to the proper dtypes, default is True -
convert_dates: a list of columns to parse for dates; If True, then try to parse date-like columns, default is True -
keep_default_dates: boolean, default True. If parsing dates, then parse the default date-like columns -
numpy: direct decoding to numpy arrays. default is False; Supports numeric data only, although labels may be non-numeric. Also note that the JSON ordering MUST be the same for each term ifnumpy=True -
precise_float: boolean, defaultFalse. Set to enable usage of higher precision (strtod) function when decoding string to double values. Default (False) is to use fast but less precise builtin functionality -
date_unit: string, the timestamp unit to detect if converting dates. Default None. By default the timestamp precision will be detected, if this is not desired then pass one of ‘s’, ‘ms’, ‘us’ or ‘ns’ to force timestamp precision to seconds, milliseconds, microseconds or nanoseconds respectively. -
lines: reads file as one json object per line. -
encoding: The encoding to use to decode py3 bytes.
The parser will raise one of ValueError/TypeError/AssertionError if the JSON is not parseable.
If a non-default orient was used when encoding to JSON be sure to pass the same option here so that decoding produces sensible results, see Orient Options for an overview.
Преобразование данных
Значения по умолчанию для convert_axes=True, dtype=True, и convert_dates=True будут пытаться преобразовать оси и все данные в соответствующие типы, включая даты. Если нужно переопределить определённые типы данных, передайте словарь в dtype. convert_axes следует устанавливать в False только если требуется сохранить строковые числа (например, ‘1’, ‘2’) в осях.
Примечание
Большие целочисленные значения могут быть преобразованы в даты, если convert_dates=True и данные и/или метки столбцов имеют вид даты. Точный порог зависит от date_unit. «Вид даты» означает, что метка столбца соответствует одному из следующих критериев:
- она заканчивается на
'_at' - она заканчивается на
'_time' - она начинается с
'timestamp' - она является
'modified' - она является
'date'
Предупреждение
При чтении данных JSON автоматическое приведение к типам данных имеет некоторые особенности:
- индекс может быть восстановлен в другом порядке по сравнению с сериализацией, то есть порядок возвращаемого индекса не гарантируется как идентичный до сериализации
- столбец, содержавший данные
floatбудет преобразован вintegerесли это возможно безопасно, например, столбец1. - столбцы bool будут преобразованы в
integerпри восстановлении
Поэтому иногда может потребоваться указать определённые типы данных через параметр dtype.
Чтение из JSON строки:
In [200]: pd.read_json(json)
Out[200]:
A B date
0 -1.206412 2.565646 2013-01-01
1 1.431256 1.340309 2013-01-01
2 -1.170299 -0.226169 2013-01-01
3 0.410835 0.813850 2013-01-01
4 0.132003 -0.827317 2013-01-01
Чтение из файла:
In [201]: pd.read_json('test.json')
Out[201]:
A B bools date ints
2013-01-01 -1.294524 0.413738 True 2013-01-01 0
2013-01-02 0.276662 -0.472035 True 2013-01-01 1
2013-01-03 -0.013960 -0.362543 True 2013-01-01 2
2013-01-04 -0.006154 -0.923061 True 2013-01-01 3
2013-01-05 0.895717 0.805244 True 2013-01-01 4
Не преобразовывать данные (но всё же преобразовать оси и даты):
In [202]: pd.read_json('test.json', dtype=object).dtypes
Out[202]:
A object
B object
bools object
date object
ints object
dtype: object
Указать типы данных для преобразования:
In [203]: pd.read_json('test.json', dtype={'A' : 'float32', 'bools' : 'int8'}).dtypes
Out[203]:
A float32
B float64
bools int8
date datetime64[ns]
ints int64
dtype: object
Сохранить строковые индексы:
In [204]: si = pd.DataFrame(np.zeros((4, 4)),
.....: columns=list(range(4)),
.....: index=[str(i) for i in range(4)])
.....:
In [205]: si
Out[205]:
0 1 2 3
0 0.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0
2 0.0 0.0 0.0 0.0
3 0.0 0.0 0.0 0.0
In [206]: si.index
Out[206]: Index([u'0', u'1', u'2', u'3'], dtype='object')
In [207]: si.columns
Out[207]: Int64Index([0, 1, 2, 3], dtype='int64')
In [208]: json = si.to_json()
In [209]: sij = pd.read_json(json, convert_axes=False)
In [210]: sij
Out[210]:
0 1 2 3
0 0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
In [211]: sij.index
Out[211]: Index([u'0', u'1', u'2', u'3'], dtype='object')
In [212]: sij.columns
Out[212]: Index([u'0', u'1', u'2', u'3'], dtype='object')
Даты, записанные в наносекундах, должны быть прочитаны обратно в наносекундах:
In [213]: json = dfj2.to_json(date_unit='ns')
# Try to parse timestamps as millseconds -> Won't Work
In [214]: dfju = pd.read_json(json, date_unit='ms')
In [215]: dfju
Out[215]:
A B bools date ints
1356998400000000000 -1.294524 0.413738 True 1356998400000000000 0
1357084800000000000 0.276662 -0.472035 True 1356998400000000000 1
1357171200000000000 -0.013960 -0.362543 True 1356998400000000000 2
1357257600000000000 -0.006154 -0.923061 True 1356998400000000000 3
1357344000000000000 0.895717 0.805244 True 1356998400000000000 4
# Let pandas detect the correct precision
In [216]: dfju = pd.read_json(json)
In [217]: dfju
Out[217]:
A B bools date ints
2013-01-01 -1.294524 0.413738 True 2013-01-01 0
2013-01-02 0.276662 -0.472035 True 2013-01-01 1
2013-01-03 -0.013960 -0.362543 True 2013-01-01 2
2013-01-04 -0.006154 -0.923061 True 2013-01-01 3
2013-01-05 0.895717 0.805244 True 2013-01-01 4
# Or specify that all timestamps are in nanoseconds
In [218]: dfju = pd.read_json(json, date_unit='ns')
In [219]: dfju
Out[219]:
A B bools date ints
2013-01-01 -1.294524 0.413738 True 2013-01-01 0
2013-01-02 0.276662 -0.472035 True 2013-01-01 1
2013-01-03 -0.013960 -0.362543 True 2013-01-01 2
2013-01-04 -0.006154 -0.923061 True 2013-01-01 3
2013-01-05 0.895717 0.805244 True 2013-01-01 4
Параметр Numpy
Примечание
Эта функция поддерживает только числовые данные. Метки индексов и столбцов могут быть нечисловыми, например, строками, датами и т. д.
Если numpy=True передаётся в read_json, будет предпринята попытка определить подходящий тип данных во время десериализации и непосредственного декодирования в массивы numpy, минуя промежуточные объекты Python.
Это может ускорить процесс, если вы десериализуете большое количество числовых данных:
In [220]: randfloats = np.random.uniform(-100, 1000, 10000)
In [221]: randfloats.shape = (1000, 10)
In [222]: dffloats = pd.DataFrame(randfloats, columns=list('ABCDEFGHIJ'))
In [223]: jsonfloats = dffloats.to_json()
In [224]: timeit pd.read_json(jsonfloats) 100 loops, best of 3: 12.2 ms per loop
In [225]: timeit pd.read_json(jsonfloats, numpy=True) 100 loops, best of 3: 7.35 ms per loop
Ускорение менее заметно для меньших наборов данных:
In [226]: jsonfloats = dffloats.head(100).to_json()
In [227]: timeit pd.read_json(jsonfloats) 100 loops, best of 3: 5.72 ms per loop
In [228]: timeit pd.read_json(jsonfloats, numpy=True) 100 loops, best of 3: 4.94 ms per loop
Предупреждение
Прямое декодирование в numpy делает ряд предположений и может завершиться сбоем или произвести неожиданный результат, если эти предположения не выполняются:
- данные являются числовыми.
- данные однородны. Тип данных определяется из первого декодированного значения. Может быть выброшено исключение
ValueErrorили получен неверный результат, если это условие не соблюдается. - метки упорядочены. Метки читаются только из первого контейнера, предполагается, что каждая последующая строка/столбец закодирована в том же порядке. Это должно выполняться, если данные были закодированы с использованием
to_json, но может не выполняться, если JSON получен из другого источника.
Нормализация
Введено в версии 0.13.0.
pandas предоставляет вспомогательную функцию для преобразования словаря или списка словарей в плоскую таблицу.
In [229]: from pandas.io.json import json_normalize
In [230]: data = [{'state': 'Florida',
.....: 'shortname': 'FL',
.....: 'info': {
.....: 'governor': 'Rick Scott'
.....: },
.....: 'counties': [{'name': 'Dade', 'population': 12345},
.....: {'name': 'Broward', 'population': 40000},
.....: {'name': 'Palm Beach', 'population': 60000}]},
.....: {'state': 'Ohio',
.....: 'shortname': 'OH',
.....: 'info': {
.....: 'governor': 'John Kasich'
.....: },
.....: 'counties': [{'name': 'Summit', 'population': 1234},
.....: {'name': 'Cuyahoga', 'population': 1337}]}]
.....:
In [231]: json_normalize(data, 'counties', ['state', 'shortname', ['info', 'governor']])
Out[231]:
name population info.governor state shortname
0 Dade 12345 Rick Scott Florida FL
1 Broward 40000 Rick Scott Florida FL
2 Palm Beach 60000 Rick Scott Florida FL
3 Summit 1234 John Kasich Ohio OH
4 Cuyahoga 1337 John Kasich Ohio OH
JSON в формате с разделителями строк
Введено в версии 0.19.0.
pandas умеет читать и записывать файлы в формате JSON с разделителями строк, что часто используется в обработке данных в системах типа Hadoop или Spark.
In [232]: jsonl = '''
.....: {"a":1,"b":2}
.....: {"a":3,"b":4}
.....: '''
.....:
In [233]: df = pd.read_json(jsonl, lines=True)
In [234]: df
Out[234]:
a b
0 1 2
1 3 4
In [235]: df.to_json(orient='records', lines=True)
Out[235]: u'{"a":1,"b":2}\n{"a":3,"b":4}'
HTML
Чтение содержимого HTML
Предупреждение
Мы настоятельно рекомендуем ознакомиться с особенностями разбора HTML в отношении проблем с парсерами BeautifulSoup4/html5lib/lxml.
Введено в версии 0.12.0.
Функция верхнего уровня read_html() может принимать строку/файл/URL HTML и парсить таблицы HTML в список pandas DataFrame. Давайте рассмотрим несколько примеров.
Примечание
read_html возвращает list DataFrame объектов, даже если в содержимом HTML содержится только одна таблица.
Чтение URL без параметров
In [236]: url = 'http://www.fdic.gov/bank/individual/failed/banklist.html'
In [237]: dfs = pd.read_html(url)
In [238]: dfs
Out[238]:
[ Bank Name City ST CERT \
0 Allied Bank Mulberry AR 91
1 The Woodbury Banking Company Woodbury GA 11297
2 First CornerStone Bank King of Prussia PA 35312
3 Trust Company Bank Memphis TN 9956
4 North Milwaukee State Bank Milwaukee WI 20364
5 Hometown National Bank Longview WA 35156
6 The Bank of Georgia Peachtree City GA 35259
.. ... ... .. ...
540 Hamilton Bank, NA En Espanol Miami FL 24382
541 Sinclair National Bank Gravette AR 34248
542 Superior Bank, FSB Hinsdale IL 32646
543 Malta National Bank Malta OH 6629
544 First Alliance Bank & Trust Co. Manchester NH 34264
545 National State Bank of Metropolis Metropolis IL 3815
546 Bank of Honolulu Honolulu HI 21029
Acquiring Institution Closing Date \
0 Today's Bank September 23, 2016
1 United Bank August 19, 2016
2 First-Citizens Bank & Trust Company May 6, 2016
3 The Bank of Fayette County April 29, 2016
4 First-Citizens Bank & Trust Company March 11, 2016
5 Twin City Bank October 2, 2015
6 Fidelity Bank October 2, 2015
.. ... ...
540 Israel Discount Bank of New York January 11, 2002
541 Delta Trust & Bank September 7, 2001
542 Superior Federal, FSB July 27, 2001
543 North Valley Bank May 3, 2001
544 Southern New Hampshire Bank & Trust February 2, 2001
545 Banterra Bank of Marion December 14, 2000
546 Bank of the Orient October 13, 2000
Updated Date
0 November 17, 2016
1 November 17, 2016
2 September 6, 2016
3 September 6, 2016
4 June 16, 2016
5 April 13, 2016
6 October 24, 2016
.. ...
540 September 21, 2015
541 February 10, 2004
542 August 19, 2014
543 November 18, 2002
544 February 18, 2003
545 March 17, 2005
546 March 17, 2005
[547 rows x 7 columns]]
Примечание
Данные с указанного URL меняются каждую понедельник, поэтому полученные данные выше и ниже могут незначительно отличаться.
Чтение содержимого файла из указанного URL и передача его функции read_html как строки
In [239]: with open(file_path, 'r') as f:
.....: dfs = pd.read_html(f.read())
.....:
In [240]: dfs
Out[240]:
[ Bank Name City ST CERT \
0 Banks of Wisconsin d/b/a Bank of Kenosha Kenosha WI 35386
1 Central Arizona Bank Scottsdale AZ 34527
2 Sunrise Bank Valdosta GA 58185
3 Pisgah Community Bank Asheville NC 58701
4 Douglas County Bank Douglasville GA 21649
5 Parkway Bank Lenoir NC 57158
6 Chipola Community Bank Marianna FL 58034
.. ... ... .. ...
499 Hamilton Bank, NAEn Espanol Miami FL 24382
500 Sinclair National Bank Gravette AR 34248
501 Superior Bank, FSB Hinsdale IL 32646
502 Malta National Bank Malta OH 6629
503 First Alliance Bank & Trust Co. Manchester NH 34264
504 National State Bank of Metropolis Metropolis IL 3815
505 Bank of Honolulu Honolulu HI 21029
Acquiring Institution Closing Date Updated Date
0 North Shore Bank, FSB May 31, 2013 May 31, 2013
1 Western State Bank May 14, 2013 May 20, 2013
2 Synovus Bank May 10, 2013 May 21, 2013
3 Capital Bank, N.A. May 10, 2013 May 14, 2013
4 Hamilton State Bank April 26, 2013 May 16, 2013
5 CertusBank, National Association April 26, 2013 May 17, 2013
6 First Federal Bank of Florida April 19, 2013 May 16, 2013
.. ... ... ...
499 Israel Discount Bank of New York January 11, 2002 June 5, 2012
500 Delta Trust & Bank September 7, 2001 February 10, 2004
501 Superior Federal, FSB July 27, 2001 June 5, 2012
502 North Valley Bank May 3, 2001 November 18, 2002
503 Southern New Hampshire Bank & Trust February 2, 2001 February 18, 2003
504 Banterra Bank of Marion December 14, 2000 March 17, 2005
505 Bank of the Orient October 13, 2000 March 17, 2005
[506 rows x 7 columns]]
Вы также можете передать экземпляр StringIO по своему желанию
In [241]: with open(file_path, 'r') as f:
.....: sio = StringIO(f.read())
.....:
In [242]: dfs = pd.read_html(sio)
In [243]: dfs
Out[243]:
[ Bank Name City ST CERT \
0 Banks of Wisconsin d/b/a Bank of Kenosha Kenosha WI 35386
1 Central Arizona Bank Scottsdale AZ 34527
2 Sunrise Bank Valdosta GA 58185
3 Pisgah Community Bank Asheville NC 58701
4 Douglas County Bank Douglasville GA 21649
5 Parkway Bank Lenoir NC 57158
6 Chipola Community Bank Marianna FL 58034
.. ... ... .. ...
499 Hamilton Bank, NAEn Espanol Miami FL 24382
500 Sinclair National Bank Gravette AR 34248
501 Superior Bank, FSB Hinsdale IL 32646
502 Malta National Bank Malta OH 6629
503 First Alliance Bank & Trust Co. Manchester NH 34264
504 National State Bank of Metropolis Metropolis IL 3815
505 Bank of Honolulu Honolulu HI 21029
Acquiring Institution Closing Date Updated Date
0 North Shore Bank, FSB May 31, 2013 May 31, 2013
1 Western State Bank May 14, 2013 May 20, 2013
2 Synovus Bank May 10, 2013 May 21, 2013
3 Capital Bank, N.A. May 10, 2013 May 14, 2013
4 Hamilton State Bank April 26, 2013 May 16, 2013
5 CertusBank, National Association April 26, 2013 May 17, 2013
6 First Federal Bank of Florida April 19, 2013 May 16, 2013
.. ... ... ...
499 Israel Discount Bank of New York January 11, 2002 June 5, 2012
500 Delta Trust & Bank September 7, 2001 February 10, 2004
501 Superior Federal, FSB July 27, 2001 June 5, 2012
502 North Valley Bank May 3, 2001 November 18, 2002
503 Southern New Hampshire Bank & Trust February 2, 2001 February 18, 2003
504 Banterra Bank of Marion December 14, 2000 March 17, 2005
505 Bank of the Orient October 13, 2000 March 17, 2005
[506 rows x 7 columns]]
Примечание
Следующие примеры не выполняются IPython-интерпретатором, так как наличие большого числа функций, обращение к сети, замедляет сборку документации. Если вы обнаружите ошибку или пример, который не работает, пожалуйста, не стесняйтесь сообщить об этом на странице вопросов на GitHub проекта pandas.
Чтение URL и подбор таблицы, содержащей определённый текст
match = 'Metcalf Bank' df_list = pd.read_html(url, match=match)
Указать строку заголовка (по умолчанию для формирования индекса столбцов используются элементы <th>; если указано, строка заголовка берется из данных за вычетом обработанных заголовков (элементы <th>).
dfs = pd.read_html(url, header=0)
Указать столбец индекса
dfs = pd.read_html(url, index_col=0)
Указать количество строк, которое нужно пропустить
dfs = pd.read_html(url, skiprows=0)
Указать количество строк, которое нужно пропустить, используя список (xrange (только Python 2) также работает)
dfs = pd.read_html(url, skiprows=range(2))
Указать атрибут HTML
dfs1 = pd.read_html(url, attrs={'id': 'table'})
dfs2 = pd.read_html(url, attrs={'class': 'sortable'})
print(np.array_equal(dfs1[0], dfs2[0])) # Should be True
Указать значения, которые должны быть преобразованы в NaN
dfs = pd.read_html(url, na_values=['No Acquirer'])
Введено в версии 0.19.
Указать, нужно ли сохранять набор значений по умолчанию NaN
dfs = pd.read_html(url, keep_default_na=False)
Введено в версии 0.19.
Указать преобразования для столбцов. Это полезно для числовых текстовых данных, имеющих ведущие нули. По умолчанию столбцы, которые являются числовыми, преобразуются в числовые типы, а ведущие нули теряются. Чтобы этого избежать, мы можем преобразовать эти столбцы в строки.
url_mcc = 'https://en.wikipedia.org/wiki/Mobile_country_code'
dfs = pd.read_html(url_mcc, match='Telekom Albania', header=0, converters={'MNC':
str})
Введено в версии 0.19.
Использовать некоторые комбинации из вышеперечисленного
dfs = pd.read_html(url, match='Metcalf Bank', index_col=0)
Чтение пандас to_html вывода (с некоторыми потерями точности чисел с плавающей запятой)
df = pd.DataFrame(randn(2, 2))
s = df.to_html(float_format='{0:.40g}'.format)
dfin = pd.read_html(s, index_col=0)
Бэкенд lxml будет генерировать ошибку при неудачном разборе, если это единственный предоставленный вами парсер (если у вас только один парсер, вы можете предоставить только строку, но считается хорошей практикой передавать список из одной строки, если, например, функция ожидает последовательность строк)
dfs = pd.read_html(url, 'Metcalf Bank', index_col=0, flavor=['lxml'])
или
dfs = pd.read_html(url, 'Metcalf Bank', index_col=0, flavor='lxml')
Однако, если у вас установлены bs4 и html5lib и вы передадите None или ['lxml',
'bs4'], то разбор, скорее всего, пройдет успешно. Обратите внимание, что как только разбор пройдет успешно, функция вернёт результат.
dfs = pd.read_html(url, 'Metcalf Bank', index_col=0, flavor=['lxml', 'bs4'])
Запись в файлы HTML
Объекты DataFrame имеют метод экземпляра to_html, который отображает содержимое DataFrame в виде HTML-таблицы. Аргументы функции такие же, как в методе to_string, описанном выше.
Примечание
Для краткости здесь показаны не все возможные параметры для DataFrame.to_html. Полный набор параметров см. в to_html().
In [244]: df = pd.DataFrame(randn(2, 2))
In [245]: df
Out[245]:
0 1
0 -0.184744 0.496971
1 -0.856240 1.857977
In [246]: print(df.to_html()) # raw html
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.184744</td>
<td>0.496971</td>
</tr>
<tr>
<th>1</th>
<td>-0.856240</td>
<td>1.857977</td>
</tr>
</tbody>
</table>
HTML:
| 0 | 1 | |
|---|---|---|
| 0 | -0.184744 | 0.496971 |
| 1 | -0.856240 | 1.857977 |
Аргумент columns ограничит отображаемые столбцы
In [247]: print(df.to_html(columns=[0]))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.184744</td>
</tr>
<tr>
<th>1</th>
<td>-0.856240</td>
</tr>
</tbody>
</table>
HTML:
| 0 | |
|---|---|
| 0 | -0.184744 |
| 1 | -0.856240 |
float_format принимает Python-вызов для управления точностью значений с плавающей запятой
In [248]: print(df.to_html(float_format='{0:.10f}'.format))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.1847438576</td>
<td>0.4969711327</td>
</tr>
<tr>
<th>1</th>
<td>-0.8562396763</td>
<td>1.8579766508</td>
</tr>
</tbody>
</table>
HTML:
| 0 | 1 | |
|---|---|---|
| 0 | -0.1847438576 | 0.4969711327 |
| 1 | -0.8562396763 | 1.8579766508 |
bold_rows сделает метки строк полужирными по умолчанию, но вы можете это отключить
In [249]: print(df.to_html(bold_rows=False))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>-0.184744</td>
<td>0.496971</td>
</tr>
<tr>
<td>1</td>
<td>-0.856240</td>
<td>1.857977</td>
</tr>
</tbody>
</table>
| 0 | 1 | |
|---|---|---|
| 0 | -0.184744 | 0.496971 |
| 1 | -0.856240 | 1.857977 |
Аргумент classes предоставляет возможность добавления CSS-классов к результирующей HTML-таблице. Обратите внимание, что эти классы добавляются к существующему классу 'dataframe'.
In [250]: print(df.to_html(classes=['awesome_table_class', 'even_more_awesome_class']))
<table border="1" class="dataframe awesome_table_class even_more_awesome_class">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>-0.184744</td>
<td>0.496971</td>
</tr>
<tr>
<th>1</th>
<td>-0.856240</td>
<td>1.857977</td>
</tr>
</tbody>
</table>
Наконец, аргумент escape позволяет управлять тем, будут ли символы “<”, “>” и “&” экранированы в результирующем HTML (по умолчанию это True). Чтобы получить HTML без экранированных символов, передайте escape=False
In [251]: df = pd.DataFrame({'a': list('&<>'), 'b': randn(3)})
Экранировано:
In [252]: print(df.to_html())
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>a</th>
<th>b</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>&</td>
<td>-0.474063</td>
</tr>
<tr>
<th>1</th>
<td><</td>
<td>-0.230305</td>
</tr>
<tr>
<th>2</th>
<td>></td>
<td>-0.400654</td>
</tr>
</tbody>
</table>
| a | b | |
|---|---|---|
| 0 | & | -0.474063 |
| 1 | < | -0.230305 |
| 2 | > | -0.400654 |
Не экранировано:
In [253]: print(df.to_html(escape=False))
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>a</th>
<th>b</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>&</td>
<td>-0.474063</td>
</tr>
<tr>
<th>1</th>
<td><</td>
<td>-0.230305</td>
</tr>
<tr>
<th>2</th>
<td>></td>
<td>-0.400654</td>
</tr>
</tbody>
</table>
| a | b | |
|---|---|---|
| 0 | & | -0.474063 |
| 1 | < | -0.230305 |
| 2 | > | -0.400654 |
Примечание
Некоторые браузеры могут не показывать разницы в отображении двух предыдущих HTML-таблиц.
Файлы Excel
Метод read_excel() может читать файлы Excel 2003 (.xls) и Excel 2007+ (.xlsx) с помощью модуля Python xlrd. Метод экземпляра to_excel() используется для сохранения DataFrame в Excel. В целом семантика аналогична работе с данными csv. См. раздел справочник для некоторых продвинутых стратегий
Чтение файлов Excel
В самом простом случае read_excel принимает путь к файлу Excel, а sheetname указывает лист, который нужно проанализировать.
# Returns a DataFrame
read_excel('path_to_file.xls', sheetname='Sheet1')
ExcelFile класс
Для работы с несколькими листами из одного файла можно использовать класс ExcelFile, который может обернуть файл и передаваться в read_excel. Будет наблюдаться прирост производительности при чтении нескольких листов, так как файл будет считан в память только один раз.
xlsx = pd.ExcelFile('path_to_file.xls)
df = pd.read_excel(xlsx, 'Sheet1')
Класс ExcelFile также может использоваться как менеджер контекста.
with pd.ExcelFile('path_to_file.xls') as xls:
df1 = pd.read_excel(xls, 'Sheet1')
df2 = pd.read_excel(xls, 'Sheet2')
Свойство sheet_names сгенерирует список имён листов в файле.
Основное применение класса ExcelFile — анализ нескольких листов с разными параметрами.
data = {}
# For when Sheet1's format differs from Sheet2
with pd.ExcelFile('path_to_file.xls') as xls:
data['Sheet1'] = pd.read_excel(xls, 'Sheet1', index_col=None, na_values=['NA'])
data['Sheet2'] = pd.read_excel(xls, 'Sheet2', index_col=1)
Обратите внимание, что если для всех листов используются одинаковые параметры анализа, то список имён листов можно просто передать в read_excel без потери производительности.
# using the ExcelFile class
data = {}
with pd.ExcelFile('path_to_file.xls') as xls:
data['Sheet1'] = read_excel(xls, 'Sheet1', index_col=None, na_values=['NA'])
data['Sheet2'] = read_excel(xls, 'Sheet2', index_col=None, na_values=['NA'])
# equivalent using the read_excel function
data = read_excel('path_to_file.xls', ['Sheet1', 'Sheet2'], index_col=None, na_values=['NA'])
Введено в версии 0.12.
ExcelFile был перемещен в пространство имен верхнего уровня.
Введено в версии 0.17.
read_excel может принимать объект ExcelFile в качестве входных данных.
Указание листов
Примечание
Второй аргумент — sheetname, не путать с ExcelFile.sheet_names
Примечание
Атрибут sheet_names объекта ExcelFile предоставляет доступ к списку листов.
- Аргумент
sheetnameпозволяет указать лист или листы для чтения. - Значение по умолчанию для
sheetnameравно 0, что указывает на чтение первого листа. - Передача строки позволяет сослаться на имя конкретного листа в книге.
- Передача целого числа позволяет сослаться на индекс листа. Индексы следуют соглашению Python, начиная с 0.
- Передача списка строк или целых чисел возвращает словарь указанных листов.
- Передача
Noneвозвращает словарь всех доступных листов.
# Returns a DataFrame
read_excel('path_to_file.xls', 'Sheet1', index_col=None, na_values=['NA'])
Использование индекса листа:
# Returns a DataFrame
read_excel('path_to_file.xls', 0, index_col=None, na_values=['NA'])
Использование всех значений по умолчанию:
# Returns a DataFrame
read_excel('path_to_file.xls')
Использование None для получения всех листов:
# Returns a dictionary of DataFrames
read_excel('path_to_file.xls',sheetname=None)
Использование списка для получения нескольких листов:
# Returns the 1st and 4th sheet, as a dictionary of DataFrames.
read_excel('path_to_file.xls',sheetname=['Sheet1',3])
Введено в версии 0.16.
read_excel может читать более одного листа, установив sheetname в список имён листов, список позиций листов или None для чтения всех листов.
Введено в версии 0.13.
Листы можно указывать по индексу или имени листа, используя целое число или строку соответственно.
Чтение MultiIndex
Введено в версии 0.17.
read_excel может читать многоуровневый индекс, передав список столбцов в index_col и список строк в header. Если у index или columns есть сериализованные имена уровней, они также будут считаны при указании строк/столбцов, составляющих уровни.
Например, для чтения многоуровневого индекса без имён:
In [254]: df = pd.DataFrame({'a':[1,2,3,4], 'b':[5,6,7,8]},
.....: index=pd.MultiIndex.from_product([['a','b'],['c','d']]))
.....:
In [255]: df.to_excel('path_to_file.xlsx')
In [256]: df = pd.read_excel('path_to_file.xlsx', index_col=[0,1])
In [257]: df
Out[257]:
a b
a c 1 5
d 2 6
b c 3 7
d 4 8
Если у индекса есть имена уровней, они также будут проанализированы, используя те же параметры.
In [258]: df.index = df.index.set_names(['lvl1', 'lvl2'])
In [259]: df.to_excel('path_to_file.xlsx')
In [260]: df = pd.read_excel('path_to_file.xlsx', index_col=[0,1])
In [261]: df
Out[261]:
a b
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
Если исходный файл содержит как многоуровневый индекс, так и столбцы, списки, указывающие каждый из них, должны быть переданы в index_col и header
In [262]: df.columns = pd.MultiIndex.from_product([['a'],['b', 'd']], names=['c1', 'c2'])
In [263]: df.to_excel('path_to_file.xlsx')
In [264]: df = pd.read_excel('path_to_file.xlsx',
.....: index_col=[0,1], header=[0,1])
.....:
In [265]: df
Out[265]:
c1 a
c2 b d
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
Предупреждение
Файлы Excel, сохранённые в версии 0.16.2 или ранее, имеющие имена индекса, всё ещё смогут быть прочитаны, но аргумент has_index_names должен быть указан в True.
Анализ определённых столбцов
Часто пользователи вставляют столбцы для временных вычислений в Excel, и вам может не потребоваться читать эти столбцы. read_excel принимает ключевое слово parse_cols, чтобы позволить вам указать подмножество столбцов для анализа.
Если parse_cols является целым числом, то оно предполагается как указание последнего столбца для анализа.
read_excel('path_to_file.xls', 'Sheet1', parse_cols=2)
Если parse_cols является списком целых чисел, то он предполагается как список индексов столбцов файла для анализа.
read_excel('path_to_file.xls', 'Sheet1', parse_cols=[0, 2, 3])
Преобразователи ячеек
Можно преобразовать содержимое ячеек Excel с помощью опции converters. Например, для преобразования столбца в булевы значения:
read_excel('path_to_file.xls', 'Sheet1', converters={'MyBools': bool})
Эта опция обрабатывает пропущенные значения и рассматривает исключения в преобразователях как пропущенные данные. Преобразования применяются к каждой ячейке по отдельности, а не к столбцу целиком, поэтому тип данных массива не гарантируется. Например, столбец целых чисел с пропущенными значениями не может быть преобразован в массив с целочисленным типом данных, потому что NaN — строго тип с плавающей запятой. Вы можете вручную замаскировать пропущенные данные, чтобы восстановить целочисленный тип данных:
cfun = lambda x: int(x) if x else -1
read_excel('path_to_file.xls', 'Sheet1', converters={'MyInts': cfun})
Запись файлов Excel
Запись файлов Excel на диск
Для записи объекта DataFrame в лист файла Excel можно использовать метод экземпляра to_excel. Аргументы в основном такие же, как в to_csv, описанном выше, первым аргументом является имя файла Excel, а необязательным вторым аргументом является имя листа, в который должен быть записан DataFrame. Например:
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1')
Файлы с расширением .xls будут записаны с помощью xlwt, а файлы с расширением .xlsx будут записаны с помощью xlsxwriter (если доступно) или openpyxl.
Фрейм DataFrame будет записан таким образом, чтобы имитировать вывод REPL. Отличие от версии 0.12.0 заключается в том, что index_label будет размещён во второй строке вместо первой. Предыдущее поведение можно получить, установив опцию merge_cells в to_excel() на значение False.
df.to_excel('path_to_file.xlsx', index_label='label', merge_cells=False)
Класс Panel также имеет метод to_excel, который записывает каждый DataFrame в Panel в отдельный лист.
Для записи отдельных DataFrame в отдельные листы одного файла Excel можно передать ExcelWriter.
with ExcelWriter('path_to_file.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sheet1')
df2.to_excel(writer, sheet_name='Sheet2')
Примечание
Достижение немного большей производительности при работе с read_excel Внутри Excel все числовые данные хранятся как числа с плавающей запятой. Поскольку это может привести к неожиданному поведению при чтении данных, pandas по умолчанию пытается преобразовать целые числа в числа с плавающей запятой, если при этом не теряется информация (1.0 -->
1). Вы можете передать convert_float=False для отключения этого поведения, что может немного улучшить производительность.
Запись файлов Excel в буфер
Новое в версии 0.17.
Pandas поддерживает запись файлов Excel в объекты, похожие на буфер, такие как StringIO или BytesIO с помощью ExcelWriter.
Новое в версии 0.17.
Добавлена поддержка Openpyxl >= 2.2
# Safe import for either Python 2.x or 3.x
try:
from io import BytesIO
except ImportError:
from cStringIO import StringIO as BytesIO
bio = BytesIO()
# By setting the 'engine' in the ExcelWriter constructor.
writer = ExcelWriter(bio, engine='xlsxwriter')
df.to_excel(writer, sheet_name='Sheet1')
# Save the workbook
writer.save()
# Seek to the beginning and read to copy the workbook to a variable in memory
bio.seek(0)
workbook = bio.read()
Примечание
engine необязательно, но рекомендуется. Установка движка определяет используемую версию книги. Установка engine='xlrd' создаст рабочую книгу в формате Excel 2003 (xls). Использование 'openpyxl' или 'xlsxwriter' создаст рабочую книгу в формате Excel 2007 (xlsx). Если движок не указан, создаётся рабочая книга в формате Excel 2007.
Движки записи Excel
Новое в версии 0.13.
pandas выбирает движок записи Excel двумя способами:
- ключевое слово
engine - расширение файла (через значение по умолчанию, заданное в параметрах конфигурации)
По умолчанию pandas использует XlsxWriter для .xlsx и openpyxl для .xlsm файлов, а xlwt - для .xls файлов. Если установлены несколько движков, можно установить движок по умолчанию, задав параметры конфигурации с помощью параметров конфигурации io.excel.xlsx.writer и io.excel.xls.writer. Pandas будет использовать openpyxl для .xlsx файлов, если Xlsxwriter недоступен.
Для указания нужного движка записи вы можете передать ключевое слово engine в to_excel и ExcelWriter . Доступные встроенные движки:
-
openpyxl: Это включает в себя стабильную поддержку Openpyxl от версии 1.6.1. Однако рекомендуется использовать версии 2.2 и выше, особенно при работе со стилями. xlsxwriterxlwt
# By setting the 'engine' in the DataFrame and Panel 'to_excel()' methods.
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1', engine='xlsxwriter')
# By setting the 'engine' in the ExcelWriter constructor.
writer = ExcelWriter('path_to_file.xlsx', engine='xlsxwriter')
# Or via pandas configuration.
from pandas import options
options.io.excel.xlsx.writer = 'xlsxwriter'
df.to_excel('path_to_file.xlsx', sheet_name='Sheet1')
Буфер обмена
Удобным способом получения данных является использование метода read_clipboard, который получает содержимое буфера обмена и передаёт его методу read_table. Например, можно скопировать следующий текст в буфер обмена (CTRL-C во многих операционных системах):
A B C x 1 4 p y 2 5 q z 3 6 r
Затем импортировать данные непосредственно в DataFrame, вызвав:
clipdf = pd.read_clipboard()
In [266]: clipdf Out[266]: A B C x 1 4 p y 2 5 q z 3 6 r
Метод to_clipboard может использоваться для записи содержимого DataFrame в буфер обмена. После чего содержимое буфера обмена можно вставить в другие приложения (CTRL-V во многих операционных системах). Здесь мы демонстрируем запись DataFrame в буфер обмена и считывание его обратно.
In [267]: df = pd.DataFrame(randn(5,3))
In [268]: df
Out[268]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
In [269]: df.to_clipboard()
In [270]: pd.read_clipboard()
Out[270]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
Мы видим, что получили те же данные, что и ранее записали в буфер обмена.
Примечание
Для использования этих методов вам может потребоваться установить xclip или xsel (с модулями gtk или PyQt4) в Linux.
Запись в двоичный формат
Все объекты pandas оснащены методами to_pickle, которые используют модуль Python cPickle для сохранения структур данных на диск в формате pickle.
In [271]: df
Out[271]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
In [272]: df.to_pickle('foo.pkl')
Функция read_pickle в пространстве имён pandas может использоваться для загрузки любого закодированного объекта pandas (или любого другого закодированного объекта) из файла:
In [273]: pd.read_pickle('foo.pkl')
Out[273]:
0 1 2
0 -0.288267 -0.084905 0.004772
1 1.382989 0.343635 -1.253994
2 -0.124925 0.212244 0.496654
3 0.525417 1.238640 -1.210543
4 -1.175743 -0.172372 -0.734129
Предупреждение
Загрузка закодированных данных из ненадежных источников может быть небезопасной.
Предупреждение
Несколько внутренних рефакторингов, в 0.13 (Рефакторинг Series), и 0.15 (Рефакторинг Index), сохраняют совместимость с файлами pickle, созданными до этих версий. Однако их нужно читать с помощью pd.read_pickle, а не стандартного модуля Python pickle.load. Подробное объяснение можно найти в этой статье.
Примечание
Эти методы ранее были pd.save и pd.load, до версии 0.12.0, и теперь устарели.
msgpack (экспериментальный)
Новое в версии 0.13.0.
Начиная с версии 0.13.0, pandas поддерживает формат msgpack для сериализации объектов. Это лёгкий портативный двоичный формат, похожий на двоичный JSON, который отличается высокой компактностью и хорошей производительностью при записи (сериализации) и чтении (десериализации).
Предупреждение
Это очень новая функция pandas. В будущем мы планируем внести определённые оптимизации в работу с вводом-выводом msgpack данных. Поскольку эта библиотека помечена как ЭКСПЕРИМЕНТАЛЬНАЯ, формат хранения может не быть стабильным до будущей версии.
Из-за изменений формата записи и других проблем:
| Закодировано с | Можно раскодировать с |
|---|---|
| до 0.17 / Python 2 | любая версия |
| до 0.17 / Python 3 | любая версия |
| 0.17 / Python 2 |
|
| 0.17 / Python 3 | >=0.18 / любой Python |
| 0.18 | >= 0.18 |
Чтение (файлов, закодированных более старыми версиями) является обратной совместимой, за исключением файлов, закодированных 0.17 в Python 2, в котором случае их можно раскодировать только в Python 2.
In [274]: df = pd.DataFrame(np.random.rand(5,2),columns=list('AB'))
In [275]: df.to_msgpack('foo.msg')
In [276]: pd.read_msgpack('foo.msg')
Out[276]:
A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106
In [277]: s = pd.Series(np.random.rand(5),index=pd.date_range('20130101',periods=5))
Вы можете передать список объектов, и получите их обратно при десериализации.
In [278]: pd.to_msgpack('foo.msg', df, 'foo', np.array([1,2,3]), s)
In [279]: pd.read_msgpack('foo.msg')
Out[279]:
[ A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106, 'foo', array([1, 2, 3]), 2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64]
Вы можете передать iterator=True для итерации по результатам раскодирования.
In [280]: for o in pd.read_msgpack('foo.msg',iterator=True):
.....: print o
.....:
A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106
foo
[1 2 3]
2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64
Вы можете передать append=True в метод записи для добавления в существующий набор.
In [281]: df.to_msgpack('foo.msg',append=True)
In [282]: pd.read_msgpack('foo.msg')
Out[282]:
[ A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106, 'foo', array([1, 2, 3]), 2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64, A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106]
В отличие от других методов ввода-вывода, to_msgpack доступен как для работы с отдельными объектами, df.to_msgpack(), так и с использованием верхнеуровневой функции pd.to_msgpack(...), где вы можете кодировать произвольные коллекции python-списков, словарей, скаляров, смешивая объекты pandas.
In [283]: pd.to_msgpack('foo2.msg', { 'dict' : [ { 'df' : df }, { 'string' : 'foo' }, { 'scalar' : 1. }, { 's' : s } ] })
In [284]: pd.read_msgpack('foo2.msg')
Out[284]:
{'dict': ({'df': A B
0 0.154336 0.710999
1 0.398096 0.765220
2 0.586749 0.293052
3 0.290293 0.710783
4 0.988593 0.062106},
{'string': 'foo'},
{'scalar': 1.0},
{'s': 2013-01-01 0.690810
2013-01-02 0.235907
2013-01-03 0.712756
2013-01-04 0.119599
2013-01-05 0.023493
Freq: D, dtype: float64})}
API чтения/записи
Msgpack также можно считывать и записывать в строки.
In [285]: df.to_msgpack() Out[285]: '\x84\xa6blocks\x91\x86\xa5dtype\xa7float64\xa8compress\xc0\xa4locs\x86\xa4ndim\x01\xa5dtype\xa5int64\xa8compress\xc0\xa4data\xd8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xa5shape\x91\x02\xa3typ\xa7ndarray\xa5shape\x92\x02\x05\xa6values\xc7P\x00\xa0\xab\xfb6H\xc1\xc3?\x98(oMgz\xd9?\x17\xaed\\\xa5\xc6\xe2?\xdc\xd0\x1bd(\x94\xd2?\xb5\xe8\xf5\x0e\x8d\xa2\xef?\x02D\xebO\x80\xc0\xe6?\x16\xbddQ\xae|\xe8?\x10?Ya[\xc1\xd2?\xa8\xfd\xcf\xa0\xbc\xbe\xe6? Z\xe1\ti\xcc\xaf?\xa5klass\xaaFloatBlock\xa4axes\x92\x86\xa4name\xc0\xa5dtype\xa6object\xa8compress\xc0\xa4data\x92\xc4\x01A\xc4\x01B\xa5klass\xa5Index\xa3typ\xa5index\x86\xa4name\xc0\xa4stop\x05\xa5start\x00\xa4step\x01\xa5klass\xaaRangeIndex\xa3typ\xabrange_index\xa3typ\xadblock_manager\xa5klass\xa9DataFrame'
Кроме того, вы можете конкатенировать строки, чтобы получить список исходных объектов.
In [286]: pd.read_msgpack(df.to_msgpack() + s.to_msgpack()) Out[286]: [ A B 0 0.154336 0.710999 1 0.398096 0.765220 2 0.586749 0.293052 3 0.290293 0.710783 4 0.988593 0.062106, 2013-01-01 0.690810 2013-01-02 0.235907 2013-01-03 0.712756 2013-01-04 0.119599 2013-01-05 0.023493 Freq: D, dtype: float64]
HDF5 (PyTables)
HDFStore – это объект, подобный словарю, который читает и записывает данные pandas в формате HDF5 с высокой производительностью, используя отличную библиотеку PyTables. См. пособие для получения некоторых расширенных стратегий.
Предупреждение
Начиная с версии 0.15.0, pandas требует PyTables >= 3.0.0. Файлы, записанные с предыдущими версиями pandas / PyTables >= 2.3, полностью совместимы (предыдущая минимальная PyTables версия требовала).
Предупреждение
Есть ошибка индексирования PyTables, которая может возникнуть при запросах к хранилищу с использованием индекса. Если вы видите, что возвращается подмножество результатов, обновите PyTables до версии >= 3.2. Предыдущие хранилища необходимо переписать с использованием обновлённой версии.
Предупреждение
Начиная с версии 0.17.0, HDFStore по умолчанию не будет удалять строки с пропускаемыми значениями. Ранее, если все значения (кроме индекса) были отсутствующими, HDFStore не записывал эти строки на диск.
In [287]: store = pd.HDFStore('store.h5')
In [288]: print(store)
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
Empty
Объекты могут быть записаны в файл так же, как добавление пар ключ-значение в словарь:
In [289]: np.random.seed(1234)
In [290]: index = pd.date_range('1/1/2000', periods=8)
In [291]: s = pd.Series(randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [292]: df = pd.DataFrame(randn(8, 3), index=index,
.....: columns=['A', 'B', 'C'])
.....:
In [293]: wp = pd.Panel(randn(2, 5, 4), items=['Item1', 'Item2'],
.....: major_axis=pd.date_range('1/1/2000', periods=5),
.....: minor_axis=['A', 'B', 'C', 'D'])
.....:
# store.put('s', s) is an equivalent method
In [294]: store['s'] = s
In [295]: store['df'] = df
In [296]: store['wp'] = wp
# the type of stored data
In [297]: store.root.wp._v_attrs.pandas_type
Out[297]: 'wide'
In [298]: store
Out[298]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame (shape->[8,3])
/s series (shape->[5])
/wp wide (shape->[2,5,4])
В текущей или последующей сессии Python вы можете получить сохранённые объекты:
# store.get('df') is an equivalent method
In [299]: store['df']
Out[299]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
# dotted (attribute) access provides get as well
In [300]: store.df
Out[300]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
Удаление объекта, указанного ключом
# store.remove('wp') is an equivalent method
In [301]: del store['wp']
In [302]: store
Out[302]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame (shape->[8,3])
/s series (shape->[5])
Закрытие хранилища, менеджер контекста
In [303]: store.close()
In [304]: store
Out[304]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
File is CLOSED
In [305]: store.is_open
Out[305]: False
# Working with, and automatically closing the store with the context
# manager
In [306]: with pd.HDFStore('store.h5') as store:
.....: store.keys()
.....:
API чтения/записи
HDFStore поддерживает верхнеуровневый API с использованием read_hdf для чтения и to_hdf для записи, аналогично тому, как работают read_csv и to_csv. (новая функция в 0.11.0)
In [307]: df_tl = pd.DataFrame(dict(A=list(range(5)), B=list(range(5))))
In [308]: df_tl.to_hdf('store_tl.h5','table',append=True)
In [309]: pd.read_hdf('store_tl.h5', 'table', where = ['index>2'])
Out[309]:
A B
3 3 3
4 4 4
Начиная с версии 0.17.0, HDFStore больше не будет удалять строки с пропускаемыми значениями по умолчанию. Это поведение можно включить, установив dropna=True.
In [310]: df_with_missing = pd.DataFrame({'col1':[0, np.nan, 2],
.....: 'col2':[1, np.nan, np.nan]})
.....:
In [311]: df_with_missing
Out[311]:
col1 col2
0 0.0 1.0
1 NaN NaN
2 2.0 NaN
In [312]: df_with_missing.to_hdf('file.h5', 'df_with_missing',
.....: format = 'table', mode='w')
.....:
In [313]: pd.read_hdf('file.h5', 'df_with_missing')
Out[313]:
col1 col2
0 0.0 1.0
1 NaN NaN
2 2.0 NaN
In [314]: df_with_missing.to_hdf('file.h5', 'df_with_missing',
.....: format = 'table', mode='w', dropna=True)
.....:
In [315]: pd.read_hdf('file.h5', 'df_with_missing')
Out[315]:
col1 col2
0 0.0 1.0
2 2.0 NaN
Это также верно для большой оси Panel:
In [316]: matrix = [[[np.nan, np.nan, np.nan],[1,np.nan,np.nan]],
.....: [[np.nan, np.nan, np.nan], [np.nan,5,6]],
.....: [[np.nan, np.nan, np.nan],[np.nan,3,np.nan]]]
.....:
In [317]: panel_with_major_axis_all_missing = pd.Panel(matrix,
.....: items=['Item1', 'Item2','Item3'],
.....: major_axis=[1,2],
.....: minor_axis=['A', 'B', 'C'])
.....:
In [318]: panel_with_major_axis_all_missing
Out[318]:
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 2 (major_axis) x 3 (minor_axis)
Items axis: Item1 to Item3
Major_axis axis: 1 to 2
Minor_axis axis: A to C
In [319]: panel_with_major_axis_all_missing.to_hdf('file.h5', 'panel',
.....: dropna = True,
.....: format='table',
.....: mode='w')
.....:
In [320]: reloaded = pd.read_hdf('file.h5', 'panel')
In [321]: reloaded
Out[321]:
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 1 (major_axis) x 3 (minor_axis)
Items axis: Item1 to Item3
Major_axis axis: 2 to 2
Minor_axis axis: A to C
Формат фиксированной длины
Примечание
Ранее, до версии 0.13.0, использовался формат Storer.
Приведенные выше примеры демонстрируют сохранение данных с использованием put, которые записывают HDF5 в PyTables в формате фиксированного массива, называемом форматом fixed. Эти типы хранилищ не могут быть расширены после записи (хотя вы можете их просто удалить и перезаписать). Кроме того, они не являются запрошиваемыми; они должны быть извлечены целиком. Они также не поддерживают фреймы данных с не уникальными именами столбцов. Форматы хранилищ fixed обеспечивают очень быструю запись и немного более быстрый доступ к чтению по сравнению с хранилищами table. Этот формат используется по умолчанию при использовании put или to_hdf или format='fixed' или format='f'.
Предупреждение
Формат fixed вызовет TypeError, если вы попытаетесь получить доступ к нему с помощью where.
pd.DataFrame(randn(10,2)).to_hdf('test_fixed.h5','df')
pd.read_hdf('test_fixed.h5','df',where='index>5')
TypeError: cannot pass a where specification when reading a fixed format.
this store must be selected in its entirety
Таблица
HDFStore поддерживает другой формат на диске — table формат. Концептуально, table имеет структуру, очень похожую на фрейм данных DataFrame, с строками и столбцами. К table можно добавлять данные в одном или других сеансах. Кроме того, поддерживаются операции удаления и запроса данных. Этот формат задается format='table' или format='t' для append или put или to_hdf.
Введено в версии 0.13.
Этот формат также может быть задан как опция pd.set_option('io.hdf.default_format','table') для включения put/append/to_hdf по умолчанию, сохраняя данные в формате table.
In [322]: store = pd.HDFStore('store.h5')
In [323]: df1 = df[0:4]
In [324]: df2 = df[4:]
# append data (creates a table automatically)
In [325]: store.append('df', df1)
In [326]: store.append('df', df2)
In [327]: store
Out[327]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
# select the entire object
In [328]: store.select('df')
Out[328]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
# the type of stored data
In [329]: store.root.df._v_attrs.pandas_type
Out[329]: 'frame_table'
Примечание
Также можно создать table, передав format='table' или format='t' в операцию put.
Иерархические ключи
Ключи к хранилищу могут быть заданы в виде строки. Они могут быть заданы в формате иерархического пути (например, foo/bar/bah), который сгенерирует иерархию подхранилищ (или Groups в терминологии PyTables). Ключи могут быть указаны без ведущего «/» и всегда являются абсолютными (например, «foo» относится к «/foo»). Операции удаления могут удалить все в подхранилище и НИЖЕ, поэтому будьте осторожны.
In [330]: store.put('foo/bar/bah', df)
In [331]: store.append('food/orange', df)
In [332]: store.append('food/apple', df)
In [333]: store
Out[333]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/foo/bar/bah frame (shape->[8,3])
/food/apple frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/food/orange frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
# a list of keys are returned
In [334]: store.keys()
Out[334]: ['/df', '/food/apple', '/food/orange', '/foo/bar/bah']
# remove all nodes under this level
In [335]: store.remove('food')
In [336]: store
Out[336]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/foo/bar/bah frame (shape->[8,3])
Предупреждение
Иерархические ключи не могут быть получены как точки доступа (атрибуты), как описано выше для элементов, сохраненных в корневом узле.
In [8]: store.foo.bar.bah AttributeError: 'HDFStore' object has no attribute 'foo' # you can directly access the actual PyTables node but using the root node In [9]: store.root.foo.bar.bah Out[9]: /foo/bar/bah (Group) '' children := ['block0_items' (Array), 'block0_values' (Array), 'axis0' (Array), 'axis1' (Array)]
Вместо этого используйте явные ключи на основе строк.
In [337]: store['foo/bar/bah']
Out[337]:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
Типы данных
Сохранение данных смешанных типов в таблице
Поддерживается хранение данных смешанного типа. Строки хранятся как фиксированной ширины, используя максимальный размер добавляемого столбца. Попытки добавить более длинные строки приведут к исключению ValueError.
Передача min_itemsize={`values`: size} в качестве параметра к append установит больший минимум для столбцов строк. Хранение floats,
strings, ints, bools, datetime64 в настоящее время поддерживается. Для столбцов строк передача nan_rep = 'nan' к append изменит представление NaN на диске (которое преобразуется в/из np.nan). По умолчанию это nan.
In [338]: df_mixed = pd.DataFrame({ 'A' : randn(8),
.....: 'B' : randn(8),
.....: 'C' : np.array(randn(8),dtype='float32'),
.....: 'string' :'string',
.....: 'int' : 1,
.....: 'bool' : True,
.....: 'datetime64' : pd.Timestamp('20010102')},
.....: index=list(range(8)))
.....:
In [339]: df_mixed.ix[3:5,['A', 'B', 'string', 'datetime64']] = np.nan
In [340]: store.append('df_mixed', df_mixed, min_itemsize = {'values': 50})
In [341]: df_mixed1 = store.select('df_mixed')
In [342]: df_mixed1
Out[342]:
A B C bool datetime64 int string
0 0.704721 -1.152659 -0.430096 True 2001-01-02 1 string
1 -0.785435 0.631979 0.767369 True 2001-01-02 1 string
2 0.462060 0.039513 0.984920 True 2001-01-02 1 string
3 NaN NaN 0.270836 True NaT 1 NaN
4 NaN NaN 1.391986 True NaT 1 NaN
5 NaN NaN 0.079842 True NaT 1 NaN
6 2.007843 0.152631 -0.399965 True 2001-01-02 1 string
7 0.226963 0.164530 -1.027851 True 2001-01-02 1 string
In [343]: df_mixed1.get_dtype_counts()
Out[343]:
bool 1
datetime64[ns] 1
float32 1
float64 2
int64 1
object 1
dtype: int64
# we have provided a minimum string column size
In [344]: store.root.df_mixed.table
Out[344]:
/df_mixed/table (Table(8,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(2,), dflt=0.0, pos=1),
"values_block_1": Float32Col(shape=(1,), dflt=0.0, pos=2),
"values_block_2": Int64Col(shape=(1,), dflt=0, pos=3),
"values_block_3": Int64Col(shape=(1,), dflt=0, pos=4),
"values_block_4": BoolCol(shape=(1,), dflt=False, pos=5),
"values_block_5": StringCol(itemsize=50, shape=(1,), dflt='', pos=6)}
byteorder := 'little'
chunkshape := (689,)
autoindex := True
colindexes := {
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
Хранение фреймов данных с многоуровневыми индексами
Хранение фреймов данных с многоуровневыми индексами в виде таблиц очень похоже на хранение/выбор фреймов данных с однородными индексами.
In [345]: index = pd.MultiIndex(levels=[['foo', 'bar', 'baz', 'qux'],
.....: ['one', 'two', 'three']],
.....: labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3, 3],
.....: [0, 1, 2, 0, 1, 1, 2, 0, 1, 2]],
.....: names=['foo', 'bar'])
.....:
In [346]: df_mi = pd.DataFrame(np.random.randn(10, 3), index=index,
.....: columns=['A', 'B', 'C'])
.....:
In [347]: df_mi
Out[347]:
A B C
foo bar
foo one -0.584718 0.816594 -0.081947
two -0.344766 0.528288 -1.068989
three -0.511881 0.291205 0.566534
bar one 0.503592 0.285296 0.484288
two 1.363482 -0.781105 -0.468018
baz two 1.224574 -1.281108 0.875476
three -1.710715 -0.450765 0.749164
qux one -0.203933 -0.182175 0.680656
two -1.818499 0.047072 0.394844
three -0.248432 -0.617707 -0.682884
In [348]: store.append('df_mi',df_mi)
In [349]: store.select('df_mi')
Out[349]:
A B C
foo bar
foo one -0.584718 0.816594 -0.081947
two -0.344766 0.528288 -1.068989
three -0.511881 0.291205 0.566534
bar one 0.503592 0.285296 0.484288
two 1.363482 -0.781105 -0.468018
baz two 1.224574 -1.281108 0.875476
three -1.710715 -0.450765 0.749164
qux one -0.203933 -0.182175 0.680656
two -1.818499 0.047072 0.394844
three -0.248432 -0.617707 -0.682884
# the levels are automatically included as data columns
In [350]: store.select('df_mi', 'foo=bar')
Out[350]:
A B C
foo bar
bar one 0.503592 0.285296 0.484288
two 1.363482 -0.781105 -0.468018
Запросы
Запрос таблицы
Предупреждение
Возможности запросов существенно изменились начиная с 0.13.0. Запросы предыдущих версий принимаются (с сообщением DeprecationWarning, если он не является строковым).
select и delete операции имеют необязательный критерий, который может быть задан для выбора/удаления только подмножества данных. Это позволяет иметь очень большую таблицу на диске и извлекать только часть данных.
Запрос задается с использованием класса Term внутри, как булево выражение.
-
indexиcolumnsподдерживаются как индексаторы DataFrame. -
major_axis,minor_axis, иitemsподдерживаются как индексаторы Panel. - если
data_columnsзаданы, они могут быть использованы как дополнительные индексаторы.
Допустимые операторы сравнения:
=, ==, !=, >, >=, <, <=
Допустимые булевы выражения комбинируются с:
-
|: или -
&: и -
(и): для группировки
Эти правила аналогичны тому, как булевы выражения используются в pandas для индексирования.
Примечание
-
=будет автоматически расширено до оператора сравнения== -
~— это оператор не, но он может использоваться только в очень ограниченных случаях. - Если передается список/кортеж выражений, они будут объединены с помощью
&
Следующие выражения являются допустимыми:
'index>=date'"columns=['A', 'D']""columns in ['A', 'D']"'columns=A''columns==A'"~(columns=['A','B'])"'index>df.index[3] & string="bar"''(index>df.index[3] & index<=df.index[6]) | string="bar"'"ts>=Timestamp('2012-02-01')""major_axis>=20130101"
indexers находятся в левой части подвыражения:
columns, major_axis, ts
Правая часть подвыражения (после оператора сравнения) может быть:
- функциями, которые будут вычислены, например,
Timestamp('2012-02-01') - строками, например,
"bar" - данными типа даты, например,
20130101, или"20130101" - списками, например,
"['A','B']" - переменными, определенными в локальном пространстве имен, например,
date
Примечание
Не рекомендуется передавать строку в запрос, интерполируя ее в выражение запроса. Просто присвойте интересующую строку переменной и используйте эту переменную в выражении. Например, сделайте так
string = "HolyMoly'"
store.select('df', 'index == string')
вместо этого
string = "HolyMoly'"
store.select('df', 'index == %s' % string)
Последний вариант не сработает и вызовет SyntaxError. Обратите внимание, что в переменной string есть одинарная кавычка, за которой следует двойная кавычка.
Если вам необходимо выполнить интерполяцию, используйте спецификатор формата '%r'
store.select('df', 'index == %r' % string)
что приводит к цитированию string.
Вот некоторые примеры:
In [351]: dfq = pd.DataFrame(randn(10,4),columns=list('ABCD'),index=pd.date_range('20130101',periods=10))
In [352]: store.append('dfq',dfq,format='table',data_columns=True)
Используйте булевы выражения с вычислением функций в строке.
In [353]: store.select('dfq',"index>pd.Timestamp('20130104') & columns=['A', 'B']")
Out[353]:
A B
2013-01-05 1.210384 0.797435
2013-01-06 -0.850346 1.176812
2013-01-07 0.984188 -0.121728
2013-01-08 0.796595 -0.474021
2013-01-09 -0.804834 -2.123620
2013-01-10 0.334198 0.536784
Используйте ссылку на столбец в строке.
In [354]: store.select('dfq',where="A>0 or C>0")
Out[354]:
A B C D
2013-01-01 0.436258 -1.703013 0.393711 -0.479324
2013-01-02 -0.299016 0.694103 0.678630 0.239556
2013-01-03 0.151227 0.816127 1.893534 0.639633
2013-01-04 -0.962029 -2.085266 1.930247 -1.735349
2013-01-05 1.210384 0.797435 -0.379811 0.702562
2013-01-07 0.984188 -0.121728 2.365769 0.496143
2013-01-08 0.796595 -0.474021 -0.056696 1.357797
2013-01-10 0.334198 0.536784 -0.743830 -0.320204
Работает и с Panel.
In [355]: store.append('wp',wp)
In [356]: store
Out[356]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/foo/bar/bah frame (shape->[8,3])
/wp wide_table (typ->appendable,nrows->20,ncols->2,indexers->[major_axis,minor_axis])
In [357]: store.select('wp', "major_axis>pd.Timestamp('20000102') & minor_axis=['A', 'B']")
Out[357]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 3 (major_axis) x 2 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to B
Ключевое слово columns может быть передано для выбора списка столбцов, которые должны быть возвращены, что эквивалентно передаче 'columns=list_of_columns_to_filter':
In [358]: store.select('df', "columns=['A', 'B']")
Out[358]:
A B
2000-01-01 0.887163 0.859588
2000-01-02 0.015696 -2.242685
2000-01-03 0.991946 0.953324
2000-01-04 -0.334077 0.002118
2000-01-05 0.289092 1.321158
2000-01-06 -0.202646 -0.655969
2000-01-07 0.553439 1.318152
2000-01-08 0.675554 -1.817027
Параметры start и stop могут быть заданы для ограничения всего пространства поиска. Это относится к общему количеству строк в таблице.
# this is effectively what the storage of a Panel looks like
In [359]: wp.to_frame()
Out[359]:
Item1 Item2
major minor
2000-01-01 A 1.058969 0.215269
B -0.397840 0.841009
C 0.337438 -1.445810
D 1.047579 -1.401973
2000-01-02 A 1.045938 -0.100918
B 0.863717 -0.548242
C -0.122092 -0.144620
... ... ...
2000-01-04 B 0.036142 0.307969
C -2.074978 -0.208499
D 0.247792 1.033801
2000-01-05 A -0.897157 -2.400454
B -0.136795 2.030604
C 0.018289 -1.142631
D 0.755414 0.211883
[20 rows x 2 columns]
# limiting the search
In [360]: store.select('wp',"major_axis>20000102 & minor_axis=['A','B']",
.....: start=0, stop=10)
.....:
Out[360]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 1 (major_axis) x 2 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-03 00:00:00
Minor_axis axis: A to B
Примечание
select вызовет ValueError, если в выражении запроса есть ссылка на неизвестную переменную. Обычно это означает, что вы пытаетесь выбрать столбец, который не является столбцом данных.
select вызовет SyntaxError, если выражение запроса не является допустимым.
Использование timedelta64[ns]
Введено в версии 0.13.
Начиная с версии 0.13.0, вы можете хранить и запрашивать значения типа timedelta64[ns]. Термы могут быть указаны в формате: <float>(<unit>), где число с плавающей точкой может быть со знаком (и дробным), а единица может быть D,s,ms,us,ns для timedelta. Вот пример:
In [361]: from datetime import timedelta
In [362]: dftd = pd.DataFrame(dict(A = pd.Timestamp('20130101'), B = [ pd.Timestamp('20130101') + timedelta(days=i,seconds=10) for i in range(10) ]))
In [363]: dftd['C'] = dftd['A']-dftd['B']
In [364]: dftd
Out[364]:
A B C
0 2013-01-01 2013-01-01 00:00:10 -1 days +23:59:50
1 2013-01-01 2013-01-02 00:00:10 -2 days +23:59:50
2 2013-01-01 2013-01-03 00:00:10 -3 days +23:59:50
3 2013-01-01 2013-01-04 00:00:10 -4 days +23:59:50
4 2013-01-01 2013-01-05 00:00:10 -5 days +23:59:50
5 2013-01-01 2013-01-06 00:00:10 -6 days +23:59:50
6 2013-01-01 2013-01-07 00:00:10 -7 days +23:59:50
7 2013-01-01 2013-01-08 00:00:10 -8 days +23:59:50
8 2013-01-01 2013-01-09 00:00:10 -9 days +23:59:50
9 2013-01-01 2013-01-10 00:00:10 -10 days +23:59:50
In [365]: store.append('dftd',dftd,data_columns=True)
In [366]: store.select('dftd',"C<'-3.5D'")
Out[366]:
A B C
4 2013-01-01 2013-01-05 00:00:10 -5 days +23:59:50
5 2013-01-01 2013-01-06 00:00:10 -6 days +23:59:50
6 2013-01-01 2013-01-07 00:00:10 -7 days +23:59:50
7 2013-01-01 2013-01-08 00:00:10 -8 days +23:59:50
8 2013-01-01 2013-01-09 00:00:10 -9 days +23:59:50
9 2013-01-01 2013-01-10 00:00:10 -10 days +23:59:50
Индексирование
Вы можете создать/изменить индекс для таблицы с помощью create_table_index после того, как данные уже находятся в таблице (после операции append/put). Создание индекса таблицы высоко рекомендуется. Это значительно ускорит ваши запросы, когда вы используете select с индексируемым измерением как where.
Примечание
Индексы автоматически создаются (начиная с 0.10.1) для индексируемых и любых столбцов данных, которые вы указываете. Это поведение можно отключить, передав index=False в append.
# we have automagically already created an index (in the first section)
In [367]: i = store.root.df.table.cols.index.index
In [368]: i.optlevel, i.kind
Out[368]: (6, 'medium')
# change an index by passing new parameters
In [369]: store.create_table_index('df', optlevel=9, kind='full')
In [370]: i = store.root.df.table.cols.index.index
In [371]: i.optlevel, i.kind
Out[371]: (9, 'full')
Часто при добавлении большого количества данных в хранилище полезно отключить создание индекса для каждого добавления, а затем пересоздать его в конце.
In [372]: df_1 = pd.DataFrame(randn(10,2),columns=list('AB'))
In [373]: df_2 = pd.DataFrame(randn(10,2),columns=list('AB'))
In [374]: st = pd.HDFStore('appends.h5',mode='w')
In [375]: st.append('df', df_1, data_columns=['B'], index=False)
In [376]: st.append('df', df_2, data_columns=['B'], index=False)
In [377]: st.get_storer('df').table
Out[377]:
/df/table (Table(20,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(1,), dflt=0.0, pos=1),
"B": Float64Col(shape=(), dflt=0.0, pos=2)}
byteorder := 'little'
chunkshape := (2730,)
Затем создайте индекс по окончании добавления данных.
In [378]: st.create_table_index('df', columns=['B'], optlevel=9, kind='full')
In [379]: st.get_storer('df').table
Out[379]:
/df/table (Table(20,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(1,), dflt=0.0, pos=1),
"B": Float64Col(shape=(), dflt=0.0, pos=2)}
byteorder := 'little'
chunkshape := (2730,)
autoindex := True
colindexes := {
"B": Index(9, full, shuffle, zlib(1)).is_csi=True}
In [380]: st.close()
См. здесь, как создать полностью отсортированный индекс (CSI) в существующем хранилище.
Запрос через столбцы данных
Вы можете указать (и проиндексировать) определенные столбцы, для которых вы хотите иметь возможность выполнять запросы (кроме столбцов indexable, которые вы всегда можете запросить). Например, предположим, что вы хотите выполнить эту распространенную операцию на диске и вернуть только фрейм, который соответствует этому запросу. Вы можете указать data_columns = True для принудительного назначения всех столбцов в качестве столбцов данных.
In [381]: df_dc = df.copy()
In [382]: df_dc['string'] = 'foo'
In [383]: df_dc.ix[4:6,'string'] = np.nan
In [384]: df_dc.ix[7:9,'string'] = 'bar'
In [385]: df_dc['string2'] = 'cool'
In [386]: df_dc.ix[1:3,['B','C']] = 1.0
In [387]: df_dc
Out[387]:
A B C string string2
2000-01-01 0.887163 0.859588 -0.636524 foo cool
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
2000-01-05 0.289092 1.321158 -1.546906 NaN cool
2000-01-06 -0.202646 -0.655969 0.193421 NaN cool
2000-01-07 0.553439 1.318152 -0.469305 foo cool
2000-01-08 0.675554 -1.817027 -0.183109 bar cool
# on-disk operations
In [388]: store.append('df_dc', df_dc, data_columns = ['B', 'C', 'string', 'string2'])
In [389]: store.select('df_dc', [ pd.Term('B>0') ])
Out[389]:
A B C string string2
2000-01-01 0.887163 0.859588 -0.636524 foo cool
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
2000-01-05 0.289092 1.321158 -1.546906 NaN cool
2000-01-07 0.553439 1.318152 -0.469305 foo cool
# getting creative
In [390]: store.select('df_dc', 'B > 0 & C > 0 & string == foo')
Out[390]:
A B C string string2
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
# this is in-memory version of this type of selection
In [391]: df_dc[(df_dc.B > 0) & (df_dc.C > 0) & (df_dc.string == 'foo')]
Out[391]:
A B C string string2
2000-01-02 0.015696 1.000000 1.000000 foo cool
2000-01-03 0.991946 1.000000 1.000000 foo cool
2000-01-04 -0.334077 0.002118 0.405453 foo cool
# we have automagically created this index and the B/C/string/string2
# columns are stored separately as ``PyTables`` columns
In [392]: store.root.df_dc.table
Out[392]:
/df_dc/table (Table(8,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": Float64Col(shape=(1,), dflt=0.0, pos=1),
"B": Float64Col(shape=(), dflt=0.0, pos=2),
"C": Float64Col(shape=(), dflt=0.0, pos=3),
"string": StringCol(itemsize=3, shape=(), dflt='', pos=4),
"string2": StringCol(itemsize=4, shape=(), dflt='', pos=5)}
byteorder := 'little'
chunkshape := (1680,)
autoindex := True
colindexes := {
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"C": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"B": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"string2": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"string": Index(6, medium, shuffle, zlib(1)).is_csi=False}
Существует некоторое снижение производительности, если сделать много столбцов столбцами данных, поэтому это зависит от пользователя, чтобы назначить эти столбцы. Кроме того, вы не можете изменить столбцы данных (ни индексируемые) после первой операции append/put (конечно, вы можете просто считать данные и создать новую таблицу!).
Итератор
Начиная с 0.11.0, вы можете передать iterator=True или chunksize=number_in_a_chunk в select и select_as_multiple для возврата итератора по результатам. По умолчанию возвращается 50 000 строк в блоке.
In [393]: for df in store.select('df', chunksize=3):
.....: print(df)
.....:
A B C
2000-01-01 0.887163 0.859588 -0.636524
2000-01-02 0.015696 -2.242685 1.150036
2000-01-03 0.991946 0.953324 -2.021255
A B C
2000-01-04 -0.334077 0.002118 0.405453
2000-01-05 0.289092 1.321158 -1.546906
2000-01-06 -0.202646 -0.655969 0.193421
A B C
2000-01-07 0.553439 1.318152 -0.469305
2000-01-08 0.675554 -1.817027 -0.183109
Примечание
Новая в версии 0.12.0.
Вы также можете использовать итератор с read_hdf, который откроет, а затем автоматически закроет хранилище по завершении итерации.
for df in pd.read_hdf('store.h5','df', chunksize=3):
print(df)
Обратите внимание, что параметр chunksize относится к строкам источника. Таким образом, если вы выполняете запрос, то chunksize разделит общее количество строк в таблице и применённый запрос, вернув итератор по потенциально неравномерным блокам.
Вот рецепт для генерации запроса и использования его для создания равномерных блоков возврата.
In [394]: dfeq = pd.DataFrame({'number': np.arange(1,11)})
In [395]: dfeq
Out[395]:
number
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
In [396]: store.append('dfeq', dfeq, data_columns=['number'])
In [397]: def chunks(l, n):
.....: return [l[i:i+n] for i in range(0, len(l), n)]
.....:
In [398]: evens = [2,4,6,8,10]
In [399]: coordinates = store.select_as_coordinates('dfeq','number=evens')
In [400]: for c in chunks(coordinates, 2):
.....: print store.select('dfeq',where=c)
.....:
number
1 2
3 4
number
5 6
7 8
number
9 10
Расширенные запросы
Выбор одного столбца
Для получения одного индексируемого или данных столбца используйте метод select_column. Это позволит, например, очень быстро получить индекс. Эти методы возвращают Series результата, индексированного по номеру строки. Эти методы не принимают селектор where.
In [401]: store.select_column('df_dc', 'index')
Out[401]:
0 2000-01-01
1 2000-01-02
2 2000-01-03
3 2000-01-04
4 2000-01-05
5 2000-01-06
6 2000-01-07
7 2000-01-08
Name: index, dtype: datetime64[ns]
In [402]: store.select_column('df_dc', 'string')
Out[402]:
0 foo
1 foo
2 foo
3 foo
4 NaN
5 NaN
6 foo
7 bar
Name: string, dtype: object
Выбор координат
Иногда вам нужно получить координаты (т.е. позиции индексов) вашего запроса. Это возвращает Int64Index результирующих позиций. Эти координаты также можно передать в последующие операции where.
In [403]: df_coord = pd.DataFrame(np.random.randn(1000,2),index=pd.date_range('20000101',periods=1000))
In [404]: store.append('df_coord',df_coord)
In [405]: c = store.select_as_coordinates('df_coord','index>20020101')
In [406]: c.summary()
Out[406]: u'Int64Index: 268 entries, 732 to 999'
In [407]: store.select('df_coord',where=c)
Out[407]:
0 1
2002-01-02 -0.178266 -0.064638
2002-01-03 -1.204956 -3.880898
2002-01-04 0.974470 0.415160
2002-01-05 1.751967 0.485011
2002-01-06 -0.170894 0.748870
2002-01-07 0.629793 0.811053
2002-01-08 2.133776 0.238459
... ... ...
2002-09-20 -0.181434 0.612399
2002-09-21 -0.763324 -0.354962
2002-09-22 -0.261776 0.812126
2002-09-23 0.482615 -0.886512
2002-09-24 -0.037757 -0.562953
2002-09-25 0.897706 0.383232
2002-09-26 -1.324806 1.139269
[268 rows x 2 columns]
Выбор с помощью маски where
Иногда ваш запрос может включать создание списка строк для выбора. Обычно этот список mask будет результирующим index из операции индексирования. В этом примере выбираются месяцы из datetimeindex, которые равны 5.
In [408]: df_mask = pd.DataFrame(np.random.randn(1000,2),index=pd.date_range('20000101',periods=1000))
In [409]: store.append('df_mask',df_mask)
In [410]: c = store.select_column('df_mask','index')
In [411]: where = c[pd.DatetimeIndex(c).month==5].index
In [412]: store.select('df_mask',where=where)
Out[412]:
0 1
2000-05-01 -1.006245 -0.616759
2000-05-02 0.218940 0.717838
2000-05-03 0.013333 1.348060
2000-05-04 0.662176 -1.050645
2000-05-05 -1.034870 -0.243242
2000-05-06 -0.753366 -1.454329
2000-05-07 -1.022920 -0.476989
... ... ...
2002-05-25 -0.509090 -0.389376
2002-05-26 0.150674 1.164337
2002-05-27 -0.332944 0.115181
2002-05-28 -1.048127 -0.605733
2002-05-29 1.418754 -0.442835
2002-05-30 -0.433200 0.835001
2002-05-31 -1.041278 1.401811
[93 rows x 2 columns]
Объект хранилища
Если вы хотите проверить сохраненный объект, получите его через get_storer. Вы можете использовать это программно, например, для получения количества строк в объекте.
In [413]: store.get_storer('df_dc').nrows
Out[413]: 8
Запросы к нескольким таблицам
В версии 0.10.1 появились методы append_to_multiple и select_as_multiple, которые могут выполнять операции добавления/выбора из нескольких таблиц одновременно. Идея заключается в том, чтобы иметь одну таблицу (назовем ее таблицей-селектором), в которой индексируются большинство/все столбцы, и выполнять запросы к ней. Другие таблицы — это таблицы данных с индексом, соответствующим индексу таблицы-селектора. Затем вы можете выполнить очень быстрый запрос к таблице-селектору и получить много данных. Этот метод похож на работу с очень широкой таблицей, но позволяет выполнять более эффективные запросы.
Метод append_to_multiple разбивает заданную отдельную таблицу DataFrame на несколько таблиц в соответствии с d, словарем, сопоставляющим имена таблиц со списком «столбцов», которые вы хотите в этой таблице. Если в качестве значения для ключа None используется не список, в эту таблицу будут включены оставшиеся не указанные столбцы из DataFrame. Аргумент selector определяет, какая таблица является таблицей-селектором (из которой вы можете выполнять запросы). Аргумент selector удалит строки из входного DataFrame, чтобы гарантировать синхронизацию таблиц. Это означает, что если вся строка для одной из записываемых таблиц является np.NaN, эта строка будет удалена из всех таблиц.
Если dropna равно False, ПОЛЬЗОВАТЕЛЬ НЕСЁТ ОТВЕТСТВЕННОСТЬ ЗА СИНХРОНИЗАЦИЮ ТАБЛИЦ. Помните, что строки, полностью np.Nan, не записываются в HDFStore. Поэтому, если вы вызовете dropna=False, у некоторых таблиц может быть больше строк, чем у других, и в этом случае select_as_multiple может не сработать или вернуть неожиданные результаты.
In [414]: df_mt = pd.DataFrame(randn(8, 6), index=pd.date_range('1/1/2000', periods=8),
.....: columns=['A', 'B', 'C', 'D', 'E', 'F'])
.....:
In [415]: df_mt['foo'] = 'bar'
In [416]: df_mt.ix[1, ('A', 'B')] = np.nan
# you can also create the tables individually
In [417]: store.append_to_multiple({'df1_mt': ['A', 'B'], 'df2_mt': None },
.....: df_mt, selector='df1_mt')
.....:
In [418]: store
Out[418]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df1_mt frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A,B])
/df2_mt frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index])
/df_coord frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_dc frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index],dc->[B,C,string,string2])
/df_mask frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfeq frame_table (typ->appendable,nrows->10,ncols->1,indexers->[index],dc->[number])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/dftd frame_table (typ->appendable,nrows->10,ncols->3,indexers->[index],dc->[A,B,C])
/foo/bar/bah frame (shape->[8,3])
/wp wide_table (typ->appendable,nrows->20,ncols->2,indexers->[major_axis,minor_axis])
# individual tables were created
In [419]: store.select('df1_mt')
Out[419]:
A B
2000-01-01 0.714697 0.318215
2000-01-02 NaN NaN
2000-01-03 -0.086919 0.416905
2000-01-04 0.489131 -0.253340
2000-01-05 -0.382952 -0.397373
2000-01-06 0.538116 0.226388
2000-01-07 -2.073479 -0.115926
2000-01-08 -0.695400 0.402493
In [420]: store.select('df2_mt')
Out[420]:
C D E F foo
2000-01-01 0.607460 0.790907 0.852225 0.096696 bar
2000-01-02 0.811031 -0.356817 1.047085 0.664705 bar
2000-01-03 -0.764381 -0.287229 -0.089351 -1.035115 bar
2000-01-04 -1.948100 -0.116556 0.800597 -0.796154 bar
2000-01-05 -0.717627 0.156995 -0.344718 -0.171208 bar
2000-01-06 1.541729 0.205256 1.998065 0.953591 bar
2000-01-07 1.391070 0.303013 1.093347 -0.101000 bar
2000-01-08 -1.507639 0.089575 0.658822 -1.037627 bar
# as a multiple
In [421]: store.select_as_multiple(['df1_mt', 'df2_mt'], where=['A>0', 'B>0'],
.....: selector = 'df1_mt')
.....:
Out[421]:
A B C D E F foo
2000-01-01 0.714697 0.318215 0.607460 0.790907 0.852225 0.096696 bar
2000-01-06 0.538116 0.226388 1.541729 0.205256 1.998065 0.953591 bar
Удаление из таблицы
Вы можете выборочно удалить из таблицы, указав where. При удалении строк важно понимать, что PyTables удаляет строки, стирает их, а затем перемещает последующие данные. Таким образом, удаление может быть очень дорогостоящей операцией в зависимости от расположения ваших данных. Это особенно верно для объектов более высокой размерности (Panel и Panel4D). Для достижения оптимальной производительности стоит сделать так, чтобы удаляемый вами размерность была первой в indexables.
Данные упорядочены (на диске) в соответствии с indexables. Вот простой пример. Вы храните данные типа панелей с датами в major_axis и идентификаторами в minor_axis. Данные затем переплетаются следующим образом:
- date_1 - id_1 - id_2 - . - id_n
- date_2 - id_1 - . - id_n
Должно быть ясно, что операция удаления по major_axis будет довольно быстрой, так как один блок удаляется, а затем перемещаются последующие данные. С другой стороны, операция удаления по minor_axis будет очень дорогостоящей. В этом случае было бы почти наверняка быстрее переписать таблицу, используя where, который выбирает все, кроме отсутствующих данных.
# returns the number of rows deleted
In [422]: store.remove('wp', 'major_axis>20000102' )
Out[422]: 12
In [423]: store.select('wp')
Out[423]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 2 (major_axis) x 4 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-02 00:00:00
Minor_axis axis: A to D
Предупреждение
Обратите внимание, что HDF5 НЕ ВОЗВРАЩАЕТ ПРОСТРАНСТВО в файлах h5 автоматически. Таким образом, многократное удаление (или удаление узлов) и повторное добавление БУДЕТ ТЕНДЕНЦИЮ УВЕЛИЧИВАТЬ РАЗМЕР ФАЙЛА.
Чтобы переупаковать и очистить файл, используйте ptrepack
Примечания и замечания
Сжатие
PyTables позволяет сжимать хранимые данные. Это относится ко всем видам хранилищ, а не только к таблицам.
- Передайте
complevel=intдля уровня сжатия (1-9, где 0 — отсутствие сжатия, по умолчанию) - Передайте
complib=libгде lib — любая изzlib, bzip2, lzo, bloscдля той библиотеки сжатия, которую вы предпочитаете.
HDFStore будет использовать схему сжатия на основе файла, если не указаны альтернативные опции complib или complevel. blosc обеспечивает очень быстрое сжатие и является наиболее часто используемым мною. Обратите внимание, что lzo и bzip2 могут быть не установлены (в Python) по умолчанию.
Сжатие для всех объектов в файле
store_compressed = pd.HDFStore('store_compressed.h5', complevel=9, complib='blosc')
Или сжатие в реальном времени (это относится только к таблицам). Вы можете отключить сжатие файла для конкретной таблицы, передав complevel=0
store.append('df', df, complib='zlib', complevel=5)
ptrepack
PyTables обеспечивает лучшую производительность записи, когда таблицы сжимаются после записи, а не при включении сжатия в самом начале. Вы можете использовать предоставленную утилиту PyTables ptrepack. Кроме того, ptrepack может изменить уровни сжатия после факта.
ptrepack --chunkshape=auto --propindexes --complevel=9 --complib=blosc in.h5 out.h5
Кроме того, ptrepack in.h5 out.h5 переупакует файл, чтобы вы могли повторно использовать ранее удаленное пространство. В качестве альтернативы, можно просто удалить файл и записать его заново или использовать метод copy.
Ограничения
Предупреждение
HDFStore не потокобезопасен для записи. Подлежащая PyTables библиотека поддерживает только одновременные чтения (через потоки или процессы). Если вам нужны чтение и запись одновременно, вам необходимо сериализовать эти операции в одном потоке в одном процессе. В противном случае вы повредите данные. См. (GH2397) для получения дополнительной информации.
- Если вы используете блокировки для управления доступом к записи между несколькими процессами, вам может потребоваться использовать
fsync()перед освобождением блокировок записи. Для удобства вы можете использоватьstore.flush(fsync=True)для выполнения этой задачи за вас. - После создания
table, его элементы (Panel) / столбцы (DataFrame) фиксированы; можно добавлять только точно такие же столбцы. - Помните, что часовые пояса (например,
pytz.timezone('US/Eastern')) не обязательно одинаковы для разных версий библиотек часовых поясов. Поэтому, если данные локализованы в определенном часовом поясе в HDFStore с одной версией библиотеки часовых поясов, а затем эти данные обновляются с помощью другой версии, данные будут преобразованы в UTC, так как эти часовые пояса не считаются эквивалентными. Используйте либо одну и ту же версию библиотеки часовых поясов, либоtz_convertс обновленным определением часового пояса.
Предупреждение
PyTables отобразит NaturalNameWarning если имя столбца нельзя использовать в качестве селектора атрибута. Природные идентификаторы содержат только буквы, цифры и символы подчеркивания и не могут начинаться с цифры. Другие идентификаторы нельзя использовать в where и вообще нежелательны.
Типы данных
HDFStore будет сопоставлять тип object с PyTables базовым типом. Это означает, что следующие типы работают:
| Тип | Представляет пропущенные значения |
|---|---|
floating : float64, float32, float16
| np.nan |
integer : int64, int32, int8, uint64,uint32, uint8
| |
| boolean | |
datetime64[ns] | NaT |
timedelta64[ns] | NaT |
| categorical : см. раздел ниже | |
object : strings
| np.nan |
Столбцы типа unicode не поддерживаются и БУДУТ ВЫЗЫВАТЬ ОШИБКУ.
Данные категорий
Новая в версии 0.15.2.
Запись данных в HDFStore, содержащие тип category, была реализована в версии 0.15.2. Запросы работают так же, как если бы это был массив объектов. Однако данные с типом category хранятся более эффективно.
In [424]: dfcat = pd.DataFrame({ 'A' : pd.Series(list('aabbcdba')).astype('category'),
.....: 'B' : np.random.randn(8) })
.....:
In [425]: dfcat
Out[425]:
A B
0 a 0.603273
1 a 0.262554
2 b -0.979586
3 b 2.132387
4 c 0.892485
5 d 1.996474
6 b 0.231425
7 a 0.980070
In [426]: dfcat.dtypes
Out[426]:
A category
B float64
dtype: object
In [427]: cstore = pd.HDFStore('cats.h5', mode='w')
In [428]: cstore.append('dfcat', dfcat, format='table', data_columns=['A'])
In [429]: result = cstore.select('dfcat', where="A in ['b','c']")
In [430]: result
Out[430]:
A B
2 b -0.979586
3 b 2.132387
4 c 0.892485
6 b 0.231425
In [431]: result.dtypes
Out[431]:
A category
B float64
dtype: object
Предупреждение
Формат Categorical читается предыдущими версиями pandas (< 0.15.2), но данные будут извлечены как целочисленный столбец (например, codes). Однако, данные типа categories могут быть извлечены, но требуют от пользователя выбора вручную с использованием явного метапути.
Данные хранятся так:
In [432]: cstore
Out[432]:
<class 'pandas.io.pytables.HDFStore'>
File path: cats.h5
/dfcat frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A])
/dfcat/meta/A/meta series_table (typ->appendable,nrows->4,ncols->1,indexers->[index],dc->[values])
# to get the categories
In [433]: cstore.select('dfcat/meta/A/meta')
Out[433]:
0 a
1 b
2 c
3 d
dtype: object
Столбцы строк
min_itemsize
Реализация HDFStore использует фиксированную ширину столбца (itemsize) для строковых столбцов. Размер строки столбца рассчитывается как максимальная длина данных (для данного столбца), передаваемых в HDFStore, при первом добавлении. При последующих добавлениях могут возникнуть строки для столбца, больше, чем вмещает столбец. В этом случае будет возбуждено исключение (иначе могло бы произойти неявное усечение этих столбцов, что приведёт к потере информации). В будущем мы можем ослабить это ограничение и разрешить указанное пользователем усечение.
Передайте min_itemsize при первом создании таблицы, чтобы заранее указать минимальную длину конкретного строкового столбца. min_itemsize может быть целым числом или словарем, сопоставляющим имя столбца с целым числом. Вы можете передать values в качестве ключа, чтобы применить min_itemsize ко всем индексируемым или данным_столбцам.
Начиная с версии 0.11.0, передача словаря min_itemsize приведет к автоматическому созданию всех переданных столбцов как данных_столбцов.
Примечание
Если вы не передаёте data_columns, то min_itemsize будет максимальной длиной любой переданной строки.
In [434]: dfs = pd.DataFrame(dict(A = 'foo', B = 'bar'),index=list(range(5)))
In [435]: dfs
Out[435]:
A B
0 foo bar
1 foo bar
2 foo bar
3 foo bar
4 foo bar
# A and B have a size of 30
In [436]: store.append('dfs', dfs, min_itemsize = 30)
In [437]: store.get_storer('dfs').table
Out[437]:
/dfs/table (Table(5,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": StringCol(itemsize=30, shape=(2,), dflt='', pos=1)}
byteorder := 'little'
chunkshape := (963,)
autoindex := True
colindexes := {
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
# A is created as a data_column with a size of 30
# B is size is calculated
In [438]: store.append('dfs2', dfs, min_itemsize = { 'A' : 30 })
In [439]: store.get_storer('dfs2').table
Out[439]:
/dfs2/table (Table(5,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": StringCol(itemsize=3, shape=(1,), dflt='', pos=1),
"A": StringCol(itemsize=30, shape=(), dflt='', pos=2)}
byteorder := 'little'
chunkshape := (1598,)
autoindex := True
colindexes := {
"A": Index(6, medium, shuffle, zlib(1)).is_csi=False,
"index": Index(6, medium, shuffle, zlib(1)).is_csi=False}
nan_rep
Строковые столбцы будут сериализовать np.nan (отсутствующее значение) со строковым представлением nan_rep. По умолчанию это строковое значение nan. Вы можете случайно преобразовать фактическое значение nan в отсутствующее значение.
In [440]: dfss = pd.DataFrame(dict(A = ['foo','bar','nan']))
In [441]: dfss
Out[441]:
A
0 foo
1 bar
2 nan
In [442]: store.append('dfss', dfss)
In [443]: store.select('dfss')
Out[443]:
A
0 foo
1 bar
2 NaN
# here you need to specify a different nan rep
In [444]: store.append('dfss2', dfss, nan_rep='_nan_')
In [445]: store.select('dfss2')
Out[445]:
A
0 foo
1 bar
2 nan
Внешняя совместимость
HDFStore записывает объекты формата table в определенных форматах, подходящих для создания без потерь раундов в объекты pandas. Для внешней совместимости HDFStore может читать таблицы формата PyTables.
Можно записать объект HDFStore, который легко импортируется в R с помощью библиотеки rhdf5 (Веб-сайт пакета). Создайте хранилище табличного формата так:
In [446]: np.random.seed(1)
In [447]: df_for_r = pd.DataFrame({"first": np.random.rand(100),
.....: "second": np.random.rand(100),
.....: "class": np.random.randint(0, 2, (100,))},
.....: index=range(100))
.....:
In [448]: df_for_r.head()
Out[448]:
class first second
0 0 0.417022 0.326645
1 0 0.720324 0.527058
2 1 0.000114 0.885942
3 1 0.302333 0.357270
4 1 0.146756 0.908535
In [449]: store_export = pd.HDFStore('export.h5')
In [450]: store_export.append('df_for_r', df_for_r, data_columns=df_dc.columns)
In [451]: store_export
Out[451]:
<class 'pandas.io.pytables.HDFStore'>
File path: export.h5
/df_for_r frame_table (typ->appendable,nrows->100,ncols->3,indexers->[index])
В R этот файл можно прочитать в объект data.frame с использованием библиотеки rhdf5. Следующая примерная функция считывает соответствующие имена столбцов и значения данных из значений и собирает их в data.frame.
# Load values and column names for all datasets from corresponding nodes and
# insert them into one data.frame object.
library(rhdf5)
loadhdf5data <- function(h5File) {
listing <- h5ls(h5File)
# Find all data nodes, values are stored in *_values and corresponding column
# titles in *_items
data_nodes <- grep("_values", listing$name)
name_nodes <- grep("_items", listing$name)
data_paths = paste(listing$group[data_nodes], listing$name[data_nodes], sep = "/")
name_paths = paste(listing$group[name_nodes], listing$name[name_nodes], sep = "/")
columns = list()
for (idx in seq(data_paths)) {
# NOTE: matrices returned by h5read have to be transposed to to obtain
# required Fortran order!
data <- data.frame(t(h5read(h5File, data_paths[idx])))
names <- t(h5read(h5File, name_paths[idx]))
entry <- data.frame(data)
colnames(entry) <- names
columns <- append(columns, entry)
}
data <- data.frame(columns)
return(data)
}
Теперь вы можете импортировать DataFrame в R:
> data = loadhdf5data("transfer.hdf5")
> head(data)
first second class
1 0.4170220047 0.3266449 0
2 0.7203244934 0.5270581 0
3 0.0001143748 0.8859421 1
4 0.3023325726 0.3572698 1
5 0.1467558908 0.9085352 1
6 0.0923385948 0.6233601 1
Примечание
Функция R перечисляет все содержимое файла HDF5 и собирает объект data.frame из всех сопоставляемых узлов. Поэтому используйте это только в качестве отправной точки, если вы сохранили несколько объектов DataFrame в один файл HDF5.
Обратная совместимость
0.10.1 HDFStore может считывать таблицы, созданные в предыдущей версии pandas, однако запросы, использующие предыдущую (недокументированную) методологию, не поддерживаются. HDFStore выдаст предупреждение, если вы попытаетесь использовать файл в старом формате. Вы должны прочитать весь файл и записать его в новом формате, используя метод copy, чтобы воспользоваться обновлениями. Атрибут группы pandas_version содержит информацию о версии. copy принимает несколько параметров, см. строку документации.
# a legacy store
In [452]: legacy_store = pd.HDFStore(legacy_file_path,'r')
In [453]: legacy_store
Out[453]:
<class 'pandas.io.pytables.HDFStore'>
File path: /home/joris/scipy/pandas/doc/source/_static/legacy_0.10.h5
/a series (shape->[30])
/b frame (shape->[30,4])
/df1_mixed frame_table [0.10.0] (typ->appendable,nrows->30,ncols->11,indexers->[index])
/foo/bar wide (shape->[3,30,4])
/p1_mixed wide_table [0.10.0] (typ->appendable,nrows->120,ncols->9,indexers->[major_axis,minor_axis])
/p4d_mixed ndim_table [0.10.0] (typ->appendable,nrows->360,ncols->9,indexers->[items,major_axis,minor_axis])
# copy (and return the new handle)
In [454]: new_store = legacy_store.copy('store_new.h5')
In [455]: new_store
Out[455]:
<class 'pandas.io.pytables.HDFStore'>
File path: store_new.h5
/a series (shape->[30])
/b frame (shape->[30,4])
/df1_mixed frame_table (typ->appendable,nrows->30,ncols->11,indexers->[index])
/foo/bar wide (shape->[3,30,4])
/p1_mixed wide_table (typ->appendable,nrows->120,ncols->9,indexers->[major_axis,minor_axis])
/p4d_mixed wide_table (typ->appendable,nrows->360,ncols->9,indexers->[items,major_axis,minor_axis])
In [456]: new_store.close()
Производительность
-
Формат
tablesимеет штраф за производительность записи по сравнению с хранилищамиfixed. Преимущество заключается в возможности добавлять/удалять и искать (потенциально очень большие объемы данных). Время записи обычно больше, чем в обычных хранилищах. Время поиска может быть довольно быстрым, особенно на индексированной оси. - Вы можете передать
chunksize=<int>вappend, указав размер блока записи (по умолчанию 50000). Это значительно снизит использование памяти при записи. - Вы можете передать
expectedrows=<int>в первыйappend, чтобы установить ОБЩЕЕ ожидаемое количество строк, котороеPyTablesожидает. Это оптимизирует производительность чтения/записи. - В таблицы можно записывать дубликаты строк, но они отфильтровываются при выборке (при этом выбираются последние элементы; таким образом, таблица уникальна по парам «главный-дополнительный»).
- Возбудится исключение
PerformanceWarning, если вы пытаетесь сохранить типы, которые будут сериализованы PyTables (а не хранятся как собственные типы). См. здесь для получения дополнительной информации и некоторых решений.
Экспериментально
HDFStore поддерживает хранение Panel4D.
In [457]: p4d = pd.Panel4D({ 'l1' : wp })
In [458]: p4d
Out[458]:
<class 'pandas.core.panelnd.Panel4D'>
Dimensions: 1 (labels) x 2 (items) x 5 (major_axis) x 4 (minor_axis)
Labels axis: l1 to l1
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D
In [459]: store.append('p4d', p4d)
In [460]: store
Out[460]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df1_mt frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A,B])
/df2_mt frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index])
/df_coord frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_dc frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index],dc->[B,C,string,string2])
/df_mask frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfeq frame_table (typ->appendable,nrows->10,ncols->1,indexers->[index],dc->[number])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/dfs frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index])
/dfs2 frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index],dc->[A])
/dfss frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dfss2 frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dftd frame_table (typ->appendable,nrows->10,ncols->3,indexers->[index],dc->[A,B,C])
/foo/bar/bah frame (shape->[8,3])
/p4d wide_table (typ->appendable,nrows->40,ncols->1,indexers->[items,major_axis,minor_axis])
/wp wide_table (typ->appendable,nrows->8,ncols->2,indexers->[major_axis,minor_axis])
Эти значения по умолчанию индексируют три оси items, major_axis,
minor_axis. В AppendableTable можно настроить другую схему индексирования при первом добавлении в зависимости от того, как вы хотите хранить данные. Передайте ключевое слово axes со списком измерений (в настоящее время должно быть ровно на 1 меньше, чем общее количество измерений объекта). Это нельзя изменить после создания таблицы.
In [461]: store.append('p4d2', p4d, axes=['labels', 'major_axis', 'minor_axis'])
In [462]: store
Out[462]:
<class 'pandas.io.pytables.HDFStore'>
File path: store.h5
/df frame_table (typ->appendable,nrows->8,ncols->3,indexers->[index])
/df1_mt frame_table (typ->appendable,nrows->8,ncols->2,indexers->[index],dc->[A,B])
/df2_mt frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index])
/df_coord frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_dc frame_table (typ->appendable,nrows->8,ncols->5,indexers->[index],dc->[B,C,string,string2])
/df_mask frame_table (typ->appendable,nrows->1000,ncols->2,indexers->[index])
/df_mi frame_table (typ->appendable_multi,nrows->10,ncols->5,indexers->[index],dc->[bar,foo])
/df_mixed frame_table (typ->appendable,nrows->8,ncols->7,indexers->[index])
/dfeq frame_table (typ->appendable,nrows->10,ncols->1,indexers->[index],dc->[number])
/dfq frame_table (typ->appendable,nrows->10,ncols->4,indexers->[index],dc->[A,B,C,D])
/dfs frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index])
/dfs2 frame_table (typ->appendable,nrows->5,ncols->2,indexers->[index],dc->[A])
/dfss frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dfss2 frame_table (typ->appendable,nrows->3,ncols->1,indexers->[index])
/dftd frame_table (typ->appendable,nrows->10,ncols->3,indexers->[index],dc->[A,B,C])
/foo/bar/bah frame (shape->[8,3])
/p4d wide_table (typ->appendable,nrows->40,ncols->1,indexers->[items,major_axis,minor_axis])
/p4d2 wide_table (typ->appendable,nrows->20,ncols->2,indexers->[labels,major_axis,minor_axis])
/wp wide_table (typ->appendable,nrows->8,ncols->2,indexers->[major_axis,minor_axis])
In [463]: store.select('p4d2', [ pd.Term('labels=l1'), pd.Term('items=Item1'), pd.Term('minor_axis=A_big_strings') ])
Out[463]:
<class 'pandas.core.panelnd.Panel4D'>
Dimensions: 0 (labels) x 1 (items) x 0 (major_axis) x 0 (minor_axis)
Labels axis: None
Items axis: Item1 to Item1
Major_axis axis: None
Minor_axis axis: None
Запросы SQL
Модуль pandas.io.sql предоставляет набор обёртки запросов для облегчения извлечения данных и уменьшения зависимости от API конкретной СУБД. Абстракция базы данных предоставляется SQLAlchemy, если она установлена. Кроме того, вам понадобится библиотека драйвера для вашей базы данных. Примеры таких драйверов — psycopg2 для PostgreSQL или pymysql для MySQL. Для SQLite это включено в стандартной библиотеке Python по умолчанию. Вы можете найти обзор поддерживаемых драйверов для каждого диалекта SQL в документации SQLAlchemy.
Новое в версии 0.14.0.
Если SQLAlchemy не установлен, предлагается резервное решение только для sqlite (и для mysql для обратной совместимости, но это устарело и будет удалено в будущей версии). Этот режим требует адаптера Python для базы данных, который соответствует Python DB-API.
См. также некоторые примеры кулинарной книги для некоторых расширенных стратегий.
Основные функции:
read_sql_table(table_name, con[, schema, ...]) | Чтение таблицы базы данных SQL в DataFrame. |
read_sql_query(sql, con[, index_col, ...]) | Чтение запроса SQL в DataFrame. |
read_sql(sql, con[, index_col, ...]) | Чтение запроса SQL или таблицы базы данных в DataFrame. |
DataFrame.to_sql(name, con[, flavor, ...]) | Запись записей, хранящихся в DataFrame, в базу данных SQL. |
Примечание
Функция read_sql() — это удобная обёртка вокруг read_sql_table() и read_sql_query() (и для обратной совместимости) и будет делегировать конкретной функции в зависимости от предоставленного ввода (имя таблицы базы данных или запрос SQL). Имена таблиц не нужно заключать в кавычки, если они содержат специальные символы.
В следующем примере используется движок базы данных SQL SQlite. Вы можете использовать временную базу данных SQLite, где данные хранятся в «памяти».
Для подключения с помощью SQLAlchemy используйте функцию create_engine() для создания объекта движка из URI базы данных. Вам нужно создавать движок только один раз на базу данных, к которой вы подключаетесь. Для получения дополнительной информации о create_engine() и формате URI см. примеры ниже и документацию SQLAlchemy.
In [464]: from sqlalchemy import create_engine
# Create your engine.
In [465]: engine = create_engine('sqlite:///:memory:')
Если вы хотите управлять собственными подключениями, вы можете передать их вместо этого:
with engine.connect() as conn, conn.begin():
data = pd.read_sql_table('data', conn)
Запись DataFrame
Предполагая, что следующие данные содержатся в DataFrame data, мы можем вставить их в базу данных с помощью to_sql().
| id | Дата | Столбец_1 | Столбец_2 | Столбец_3 |
|---|---|---|---|---|
| 26 | 2012-10-18 | X | 25.7 | True |
| 42 | 2012-10-19 | Y | -12.4 | False |
| 63 | 2012-10-20 | Z | 5.73 | True |
In [466]: data.to_sql('data', engine)
В некоторых базах данных запись больших DataFrame может привести к ошибкам из-за превышения ограничений размера пакетов. Этого можно избежать, установив параметр chunksize при вызове to_sql. Например, следующая запись data в базу данных осуществляется группами по 1000 строк за раз:
In [467]: data.to_sql('data_chunked', engine, chunksize=1000)
Типы данных SQL
to_sql() попытается сопоставить ваши данные с соответствующим типом данных SQL на основе типа данных данных. Когда у вас есть столбцы типа object, pandas попытается определить тип данных.
Вы всегда можете переопределить тип по умолчанию, указав желаемый SQL-тип любого из столбцов, используя аргумент dtype. Этот аргумент требует словарь, сопоставляющий имена столбцов с типами SQLAlchemy (или строки для режима обратной совместимости sqlite3). Например, для использования типа sqlalchemy String вместо типа по умолчанию Text для столбцов типа строка:
In [468]: from sqlalchemy.types import String
In [469]: data.to_sql('data_dtype', engine, dtype={'Col_1': String})
Примечание
Из-за ограниченной поддержки timedelta в различных вариантах баз данных столбцы с типом timedelta64 будут записываться в базу данных как целочисленные значения в наносекундах, и будет выведено предупреждение.
Примечание
Столбцы типа category будут преобразованы в плотное представление, как вы получите с np.asarray(categorical) (например, для строковых категорий это даст массив строк). Из-за этого при повторном чтении таблицы базы данных категориальные данные не генерируются.
Чтение таблиц
read_sql_table() будет читать таблицу базы данных, заданную именем таблицы и, необязательно, подмножеством столбцов для чтения.
Примечание
Для использования read_sql_table(), необходимо установить дополнительную зависимость SQLAlchemy.
In [470]: pd.read_sql_table('data', engine)
Out[470]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 X 27.50 True
1 1 42 2010-10-19 Y -12.50 False
2 2 63 2010-10-20 Z 5.73 True
Вы также можете указать имя столбца в качестве индекса DataFrame и указать подмножество столбцов для чтения.
In [471]: pd.read_sql_table('data', engine, index_col='id')
Out[471]:
index Date Col_1 Col_2 Col_3
id
26 0 2010-10-18 X 27.50 True
42 1 2010-10-19 Y -12.50 False
63 2 2010-10-20 Z 5.73 True
In [472]: pd.read_sql_table('data', engine, columns=['Col_1', 'Col_2'])
Out[472]:
Col_1 Col_2
0 X 27.50
1 Y -12.50
2 Z 5.73
И вы можете явно заставить столбцы анализироваться как даты:
In [473]: pd.read_sql_table('data', engine, parse_dates=['Date'])
Out[473]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 X 27.50 True
1 1 42 2010-10-19 Y -12.50 False
2 2 63 2010-10-20 Z 5.73 True
При необходимости вы можете явно указать строку формата или словарь аргументов для передачи в pandas.to_datetime():
pd.read_sql_table('data', engine, parse_dates={'Date': '%Y-%m-%d'})
pd.read_sql_table('data', engine, parse_dates={'Date': {'format': '%Y-%m-%d %H:%M:%S'}})
Вы можете проверить, существует ли таблица, используя has_table()
Поддержка схем
Введено в версии 0.15.0.
Чтение и запись в различные схемы поддерживаются с помощью ключевого слова schema в функциях read_sql_table() и to_sql(). Однако обратите внимание, что это зависит от типа базы данных (sqlite не имеет схем). Например:
df.to_sql('table', engine, schema='other_schema')
pd.read_sql_table('table', engine, schema='other_schema')
Запросы
Вы можете выполнять запросы с использованием простого SQL в функции read_sql_query(). В этом случае вы должны использовать вариант SQL, соответствующий вашей базе данных. При использовании SQLAlchemy вы также можете передать конструкции языка выражений SQLAlchemy, которые не зависят от базы данных.
In [474]: pd.read_sql_query('SELECT * FROM data', engine)
Out[474]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 00:00:00.000000 X 27.50 1
1 1 42 2010-10-19 00:00:00.000000 Y -12.50 0
2 2 63 2010-10-20 00:00:00.000000 Z 5.73 1
Конечно, вы можете указать более «сложный» запрос.
In [475]: pd.read_sql_query("SELECT id, Col_1, Col_2 FROM data WHERE id = 42;", engine)
Out[475]:
id Col_1 Col_2
0 42 Y -12.5
Функция read_sql_query() поддерживает аргумент chunksize. Если это значение задано, будет возвращён итератор, проходящий по частям результата запроса:
In [476]: df = pd.DataFrame(np.random.randn(20, 3), columns=list('abc'))
In [477]: df.to_sql('data_chunks', engine, index=False)
In [478]: for chunk in pd.read_sql_query("SELECT * FROM data_chunks", engine, chunksize=5):
.....: print(chunk)
.....:
a b c
0 0.280665 -0.073113 1.160339
1 0.369493 1.904659 1.111057
2 0.659050 -1.627438 0.602319
3 0.420282 0.810952 1.044442
4 -0.400878 0.824006 -0.562305
a b c
0 1.954878 -1.331952 -1.760689
1 -1.650721 -0.890556 -1.119115
2 1.956079 -0.326499 -1.342676
3 1.114383 -0.586524 -1.236853
4 0.875839 0.623362 -0.434957
a b c
0 1.407540 0.129102 1.616950
1 0.502741 1.558806 0.109403
2 -1.219744 2.449369 -0.545774
3 -0.198838 -0.700399 -0.203394
4 0.242669 0.201830 0.661020
a b c
0 1.792158 -0.120465 -1.233121
1 -1.182318 -0.665755 -1.674196
2 0.825030 -0.498214 -0.310985
3 -0.001891 -1.396620 -0.861316
4 0.674712 0.618539 -0.443172
Вы также можете выполнить обычный запрос без создания DataFrame с помощью execute(). Это полезно для запросов, которые не возвращают значения, таких как INSERT. Это функционально эквивалентно вызову execute объекта движка SQLAlchemy или объекта соединения db. Опять же, вы должны использовать вариант синтаксиса SQL, соответствующий вашей базе данных.
from pandas.io import sql
sql.execute('SELECT * FROM table_name', engine)
sql.execute('INSERT INTO table_name VALUES(?, ?, ?)', engine, params=[('id', 1, 12.2, True)])
Примеры подключения к движку
Для подключения с помощью SQLAlchemy используйте функцию create_engine() для создания объекта движка из URI базы данных. Вам нужно создавать движок только один раз на базу данных, к которой вы подключаетесь.
from sqlalchemy import create_engine
engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')
engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')
engine = create_engine('oracle://scott:tiger@127.0.0.1:1521/sidname')
engine = create_engine('mssql+pyodbc://mydsn')
# sqlite://<nohostname>/<path>
# where <path> is relative:
engine = create_engine('sqlite:///foo.db')
# or absolute, starting with a slash:
engine = create_engine('sqlite:////absolute/path/to/foo.db')
Для получения дополнительной информации см. примеры в документации SQLAlchemy по документации
Расширенные запросы SQLAlchemy
Вы можете использовать конструкции SQLAlchemy для описания запроса.
Используйте sqlalchemy.text() для указания параметров запроса нейтральным для бэкэнда способом
In [479]: import sqlalchemy as sa
In [480]: pd.read_sql(sa.text('SELECT * FROM data where Col_1=:col1'), engine, params={'col1': 'X'})
Out[480]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 00:00:00.000000 X 27.5 1
Если у вас есть описание базы данных с помощью SQLAlchemy, вы можете выразить условия WHERE с помощью выражений SQLAlchemy
In [481]: metadata = sa.MetaData()
In [482]: data_table = sa.Table('data', metadata,
.....: sa.Column('index', sa.Integer),
.....: sa.Column('Date', sa.DateTime),
.....: sa.Column('Col_1', sa.String),
.....: sa.Column('Col_2', sa.Float),
.....: sa.Column('Col_3', sa.Boolean),
.....: )
.....:
In [483]: pd.read_sql(sa.select([data_table]).where(data_table.c.Col_3 == True), engine)
Out[483]:
index Date Col_1 Col_2 Col_3
0 0 2010-10-18 X 27.50 True
1 2 2010-10-20 Z 5.73 True
Вы можете комбинировать выражения SQLAlchemy с параметрами, переданными в read_sql(), используя sqlalchemy.bindparam()
In [484]: import datetime as dt
In [485]: expr = sa.select([data_table]).where(data_table.c.Date > sa.bindparam('date'))
In [486]: pd.read_sql(expr, engine, params={'date': dt.datetime(2010, 10, 18)})
Out[486]:
index Date Col_1 Col_2 Col_3
0 1 2010-10-19 Y -12.50 False
1 2 2010-10-20 Z 5.73 True
Обратная совместимость с SQLite
Использование SQLite поддерживается без использования SQLAlchemy. Этот режим требует адаптера Python для базы данных, который соответствует Python DB-API.
Вы можете создать подключения следующим образом:
import sqlite3
con = sqlite3.connect(':memory:')
А затем выполнить следующие запросы:
data.to_sql('data', cnx)
pd.read_sql_query("SELECT * FROM data", con)
Google BigQuery (Экспериментально)
Введено в версии 0.13.0.
Модуль pandas.io.gbq предоставляет оболочку для веб-сервиса Google BigQuery аналитики для упрощения извлечения результатов из таблиц BigQuery с помощью запросов, похожих на SQL. Результаты парсятся в DataFrame pandas с формой и типами данных, полученными из исходной таблицы. Кроме того, DataFrames могут быть вставлены в новые таблицы BigQuery или добавлены к существующим таблицам.
Вам понадобятся дополнительные зависимости:
Предупреждение
Для использования этого модуля вам потребуется действительный аккаунт BigQuery. Подробности об этом сервисе см. в документации BigQuery.
Основные функции:
read_gbq(query[, project_id, index_col, ...]) | Загрузка данных из Google BigQuery. |
to_gbq(dataframe, destination_table, project_id) | Запись DataFrame в таблицу Google BigQuery. |
Авторизация
Введено в версии 0.18.0.
Авторизация для сервиса Google BigQuery осуществляется с помощью OAuth 2.0. Возможна авторизация как с помощью учетных данных пользователя, так и с помощью учетных данных сервисного аккаунта.
Авторизация с помощью учетных данных пользователя проста и заключается в следовании подсказкам в открытом автоматически окне браузера. Вы будете авторизованы в указанной учетной записи BigQuery с помощью имени продукта pandas GBQ. Это возможно только на локальном хосте. Дистанционная авторизация с помощью учетных данных пользователя в настоящее время не поддерживается в Pandas. Дополнительную информацию об этом механизме авторизации можно найти здесь.
Авторизация с помощью учетных данных сервисного аккаунта возможна через параметр ‘private_key’. Этот метод особенно полезен при работе на удаленных серверах (например, в jupyter iPython notebook на удаленном хосте). Дополнительную информацию о сервисных аккаунтах можно найти здесь.
Вам потребуется установить дополнительную зависимость: oauth2client.
Авторизация через application default credentials также возможна. Это справедливо только в том случае, если параметр private_key не указан. Этот метод также требует, чтобы учетные данные можно было извлечь из среды, в которой выполняется код. В противном случае используется авторизация OAuth2 на стороне клиента. Дополнительную информацию об учетных данных по умолчанию для приложений.
Введено в версии 0.19.0.
Примечание
Параметр ‘private_key’ может быть установлен либо на путь к файлу ключа сервисного аккаунта в формате JSON, либо на содержимое ключа сервисного аккаунта в формате JSON.
Примечание
Закрытый ключ можно получить из консоли разработчиков Google, нажав здесь. Используйте тип ключа JSON.
Запросы
Предположим, вы хотите загрузить все данные из существующей таблицы BigQuery: test_dataset.test_table в DataFrame с помощью функции read_gbq().
# Insert your BigQuery Project ID Here
# Can be found in the Google web console
projectid = "xxxxxxxx"
data_frame = pd.read_gbq('SELECT * FROM test_dataset.test_table', projectid)
Вы можете определить, какой столбец из BigQuery использовать в качестве индекса в целевом DataFrame, а также предпочтительный порядок столбцов следующим образом:
data_frame = pd.read_gbq('SELECT * FROM test_dataset.test_table',
index_col='index_column_name',
col_order=['col1', 'col2', 'col3'], projectid)
Примечание
Вы можете найти свой идентификатор проекта в консоли разработчиков Google.
Примечание
Вы можете переключить подробный вывод с помощью флага verbose, по умолчанию установленного в True.
Примечание
Аргумент dialect может быть использован для указания, использовать ли стандартный SQL BigQuery или SQL BigQuery (бета). Значение по умолчанию 'legacy'. Для получения дополнительной информации о стандартном SQL BigQuery, см. Справочник по SQL BigQuery
Запись DataFrame
Предположим, мы хотим записать DataFrame df в таблицу BigQuery, используя to_gbq().
In [487]: df = pd.DataFrame({'my_string': list('abc'),
.....: 'my_int64': list(range(1, 4)),
.....: 'my_float64': np.arange(4.0, 7.0),
.....: 'my_bool1': [True, False, True],
.....: 'my_bool2': [False, True, False],
.....: 'my_dates': pd.date_range('now', periods=3)})
.....:
In [488]: df
Out[488]:
my_bool1 my_bool2 my_dates my_float64 my_int64 my_string
0 True False 2016-12-24 18:33:33.411047 4.0 1 a
1 False True 2016-12-25 18:33:33.411047 5.0 2 b
2 True False 2016-12-26 18:33:33.411047 6.0 3 c
In [489]: df.dtypes
Out[489]:
my_bool1 bool
my_bool2 bool
my_dates datetime64[ns]
my_float64 float64
my_int64 int64
my_string object
dtype: object
df.to_gbq('my_dataset.my_table', projectid)
Примечание
Целевая таблица и целевой набор данных будут автоматически созданы, если они не существуют.
Аргумент if_exists может быть использован для определения, 'fail', 'replace' или 'append' в случае, если целевая таблица уже существует. Значение по умолчанию 'fail'.
Например, предположим, что if_exists установлено в значение 'fail'. Следующий фрагмент кода вызовет TableCreationError если целевая таблица уже существует.
df.to_gbq('my_dataset.my_table', projectid, if_exists='fail')
Примечание
Если аргумент if_exists установлен в 'append', целевой DataFrame будет записан в таблицу, используя определённую схему таблицы и типы столбцов. DataFrame должен соответствовать структуре и типам данных целевой таблицы. Если аргумент if_exists установлен в 'replace', и имеющаяся таблица имеет другую схему, будет принудительно установлена задержка в 2 минуты для обеспечения того, что новая схема будет распространена в среде Google. См. Google BigQuery issue 191.
Запись больших DataFrame может привести к ошибкам из-за превышения ограничений по размеру. Этого можно избежать, установив аргумент chunksize при вызове to_gbq(). Например, следующий код записывает df в таблицу BigQuery партиями по 10000 строк за раз:
df.to_gbq('my_dataset.my_table', projectid, chunksize=10000)
Также можно отслеживать прогресс операции с помощью флага verbose, по умолчанию равного True. Например:
In [8]: df.to_gbq('my_dataset.my_table', projectid, chunksize=10000, verbose=True)
Streaming Insert is 10% Complete
Streaming Insert is 20% Complete
Streaming Insert is 30% Complete
Streaming Insert is 40% Complete
Streaming Insert is 50% Complete
Streaming Insert is 60% Complete
Streaming Insert is 70% Complete
Streaming Insert is 80% Complete
Streaming Insert is 90% Complete
Streaming Insert is 100% Complete
Примечание
Если при потоковой передаче данных в BigQuery возникнет ошибка, см. Устранение неполадок BigQuery.
Примечание
Язык запросов BigQuery SQL имеет некоторые особенности, см. Документация по справочнику запросов BigQuery.
Примечание
Хотя BigQuery использует синтаксис, похожий на SQL, существуют важные отличия от традиционных баз данных в функциональности, ограничениях API (размер и количество запросов или загрузок), и способе, которым Google взимает плату за использование сервиса. Часто обращайтесь к документации Google BigQuery, поскольку сервис постоянно развивается и меняется. BigQuery подходит для быстрого анализа больших наборов данных, но не является прямым заменителем транзакционной базы данных.
Создание таблиц BigQuery
Предупреждение
Начиная с версии 0.17, функция generate_bq_schema() устарела и будет удалена в будущей версии.
Начиная с версии 0.15.2, модуль gbq имеет функцию generate_bq_schema(), которая создаст представление схемы в виде словаря для указанного DataFrame pandas.
In [10]: gbq.generate_bq_schema(df, default_type='STRING')
Out[10]: {'fields': [{'name': 'my_bool1', 'type': 'BOOLEAN'},
{'name': 'my_bool2', 'type': 'BOOLEAN'},
{'name': 'my_dates', 'type': 'TIMESTAMP'},
{'name': 'my_float64', 'type': 'FLOAT'},
{'name': 'my_int64', 'type': 'INTEGER'},
{'name': 'my_string', 'type': 'STRING'}]}
Примечание
Если вы удаляете и снова создаёте таблицу BigQuery с тем же именем, но с другой схемой таблицы, вам нужно подождать 2 минуты, прежде чем передавать данные в таблицу. В качестве обходного решения, рассмотрите создание новой таблицы с другим именем. См. Google BigQuery issue 191.
Формат Stata
Новая функция в версии 0.12.0.
Запись в формат Stata
Метод to_stata() запишет DataFrame в файл .dta. Версия формата этого файла всегда 115 (Stata 12).
In [490]: df = pd.DataFrame(randn(10, 2), columns=list('AB'))
In [491]: df.to_stata('stata.dta')
Файлы данных Stata имеют ограниченную поддержку типов данных; только строки длиной 244 символа или меньше, int8, int16, int32, float32 и float64 могут быть сохранены в файлах .dta. Кроме того, Stata зарезервировал определённые значения для представления отсутствующих данных. Экспорт значения, отличного от отсутствующего, которое находится за пределами допустимого диапазона в Stata для определённого типа данных, приведёт к преобразованию переменной к следующему большему размеру. Например, значения int8 ограничены интервалом от -127 до 100 в Stata, и поэтому переменные со значениями выше 100 будут преобразованы к типу int16. Отсутствующие значения в типах данных с плавающей запятой хранятся как базовый тип отсутствующих данных (. в Stata).
Примечание
Экспорт значений отсутствующих данных для целочисленных типов данных невозможен.
Модуль Stata корректно обрабатывает другие типы данных, включая int64, bool, uint8, uint16, uint32, преобразуя их к наименьшему поддерживаемому типу, который может представить данные. Например, данные с типом uint8 будут преобразованы к типу int8, если все значения меньше 100 (верхняя граница для значений, не являющихся отсутствующими, в данных Stata), или, если значения находятся за пределами этого диапазона, переменная преобразуется к типу int16.
Предупреждение
Преобразование из int64 в float64 может привести к потере точности, если значения int64 больше, чем 2**53.
Предупреждение
StataWriter и to_stata() поддерживают только строки фиксированной длины, содержащие до 244 символов, что является ограничением формата файла dta версии 115. Попытка записать файлы Stata dta со строками длиннее 244 символов вызовет ValueError.
Чтение из формата Stata
Функция верхнего уровня read_stata прочитает файл dta и вернёт DataFrame или итератор StataReader, который может использоваться для поэтапного чтения файла.
In [492]: pd.read_stata('stata.dta')
Out[492]:
index A B
0 0 1.810535 -1.305727
1 1 -0.344987 -0.230840
2 2 -2.793085 1.937529
3 3 0.366332 -1.044589
4 4 2.051173 0.585662
5 5 0.429526 -0.606998
6 6 0.106223 -1.525680
7 7 0.795026 -0.374438
8 8 0.134048 1.202055
9 9 0.284748 0.262467
Новая функция в версии 0.16.0.
Указание chunksize возвращает объект StataReader, который можно использовать для чтения chunksize строк из файла за раз. Объект StataReader может использоваться как итератор.
In [493]: reader = pd.read_stata('stata.dta', chunksize=3)
In [494]: for df in reader:
.....: print(df.shape)
.....:
(3, 3)
(3, 3)
(3, 3)
(1, 3)
Для более тонкого управления, используйте iterator=True и укажите chunksize при каждом вызове read().
In [495]: reader = pd.read_stata('stata.dta', iterator=True)
In [496]: chunk1 = reader.read(5)
In [497]: chunk2 = reader.read(5)
В настоящее время index извлекается как столбец.
Параметр convert_categoricals указывает, должны ли быть прочитаны метки значений и использованы для создания переменной Categorical из них. Метки значений также могут быть получены функцией value_labels, которая требует вызова read() перед использованием.
Параметр convert_missing указывает, должны ли быть сохранены представления отсутствующих значений в Stata. Если False (значение по умолчанию), отсутствующие значения представлены как np.nan. Если True, отсутствующие значения представлены с помощью объектов StataMissingValue, и столбцы, содержащие отсутствующие значения, будут иметь тип данных object.
Примечание
read_stata() и StataReader поддерживают форматы .dta 113-115 (Stata 10-12), 117 (Stata 13) и 118 (Stata 14).
Примечание
Установка preserve_dtypes=False приведёт к преобразованию к стандартным типам данных pandas: int64 для всех целочисленных типов и float64 для типов с плавающей запятой. По умолчанию типы данных Stata сохраняются при импорте.
Данные категорий
Новая функция в версии 0.15.2.
Данные Categorical могут быть экспортированы в файлы данных Stata в виде данных с метками значений. Экспортируемые данные состоят из базовых кодов категорий как целочисленных значений и категорий как меток значений. Stata не имеет явного эквивалента Categorical, и информация о том, является ли переменная упорядоченной, теряется при экспорте.
Предупреждение
Stata поддерживает только строковые метки значений, поэтому str вызывается для категорий при экспорте данных. Экспорт переменных Categorical с категориями, отличными от строк, вызовет предупреждение и может привести к потере информации, если представленя категорий str не уникальны.
Метки значений могут аналогичным образом импортироваться из файлов данных Stata как переменные Categorical с использованием ключевого аргумента convert_categoricals (True по умолчанию). Ключевой аргумент order_categoricals (True по умолчанию) определяет, являются ли импортированные переменные Categorical упорядоченными.
Примечание
При импорте категориальных данных значения переменных в файле данных Stata не сохраняются, поскольку переменные Categorical всегда используют целочисленные типы данных между -1 и n-1, где n — количество категорий. Если исходные значения в файле данных Stata необходимы, их можно импортировать, установив convert_categoricals=False, что импортирует исходные данные (но не метки переменных). Исходные значения можно сопоставить с импортированными категориальными данными, поскольку существует простое отображение между исходными значениями данных Stata и кодами категорий импортированных категориальных переменных: пропущенным значениям присваивается код -1, а наименьшему исходному значению присваивается 0, второму наименьшему — 1 и так далее до тех пор, пока наибольшему исходному значению не будет присвоен код n-1.
Примечание
Stata поддерживает частично помеченные ряды. Эти ряды имеют метки значений для некоторых, но не для всех значений данных. Импорт частично помеченного ряда приведет к Categorical со строчными категориями для помеченных значений и числовыми категориями для значений без метки.
Форматы SAS
Новая версия 0.17.0.
Функция верхнего уровня read_sas() может читать (но не записывать) файлы формата SAS xport (.XPT) и SAS7BDAT (.sas7bdat), добавленные в v0.18.0.
Файлы SAS содержат только два типа значений: текстовые значения ASCII и значения с плавающей точкой (обычно 8 байт, но иногда усеченные). Для файлов xport нет автоматического преобразования типов в целые числа, даты или категориальные значения. Для файлов SAS7BDAT коды формата могут позволить автоматически преобразовывать переменные даты в даты. По умолчанию весь файл читается и возвращается как DataFrame.
Укажите chunksize или используйте iterator=True для получения объектов чтения (XportReader или SAS7BDATReader) для поэтапного чтения файла. Объекты чтения также имеют атрибуты, содержащие дополнительную информацию о файле и его переменных.
Чтение файла SAS7BDAT:
df = pd.read_sas('sas_data.sas7bdat')
Получение итератора и чтение файла XPORT по 100 000 строк за раз:
rdr = pd.read_sas('sas_xport.xpt', chunk=100000)
for chunk in rdr:
do_something(chunk)
Спецификация формата файла xport доступна на веб-сайте SAS.
Официальной документации по формату SAS7BDAT нет.
Другие форматы файлов
Сам pandas поддерживает только ввод-вывод с ограниченным набором форматов файлов, которые чисто отображаются в его модели табличных данных. Для чтения и записи других форматов файлов в pandas и из pandas мы рекомендуем эти пакеты из более широкого сообщества.
netCDF
xarray предоставляет структуры данных, вдохновленные DataFrame pandas, для работы с многомерными наборами данных, с уклоном в формат файла netCDF и простым преобразованием в pandas и обратно.
Соображения по производительности
Это неофициальное сравнение различных методов ввода-вывода, использующее pandas 0.13.1.
In [1]: df = pd.DataFrame(randn(1000000,2),columns=list('AB'))
In [2]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1000000 entries, 0 to 999999
Data columns (total 2 columns):
A 1000000 non-null float64
B 1000000 non-null float64
dtypes: float64(2)
memory usage: 22.9 MB
Запись
In [14]: %timeit test_sql_write(df) 1 loops, best of 3: 6.24 s per loop In [15]: %timeit test_hdf_fixed_write(df) 1 loops, best of 3: 237 ms per loop In [26]: %timeit test_hdf_fixed_write_compress(df) 1 loops, best of 3: 245 ms per loop In [16]: %timeit test_hdf_table_write(df) 1 loops, best of 3: 901 ms per loop In [27]: %timeit test_hdf_table_write_compress(df) 1 loops, best of 3: 952 ms per loop In [17]: %timeit test_csv_write(df) 1 loops, best of 3: 3.44 s per loop
Чтение
In [18]: %timeit test_sql_read() 1 loops, best of 3: 766 ms per loop In [19]: %timeit test_hdf_fixed_read() 10 loops, best of 3: 19.1 ms per loop In [28]: %timeit test_hdf_fixed_read_compress() 10 loops, best of 3: 36.3 ms per loop In [20]: %timeit test_hdf_table_read() 10 loops, best of 3: 39 ms per loop In [29]: %timeit test_hdf_table_read_compress() 10 loops, best of 3: 60.6 ms per loop In [22]: %timeit test_csv_read() 1 loops, best of 3: 620 ms per loop
Место на диске (в байтах)
25843712 Apr 8 14:11 test.sql 24007368 Apr 8 14:11 test_fixed.hdf 15580682 Apr 8 14:11 test_fixed_compress.hdf 24458444 Apr 8 14:11 test_table.hdf 16797283 Apr 8 14:11 test_table_compress.hdf 46152810 Apr 8 14:11 test.csv
И вот код
import sqlite3
import os
from pandas.io import sql
df = pd.DataFrame(randn(1000000,2),columns=list('AB'))
def test_sql_write(df):
if os.path.exists('test.sql'):
os.remove('test.sql')
sql_db = sqlite3.connect('test.sql')
df.to_sql(name='test_table', con=sql_db)
sql_db.close()
def test_sql_read():
sql_db = sqlite3.connect('test.sql')
pd.read_sql_query("select * from test_table", sql_db)
sql_db.close()
def test_hdf_fixed_write(df):
df.to_hdf('test_fixed.hdf','test',mode='w')
def test_hdf_fixed_read():
pd.read_hdf('test_fixed.hdf','test')
def test_hdf_fixed_write_compress(df):
df.to_hdf('test_fixed_compress.hdf','test',mode='w',complib='blosc')
def test_hdf_fixed_read_compress():
pd.read_hdf('test_fixed_compress.hdf','test')
def test_hdf_table_write(df):
df.to_hdf('test_table.hdf','test',mode='w',format='table')
def test_hdf_table_read():
pd.read_hdf('test_table.hdf','test')
def test_hdf_table_write_compress(df):
df.to_hdf('test_table_compress.hdf','test',mode='w',complib='blosc',format='table')
def test_hdf_table_read_compress():
pd.read_hdf('test_table_compress.hdf','test')
def test_csv_write(df):
df.to_csv('test.csv',mode='w')
def test_csv_read():
pd.read_csv('test.csv',index_col=0)
© 2008–2012, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
Licensed under the 3-clause BSD License.
https://pandas.pydata.org/pandas-docs/version/0.19.2/io.html