Spec-Zone.ru › pandas 0.19

Инструменты Ввода-Вывода (Текст, 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
: строка, по умолчанию ',' для read_csv(), \t для read_table()
Разделитель. Если sep — None, попытается автоматически определить его. Разделители длиной более 1 символа и отличные от '\s+' будут интерпретироваться как регулярные выражения, заставят использовать анализатор Python и проигнорируют кавычки в данных. Пример регулярного выражения: '\\r\\t'.
delimiter
: строка, по умолчанию None
Альтернативное имя аргумента для sep.
delim_whitespace
: логическое значение, по умолчанию False

Указывает, использовать ли пробелы (например, ' ' или '\t') в качестве разделителя. Эквивалентно установке sep='\s+'. Если этот параметр установлен в True, параметр delimiter не должен передаваться.

Добавлена в версии 0.18.1: поддержка парсера Python.

Расположение и имена столбцов и индексов

header
: целое число или список целых чисел, по умолчанию 'infer'
Номер(а) строки(ок) для использования в качестве имен столбцов и начала данных. По умолчанию ведет себя так, как если бы header=0 если не передан names, иначе как если бы header=None. Явно передайте header=0 для возможности замены существующих имен. Заголовок может быть списком целых чисел, которые указывают местоположения строк для многоуровневого индекса столбцов, например, [0,1,3]. Промежуточные строки, которые не указаны, будут пропущены (например, 2 в этом примере пропущена). Обратите внимание, что этот параметр игнорирует прокомментированные строки и пустые строки, если skip_blank_lines=True, поэтому header=0 обозначает первую строку данных, а не первую строку файла.
names
: массив-подобный объект, по умолчанию None
Список имен столбцов для использования. Если файл не содержит строки заголовка, необходимо явно передать header=None. Дубликаты в этом списке не допускаются, если mangle_dupe_cols=True, что является значением по умолчанию.
index_col
: целое число или последовательность или False, по умолчанию None
Столбец для использования в качестве меток строк DataFrame. Если задана последовательность, используется многоуровневый индекс. Если у вас есть повреждённый файл с разделителями в конце каждой строки, рассмотрите возможность index_col=False чтобы заставить pandas не использовать первый столбец в качестве индекса (имен строк).
usecols
: массив-подобный объект, по умолчанию None
Возвращает подмножество столбцов. Все элементы этого массива должны быть либо позиционными (т. е. целочисленными индексами столбцов документа), либо строками, соответствующими именам столбцов, предоставленных пользователем в names или полученных из строки(ок) заголовка документа. Например, допустимым параметром usecols будет [0, 1, 2] или [‘foo’, ‘bar’, ‘baz’]. Использование этого параметра приводит к значительно более быстрому парсингу и меньшей потребности в памяти.
as_recarray
: логическое значение, по умолчанию False

УСТАРЕЛО: этот аргумент будет удален в будущих версиях. Пожалуйста, используйте pd.read_csv(...).to_records() вместо этого.

Возвращает массив NumPy recarray вместо DataFrame после парсинга данных. Если установлено True, этот параметр имеет приоритет над параметром squeeze. Кроме того, поскольку индексы строк недоступны в таком формате, параметр index_col будет проигнорирован.

squeeze
: логическое значение, по умолчанию False
Если прочитанные данные содержат только один столбец, возвращает Series.
prefix
: строка, по умолчанию None
Префикс, добавляемый к номерам столбцов, когда нет заголовка, например, «X» для X0, X1, ...
mangle_dupe_cols
: логическое значение, по умолчанию True
Дублирующие столбцы будут указаны как «X.0»…«X.N», а не «X»…«X». Передача False приведет к перезаписи данных, если в столбцах есть дублирующие имена.

Общие настройки парсинга

dtype
: Имя типа или словарь столбец -> тип, по умолчанию None
Тип данных для данных или столбцов. Например, {'a': np.float64, 'b': np.int32} (не поддерживается с engine='python'). Используйте str или object, чтобы сохранить и не интерпретировать dtype.
engine
: {'c', 'python'}
Двигатель парсера для использования. Двигатель C быстрее, а двигатель Python в настоящее время более функционален.
converters
: словарь, по умолчанию None
Словарь функций для преобразования значений в определённых столбцах. Ключи могут быть целыми числами или метками столбцов.
true_values
: список, по умолчанию None
Значения, которые следует рассматривать как True.
false_values
: список, по умолчанию None
Значения, которые следует рассматривать как False.
skipinitialspace
: булево, по умолчанию False
Пропустить пробелы после разделителя.
skiprows
: подобный списку или целое число, по умолчанию None
Номера строк для пропуска (индексация с 0) или количество строк для пропуска (целое число) в начале файла.
skipfooter
: целое число, по умолчанию 0
Количество строк внизу файла для пропуска (не поддерживается с engine='c').
skip_footer
: целое число, по умолчанию 0
УСТАРЕВШЕЕ: используйте вместо этого параметр skipfooter, так как они идентичны
nrows
: целое число, по умолчанию None
Количество строк файла для чтения. Полезно для чтения фрагментов больших файлов.
low_memory
: булево, по умолчанию True
Внутренне обрабатывает файл частями, что приводит к меньшему использованию памяти во время анализа, но, возможно, смешанному выводу типа. Чтобы гарантировать отсутствие смешанных типов, либо задайте 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 указан путь к файлу, отобразить файл непосредственно в памяти и получить доступ к данным напрямую из него. Использование этого параметра может повысить производительность, потому что теперь нет накладных расходов на ввод-вывод.

Обработка NA и пропущенных данных

na_values
: скаляр, строка, список-подобный объект или словарь, по умолчанию None
Дополнительные строки для распознавания 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
: булево, по умолчанию True
Если заданы na_values и keep_default_na равно False, значения NaN по умолчанию перезаписываются, иначе они добавляются.
na_filter
: булево, по умолчанию True
Обнаружение маркеров пропущенных значений (пустые строки и значение na_values). При данных без NA, передача na_filter=False может улучшить производительность чтения большого файла.
verbose
: булево, по умолчанию False
Указать количество значений NA, помещённых в нечисловые столбцы.
skip_blank_lines
: булево, по умолчанию True
Если True, пропустить пустые строки, а не интерпретировать их как значения NaN.

Обработка дат и времени

parse_dates
: булево или список целых чисел или имён или список списков или словарь, по умолчанию False.
  • Если True -> попытка парсинга индекса.
  • Если [1, 2, 3] -> попытка парсинга столбцов 1, 2, 3 как отдельных столбцов дат.
  • Если [[1, 3]] -> объединение столбцов 1 и 3 и парсинг как одного столбца дат.
  • Если {'foo' : [1, 3]} -> парсинг столбцов 1, 3 как дат и присвоение результата 'foo'. Быстрый путь существует для дат в формате iso8601.
infer_datetime_format
: булево, по умолчанию False
Если True и parse_dates включён для столбца, попытаться определить формат даты и времени для ускорения обработки.
keep_date_col
: булево, по умолчанию False
Если True и parse_dates определяет объединение нескольких столбцов, то сохранить исходные столбцы.
date_parser
: функция, по умолчанию None
Функция для преобразования последовательности столбцов строк в массив экземпляров datetime. По умолчанию используется dateutil.parser.parser для преобразования. Pandas попытается вызвать date_parser тремя различными способами, переходя к следующему, если произойдёт исключение: 1) Передать один или несколько массивов (как определено parse_dates) в качестве аргументов; 2) конкатенировать (по строкам) строковые значения из столбцов, определённых parse_dates, в один массив и передать его; и 3) вызвать date_parser один раз для каждой строки, используя одну или несколько строк (соответствующих столбцам, определённым parse_dates) в качестве аргументов.
dayfirst
: булево, по умолчанию False
Даты в формате ДД/ММ, международный и европейский формат.

Итерация

iterator
: булево, по умолчанию False
Возвратить объект для итерации или получения фрагментов с get_chunk().
chunksize
: целое число, по умолчанию None
Возвращает объект для итерации. См. Итерация и фрагментация ниже.

Цитаты, сжатие и формат файла

compression
: {'infer', 'gzip', 'bz2', 'zip', 'xz', None}, default 'infer'

Для декомпрессии данных на диске в режиме реального времени. Если ‘infer’, то использовать gzip, bz2, zip или xz, если filepath_or_buffer является строкой, заканчивающейся на ‘.gz’, ‘.bz2’, ‘.zip’ или ‘.xz’ соответственно, и без декомпрессии в противном случае. Если используется ‘zip’, архив ZIP должен содержать только один файл данных для чтения. Установите в None для отключения декомпрессии.

Введено в версии 0.18.1: поддержка сжатия ‘zip’ и ‘xz’.

thousands
: str, default None
Разделитель тысяч.
decimal
: str, default '.'
Символ, распознаваемый как десятичная точка. Например, используйте ',' для европейских данных.
float_precision
: string, default None
Указывает, какой конвертер должен использовать C движок для значений с плавающей точкой. Доступные варианты: None для обычного конвертера, high для конвертера высокой точности и round_trip для конвертера обратного преобразования.
lineterminator
: str (длина 1), default None
Символ для разделения файла на строки. Действителен только с C парсером.
quotechar
: str (длина 1)
Символ, используемый для обозначения начала и конца цитируемого элемента. Цитируемые элементы могут включать разделитель, и он будет проигнорирован.
quoting
: int or csv.QUOTE_* instance, default 0
Управление поведением цитирования полей по константам csv.QUOTE_* . Используйте один из QUOTE_MINIMAL (0), QUOTE_ALL (1), QUOTE_NONNUMERIC (2) или QUOTE_NONE (3).
doublequote
: boolean, default True
Когда указан quotechar, и quoting не QUOTE_NONE, указывает, следует ли интерпретировать два последовательных элемента quotechar внутри поля как один элемент quotechar.
escapechar
: str (длина 1), default None
Строка длиной в один символ, используемая для экранирования разделителя, когда цитирование QUOTE_NONE.
comment
: str, default None
Указывает, что оставшаяся часть строки не должна анализироваться. Если он находится в начале строки, строка будет проигнорирована полностью. Этот параметр должен быть одиночным символом. Как и пустые строки (пока skip_blank_lines=True), полностью комментированные строки игнорируются параметром header, но не skiprows. Например, если comment='#', парсинг ‘#empty\na,b,c\n1,2,3’ с header=0 приведет к тому, что ‘a,b,c’ будет обработана как заголовок.
encoding
: str, default None
Кодировка UTF для чтения/записи (например, 'utf-8'). Список стандартных кодировок Python.
dialect
: str or csv.Dialect instance, default None
Если None по умолчанию использует диалект Excel. Игнорируется, если sep длиннее 1 символа. См. csv.Dialect для получения дополнительной информации.
tupleize_cols
: boolean, default False
Оставить список кортежей в столбцах без изменений (по умолчанию преобразовать в MultiIndex для столбцов).

Обработка ошибок

error_bad_lines
: boolean, default True
Строки с слишком многими полями (например, строка CSV со слишком многими запятыми) по умолчанию вызовут исключение, и DataFrame не будет возвращён. Если False, то эти «плохие строки» будут удалены из возвращаемого DataFrame (действительно только с C парсером). См. плохие строки ниже.
warn_bad_lines
: boolean, default True
Если error_bad_lines False, и warn_bad_lines True, для каждой «плохой строки» будет выведено предупреждение (действительно только с C парсером).

Рассмотрим типичный 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 тремя различными способами. Если возникает исключение, будет предпринята следующая попытка:

  1. date_parser сначала вызывается с одним или несколькими массивами в качестве аргументов, как определено с помощью parse_dates (например, date_parser(['2013', '2013'], ['1', '2']))
  2. Если #1 завершается ошибкой, date_parser вызывается со всеми столбцами, склеенными построчно в один массив (например, date_parser(['2013 1', '2013 2']))
  3. Если #2 завершается ошибкой, date_parser вызывается один раз для каждой строки с одним или несколькими строковыми аргументами из столбцов, указанных с помощью parse_dates (например, date_parser('2013', '1') для первой строки, date_parser('2013', '2') для второй и т. д.)

Обратите внимание, что с точки зрения производительности вы должны попробовать эти методы анализа дат в указанном порядке:

  1. Попробуйте определить формат с помощью infer_datetime_format=True (см. раздел ниже)
  2. Если вы знаете формат, используйте pd.to_datetime(): date_parser=lambda x: pd.to_datetime(x, format=...)
  3. Если у вас действительно нестандартный формат, используйте пользовательскую функцию 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 : Если records orient, то записывает каждую запись в строку как 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}
    DataFrame
    • default is columns
    • allowed values are {split, records, index, columns, values}

    The format of the JSON string

    split dict like {index -> [index], columns -> [columns], data -> [values]}
    records list like [{column -> value}, ... , {column -> value}]
    index dict like {index -> {column -> value}}
    columns dict like {column -> {index -> value}}
    values just 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 if numpy=True
  • precise_float : boolean, default False. 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>&amp;</td>
      <td>-0.474063</td>
    </tr>
    <tr>
      <th>1</th>
      <td>&lt;</td>
      <td>-0.230305</td>
    </tr>
    <tr>
      <th>2</th>
      <td>&gt;</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 двумя способами:

  1. ключевое слово engine
  2. расширение файла (через значение по умолчанию, заданное в параметрах конфигурации)

По умолчанию 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 и выше, особенно при работе со стилями.
  • xlsxwriter
  • xlwt
# 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

Предупреждение

Загрузка закодированных данных из ненадежных источников может быть небезопасной.

См.: http://docs.python.org/2.7/library/pickle.html

Предупреждение

Несколько внутренних рефакторингов, в 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 2
  • >=0.18 / любой Python
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 или добавлены к существующим таблицам.

Вам понадобятся дополнительные зависимости:

  • Google python-gflags
  • httplib2
  • google-api-python-client

Предупреждение

Для использования этого модуля вам потребуется действительный аккаунт 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API