Инструменты ввода-вывода (текст, CSV, HDF5, …)#
API ввода-вывода pandas — это набор высокоуровневых reader функции, доступные как
pandas.read_csv() которые обычно возвращают объект pandas. Соответствующий
writer функции являются методами объектов, которые доступны как
DataFrame.to_csv(). Ниже приведена таблица с доступными readers и
writers.
Тип формата |
Описание данных |
Reader |
Writer |
|---|---|---|---|
текст |
|||
текст |
Файл с текстом фиксированной ширины |
NA |
|
текст |
|||
текст |
|||
текст |
NA |
||
текст |
|||
текст |
Локальный буфер обмена |
||
бинарный |
|||
бинарный |
NA |
||
бинарный |
|||
бинарный |
|||
бинарный |
|||
бинарный |
|||
бинарный |
|||
бинарный |
NA |
||
бинарный |
NA |
||
бинарный |
|||
SQL |
|||
SQL |
Google BigQuery;:ref:read_gbq |
Здесь является неформальным сравнением производительности для некоторых из этих методов ввода-вывода.
Примечание
Для примеров, использующих StringIO класса, убедитесь, что импортируете его с помощью from io import StringIO для Python 3.
CSV и текстовые файлы#
Основная функция для чтения текстовых файлов (также известных как плоские файлы) —
read_csv(). См. cookbook для некоторых продвинутых стратегий.
Параметры парсинга#
read_csv() принимает следующие общие аргументы:
Базовый#
- filepath_or_bufferразличные
Либо путь к файлу (
str,pathlib.Path, илиpy:py._path.local.LocalPath), URL (включая http, ftp и S3-локации) или любой объект сread()метод (например, открытый файл илиStringIO).- sepstr, по умолчанию
','дляread_csv(),\tдляread_table() Разделитель для использования. Если sep - это
None, C-движок не может автоматически определить разделитель, но Python-движок парсинга может, что означает, что последний будет использоваться и автоматически определять разделитель с помощью встроенного инструмента Python sniffer,csv.Sniffer. Кроме того, разделители длиннее 1 символа и отличающиеся от'\s+'будут интерпретироваться как регулярные выражения и также принудительно использовать парсер Python. Обратите внимание, что разделители regex склонны игнорировать данные в кавычках. Пример regex:'\\r\\t'.- разделительstr, по умолчанию
None Альтернативное имя аргумента для sep.
- delim_whitespaceboolean, по умолчанию False
Определяет, учитывать ли пробелы (например,
' 'или'\t') будет использоваться как разделитель. Эквивалентно установкеsep='\s+'. Если эта опция установлена вTrue, ничего не должно передаваться дляdelimiterпараметр.
Расположение и имена столбцов и индексов#
- headerint или список int, по умолчанию
'infer' Номера строк для использования в качестве названий столбцов и начала данных. Поведение по умолчанию — выводить названия столбцов: если имена не переданы, поведение идентично
header=0и имена столбцов выводятся из первой строки файла, если имена столбцов переданы явно, то поведение идентичноheader=None. Явно передатьheader=0чтобы иметь возможность заменять существующие имена.Заголовок может быть списком целых чисел, которые указывают позиции строк для MultiIndex на столбцах, например
[0,1,3]. Промежуточные строки которые не указаны, будут пропущены (например, 2 в этом примере пропускается). Обратите внимание, что этот параметр игнорирует закомментированные строки и пустые строки, еслиskip_blank_lines=True, поэтому header=0 обозначает первую строку данных, а не первую строку файла.- namesмассивоподобный, по умолчанию
None Список имен столбцов для использования. Если файл не содержит строки заголовка, следует явно передать
header=None. Дубликаты в этом списке не допускаются.- index_colint, str, последовательность int / str, или False, опционально, по умолчанию
None Столбец(цы) для использования в качестве меток строк
DataFrame, либо заданный как строковое имя или индекс столбца. Если задана последовательность int / str, используется MultiIndex.Примечание
index_col=Falseможно использовать для принуждения pandas к не используйте первый столбец в качестве индекса, например, когда у вас есть повреждённый файл с разделителями в конце каждой строки.Значение по умолчанию для
Noneуказывает pandas угадать. Если количество полей в строке заголовка столбца равно количеству полей в теле файла данных, то используется индекс по умолчанию. Если оно больше, то первые столбцы используются как индекс, чтобы оставшееся количество полей в теле было равно количеству полей в заголовке.Первая строка после заголовка используется для определения количества столбцов, которые войдут в индекс. Если последующие строки содержат меньше столбцов, чем первая строка, они заполняются
NaN.Этого можно избежать с помощью
usecols. Это гарантирует, что столбцы берутся как есть, а последующие данные игнорируются.- usecolsсписок или вызываемый объект, по умолчанию
None Возвращает подмножество столбцов. Если передаётся список, все элементы должны быть либо позиционными (т.е. целочисленными индексами столбцов документа), либо строками, соответствующими именам столбцов, предоставленным пользователем в
namesили выведен из строк заголовка документа. Еслиnamesуказаны, строка(и) заголовка документа не учитываются. Например, допустимый списокusecolsпараметр будет[0, 1, 2]или['foo', 'bar', 'baz'].Порядок элементов игнорируется, поэтому
usecols=[0, 1]то же самое, что[1, 0]. Для создания DataFrame изdataс сохранением порядка элементов используйтеpd.read_csv(data, usecols=['foo', 'bar'])[['foo', 'bar']]для столбцов в['foo', 'bar']порядок илиpd.read_csv(data, usecols=['foo', 'bar'])[['bar', 'foo']]для['bar', 'foo']порядок.Если вызываемый объект, вызываемая функция будет оценена по именам столбцов, возвращая имена, где вызываемая функция оценивается как True:
In [1]: import pandas as pd In [2]: from io import StringIO In [3]: data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3" In [4]: pd.read_csv(StringIO(data)) Out[4]: col1 col2 col3 0 a b 1 1 a b 2 2 c d 3 In [5]: pd.read_csv(StringIO(data), usecols=lambda x: x.upper() in ["COL1", "COL3"]) Out[5]: col1 col3 0 a 1 1 a 2 2 c 3
Использование этого параметра значительно ускоряет время парсинга и снижает использование памяти при использовании движка c. Python-движок сначала загружает данные, а затем решает, какие столбцы удалить.
Общая конфигурация парсинга#
- dtypeИмя типа или словарь столбец -> тип, по умолчанию
None Тип данных для данных или столбцов. Например,
{'a': np.float64, 'b': np.int32, 'c': 'Int64'}Используйтеstrилиobjectвместе с подходящимиna_valuesнастройки для сохранения и не интерпретации dtype. Если указаны преобразователи, они будут применены ВМЕСТО преобразования dtype.Добавлено в версии 1.5.0: Добавлена поддержка defaultdict. Укажите defaultdict в качестве входных данных, где значение по умолчанию определяет dtype столбцов, которые не указаны явно.
- dtype_backend{"numpy_nullable", "pyarrow"}, по умолчанию DataFrame на основе NumPy
Какой dtype_backend использовать, например, должен ли DataFrame иметь массивы NumPy, нулевые типы данных используются для всех типов данных, которые имеют нулевую реализацию, когда установлено "numpy_nullable", pyarrow используется для всех типов данных, если установлено "pyarrow".
Параметры dtype_backends все еще являются экспериментальными.
Добавлено в версии 2.0.
- движок{
'c','python','pyarrow'} Движок парсера для использования. Движки C и pyarrow быстрее, в то время как движок python в настоящее время более полнофункционален. Многопоточность в настоящее время поддерживается только движком pyarrow.
Добавлено в версии 1.4.0: Движок "pyarrow" был добавлен как экспериментальный движок, и некоторые функции не поддерживаются или могут работать некорректно с этим движком.
- конвертерыdict, по умолчанию
None Словарь функций для преобразования значений в определенных столбцах. Ключами могут быть либо целые числа, либо метки столбцов.
- true_valuesсписка, по умолчанию
None Значения, которые следует считать как
True.- false_valuesсписка, по умолчанию
None Значения, которые следует считать как
False.- skipinitialspaceboolean, по умолчанию
False Пропускать пробелы после разделителя.
- skiprowsсписокоподобный или целое число, по умолчанию
None Номера строк для пропуска (0-индексированные) или количество строк для пропуска (int) в начале файла.
Если передана вызываемая функция, она будет применена к индексам строк, возвращая True, если строку следует пропустить, и False в противном случае:
In [6]: data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3" In [7]: pd.read_csv(StringIO(data)) Out[7]: col1 col2 col3 0 a b 1 1 a b 2 2 c d 3 In [8]: pd.read_csv(StringIO(data), skiprows=lambda x: x % 2 != 0) Out[8]: col1 col2 col3 0 a b 2
- skipfooterint, по умолчанию
0 Количество строк в конце файла, которые нужно пропустить (не поддерживается с engine='c').
- nrowsint, по умолчанию
None Количество строк файла для чтения. Полезно для чтения частей больших файлов.
- low_memoryboolean, по умолчанию
True Внутренняя обработка файла частями, что приводит к меньшему использованию памяти при парсинге, но возможно смешанное определение типов. Чтобы гарантировать отсутствие смешанных типов, установите
False, или укажите тип с помощьюdtypeпараметр. Обратите внимание, что весь файл читается в одинDataFrameнезависимо, используйтеchunksizeилиiteratorпараметр для возврата данных частями. (Действителен только с парсером C)- memory_mapboolean, по умолчанию False
Если указан путь к файлу для
filepath_or_buffer, отобразить файловый объект непосредственно в память и получать доступ к данным напрямую оттуда. Использование этой опции может улучшить производительность, поскольку больше нет накладных расходов на ввод-вывод.
Обработка NA и пропущенных данных#
- na_valuesскаляр, строка, список или словарь, по умолчанию
None Дополнительные строки для распознавания как NA/NaN. Если передан словарь, специфичные значения NA для каждого столбца. См. константа значений na ниже для списка значений, по умолчанию интерпретируемых как NaN.
- keep_default_naboolean, по умолчанию
True Включать или нет значения NaN по умолчанию при разборе данных. В зависимости от того,
na_valuesесли передано, поведение следующее:Если
keep_default_naявляетсяTrue, иna_valuesуказаны,na_valuesдобавляется к значениям NaN по умолчанию, используемым для парсинга.Если
keep_default_naявляетсяTrue, иna_valuesне указаны, только значения NaN по умолчанию используются для парсинга.Если
keep_default_naявляетсяFalse, иna_valuesуказаны, только указанные значения NaNna_valuesиспользуются для разбора.Если
keep_default_naявляетсяFalse, иna_valuesне указаны, никакие строки не будут интерпретироваться как NaN.
Обратите внимание, что если
na_filterпередается какFalse,keep_default_naиna_valuesпараметры будут проигнорированы.- na_filterboolean, по умолчанию
True Обнаружить маркеры пропущенных значений (пустые строки и значение na_values). В данных без каких-либо NA передача
na_filter=Falseможет улучшить производительность чтения большого файла.- verboseboolean, по умолчанию
False Указывает количество значений NA, размещённых в нечисловых столбцах.
- skip_blank_linesboolean, по умолчанию
True Если
True, пропускать пустые строки вместо интерпретации как значений NaN.
Обработка даты и времени#
- parse_datesboolean или список int или имена или список списков или dict, по умолчанию
False. Если
True-> попробовать разобрать индекс.Если
[1, 2, 3]-> попробуйте разобрать столбцы 1, 2, 3 каждый как отдельный столбец даты.Если
[[1, 3]]-> объединить столбцы 1 и 3 и разобрать как одну дату столбец.Если
{'foo': [1, 3]}-> разобрать столбцы 1, 3 как дату и назвать результат 'foo'.
Примечание
Существует быстрый путь для дат в формате iso8601.
- infer_datetime_formatboolean, по умолчанию
False Если
Trueигнорируется (Устарело с версии 2.0.0: Строгая версия этого аргумента теперь используется по умолчанию, передача его не имеет эффекта.
- keep_date_colboolean, по умолчанию
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) в качестве аргументов.Устарело с версии 2.0.0: Используйте
date_formatвместо этого, или считать какobjectи затем применитьto_datetime()по мере необходимости.- date_formatstr или dict столбец -> формат, по умолчанию
None Если используется вместе с
parse_dates, будет анализировать даты в соответствии с этим форматом. Для более сложных случаев, пожалуйста, читайте какobjectи затем применитьto_datetime()по мере необходимости.Добавлено в версии 2.0.0.
- dayfirstboolean, по умолчанию
False Даты в формате ДД/ММ, международный и европейский формат.
- cache_datesлогический, по умолчанию True
Если True, использует кэш уникальных преобразованных дат для применения преобразования datetime. Может дать значительное ускорение при разборе повторяющихся строк дат, особенно с часовыми поясами.
Итерация#
- итераторboolean, по умолчанию
False Возвращает
TextFileReaderобъект для итерации или получения блоков сget_chunk().- chunksizeint, по умолчанию
None Возвращает
TextFileReaderобъект для итерации. См. итерация и разбиение на блоки ниже.
Кавычки, сжатие и формат файла#
- compression{
'infer','gzip','bz2','zip','xz','zstd',None,dict}, по умолчанию'infer' Для динамической распаковки данных на диске. Если 'infer', то используйте gzip, bz2, zip, xz или zstandard, если
filepath_or_bufferявляется путем, оканчивающимся на '.gz', '.bz2', '.zip', '.xz', '.zst', соответственно, и без распаковки в противном случае. Если используется 'zip', ZIP-файл должен содержать только один файл данных для чтения. Установите вNoneдля отсутствия распаковки. Также может быть словарём с ключом'method'установлено в одно из {'zip','gzip','bz2','zstd'} и другие пары ключ-значение передаются вzipfile.ZipFile,gzip.GzipFile,bz2.BZ2File, илиzstandard.ZstdDecompressor. В качестве примера, следующее может быть передано для более быстрого сжатия и создания воспроизводимого gzip архива:compression={'method': 'gzip', 'compresslevel': 1, 'mtime': 1}.Изменено в версии 1.2.0: Предыдущие версии передавали записи словаря для 'gzip' в
gzip.open.- тысячиstr, по умолчанию
None Разделитель тысяч.
- десятичныйstr, по умолчанию
'.' Символ, распознаваемый как десятичная точка. Например, использование
','для европейских данных.- float_precisionстрока, по умолчанию None
Указывает, какой конвертер должен использовать движок C для значений с плавающей точкой. Варианты:
Noneдля обычного преобразователя,highдля высокоточного конвертера, иround_tripдля конвертера кругового обхода.- lineterminatorstr (длина 1), по умолчанию
None Символ для разбивки файла на строки. Действителен только с C-парсером.
- quotecharstr (длина 1)
Символ, используемый для обозначения начала и конца цитируемого элемента. Цитируемые элементы могут включать разделитель, и он будет проигнорирован.
- quotingint или
csv.QUOTE_*экземпляр, по умолчанию0 Управление поведением кавычек для поля на
csv.QUOTE_*константы. Используйте одну изQUOTE_MINIMAL(0),QUOTE_ALL(1),QUOTE_NONNUMERIC(2) илиQUOTE_NONE(3).- двойные кавычкиboolean, по умолчанию
True Когда
quotecharуказан иquotingне являетсяQUOTE_NONE, указывает, следует ли интерпретировать два последовательныхquotecharэлементы внутри поле как единоеquotecharэлемент.- escapecharstr (длина 1), по умолчанию
None Односимвольная строка, используемая для экранирования разделителя при цитировании,
QUOTE_NONE.- комментарийstr, по умолчанию
None Указывает, что остаток строки не должен быть проанализирован. Если найден в начале строки, строка будет полностью проигнорирована. Этот параметр должен быть одним символом. Как и пустые строки (пока
skip_blank_lines=True), полностью закомментированные строки игнорируются параметромheaderно неskiprows. Например, еслиcomment='#', разбор '#empty\na,b,c\n1,2,3' сheader=0приведет к тому, что 'a,b,c' будут рассматриваться как заголовок.- кодировкаstr, по умолчанию
None Кодировка для использования UTF при чтении/записи (например,
'utf-8'). Список стандартных кодировок Python.- диалектstr или
csv.Dialectэкземпляр, по умолчаниюNone Если предоставлен, этот параметр переопределит значения (по умолчанию или нет) для следующих параметров:
delimiter,doublequote,escapechar,skipinitialspace,quotechar, иquoting. Если необходимо переопределить значения, будет выдано ParserWarning. См.csv.Dialectдокументация для получения дополнительных сведений.
Обработка ошибок#
- on_bad_lines('error', 'warn', 'skip'), по умолчанию 'error'
Определяет, что делать при обнаружении плохой строки (строки со слишком большим количеством полей). Допустимые значения:
‘error’, вызывает ParserError при обнаружении некорректной строки.
‘warn’, выводить предупреждение при обнаружении плохой строки и пропускать эту строку.
‘skip’, пропускать плохие строки без вызова исключения или предупреждения при их обнаружении.
Добавлено в версии 1.3.0.
Указание типов данных столбцов#
Вы можете указать тип данных для всего DataFrame или отдельные
столбцы:
In [9]: import numpy as np
In [10]: data = "a,b,c,d\n1,2,3,4\n5,6,7,8\n9,10,11"
In [11]: print(data)
a,b,c,d
1,2,3,4
5,6,7,8
9,10,11
In [12]: df = pd.read_csv(StringIO(data), dtype=object)
In [13]: df
Out[13]:
a b c d
0 1 2 3 4
1 5 6 7 8
2 9 10 11 NaN
In [14]: df["a"][0]
Out[14]: '1'
In [15]: df = pd.read_csv(StringIO(data), dtype={"b": object, "c": np.float64, "d": "Int64"})
In [16]: df.dtypes
Out[16]:
a int64
b object
c float64
d Int64
dtype: object
К счастью, pandas предлагает более одного способа гарантировать, что ваш(и) столбец(ы)
содержат только один dtype. Если вы не знакомы с этими концепциями, вы можете
посмотреть здесь чтобы узнать больше о типах данных, и
здесь чтобы узнать больше о object преобразование в
pandas.
Например, вы можете использовать converters аргумент
для read_csv():
In [17]: data = "col_1\n1\n2\n'A'\n4.22"
In [18]: df = pd.read_csv(StringIO(data), converters={"col_1": str})
In [19]: df
Out[19]:
col_1
0 1
1 2
2 'A'
3 4.22
In [20]: df["col_1"].apply(type).value_counts()
Out[20]:
col_1
4
Name: count, dtype: int64
Или вы можете использовать to_numeric() функция для приведения типов данных после чтения данных,
In [21]: df2 = pd.read_csv(StringIO(data))
In [22]: df2["col_1"] = pd.to_numeric(df2["col_1"], errors="coerce")
In [23]: df2
Out[23]:
col_1
0 1.00
1 2.00
2 NaN
3 4.22
In [24]: df2["col_1"].apply(type).value_counts()
Out[24]:
col_1
4
Name: count, dtype: int64
который преобразует все допустимые парсинги во float, оставляя недопустимые парсинги как NaN.
В конечном счете, как вы обрабатываете чтение столбцов, содержащих смешанные типы данных,
зависит от ваших конкретных потребностей. В приведенном выше случае, если вы хотите NaN выявить
аномалии данных, затем to_numeric() вероятно, ваш лучший вариант.
Однако, если вы хотите, чтобы все данные были приведены, независимо от типа, тогда
использование converters аргумент read_csv() определенно стоит попробовать.
Примечание
В некоторых случаях чтение аномальных данных со столбцами, содержащими смешанные типы данных, приведет к несогласованному набору данных. Если вы полагаетесь на pandas для определения типов данных ваших столбцов, механизм парсинга будет определять типы данных для разных фрагментов данных, а не для всего набора данных сразу. Следовательно, вы можете получить столбец(ы) со смешанными типами данных. Например,
In [25]: col_1 = list(range(500000)) + ["a", "b"] + list(range(500000))
In [26]: df = pd.DataFrame({"col_1": col_1})
In [27]: df.to_csv("foo.csv")
In [28]: mixed_df = pd.read_csv("foo.csv")
In [29]: mixed_df["col_1"].apply(type).value_counts()
Out[29]:
col_1
737858
262144
Name: count, dtype: int64
In [30]: mixed_df["col_1"].dtype
Out[30]: dtype('O')
приведёт к mixed_df содержащий int dtype для определённых частей
столбца, и str для других из-за смешанных типов данных из
прочитанных данных. Важно отметить, что весь столбец будет
помечен как dtype of object, который используется для столбцов со смешанными типами данных.
Установка dtype_backend="numpy_nullable" приведет к nullable типам данных для каждого столбца.
In [31]: data = """a,b,c,d,e,f,g,h,i,j
....: 1,2.5,True,a,,,,,12-31-2019,
....: 3,4.5,False,b,6,7.5,True,a,12-31-2019,
....: """
....:
In [32]: df = pd.read_csv(StringIO(data), dtype_backend="numpy_nullable", parse_dates=["i"])
In [33]: df
Out[33]:
a b c d e f g h i j
0 1 2.5 True a 2019-12-31
1 3 4.5 False b 6 7.5 True a 2019-12-31
In [34]: df.dtypes
Out[34]:
a Int64
b Float64
c boolean
d string[python]
e Int64
f Float64
g boolean
h string[python]
i datetime64[ns]
j Int64
dtype: object
Указание категориального типа данных#
Categorical столбцы могут быть проанализированы напрямую, указав dtype='category' или
dtype=CategoricalDtype(categories, ordered).
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
Указание dtype='category' приведёт к неупорядоченному Categorical
чей categories являются уникальными значениями, наблюдаемыми в данных. Для большего
контроля над категориями и порядком создайте
CategoricalDtype заранее и передать его для столбца dtype.
In [40]: from pandas.api.types import CategoricalDtype
In [41]: dtype = CategoricalDtype(["d", "c", "b", "a"], ordered=True)
In [42]: pd.read_csv(StringIO(data), dtype={"col1": dtype}).dtypes
Out[42]:
col1 category
col2 object
col3 int64
dtype: object
При использовании dtype=CategoricalDtype, "неожиданные" значения вне
dtype.categories обрабатываются как пропущенные значения.
In [43]: dtype = CategoricalDtype(["a", "b", "d"]) # No 'c'
In [44]: pd.read_csv(StringIO(data), dtype={"col1": dtype}).col1
Out[44]:
0 a
1 a
2 NaN
Name: col1, dtype: category
Categories (3, object): ['a', 'b', 'd']
Это соответствует поведению Categorical.set_categories().
Примечание
С dtype='category', результирующие категории всегда будут анализироваться как строки (тип object). Если категории числовые, их можно преобразовать с помощью to_numeric() функция, или, если уместно, другой
конвертер, такой как to_datetime().
Когда dtype является CategoricalDtype с однородными categories (все числовые, все даты и время и т.д.), преобразование выполняется автоматически.
In [45]: df = pd.read_csv(StringIO(data), dtype="category")
In [46]: df.dtypes
Out[46]:
col1 category
col2 category
col3 category
dtype: object
In [47]: df["col3"]
Out[47]:
0 1
1 2
2 3
Name: col3, dtype: category
Categories (3, object): ['1', '2', '3']
In [48]: new_categories = pd.to_numeric(df["col3"].cat.categories)
In [49]: df["col3"] = df["col3"].cat.rename_categories(new_categories)
In [50]: df["col3"]
Out[50]:
0 1
1 2
2 3
Name: col3, dtype: category
Categories (3, int64): [1, 2, 3]
Именование и использование столбцов#
Обработка названий столбцов#
Файл может иметь или не иметь строку заголовка. pandas предполагает, что первая строка должна использоваться как имена столбцов:
In [51]: data = "a,b,c\n1,2,3\n4,5,6\n7,8,9"
In [52]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [53]: pd.read_csv(StringIO(data))
Out[53]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9
Указав names аргумент в сочетании с header вы можете
указать другие имена для использования и следует ли отбрасывать строку заголовка (если
она есть):
In [54]: print(data)
a,b,c
1,2,3
4,5,6
7,8,9
In [55]: pd.read_csv(StringIO(data), names=["foo", "bar", "baz"], header=0)
Out[55]:
foo bar baz
0 1 2 3
1 4 5 6
2 7 8 9
In [56]: pd.read_csv(StringIO(data), names=["foo", "bar", "baz"], header=None)
Out[56]:
foo bar baz
0 a b c
1 1 2 3
2 4 5 6
3 7 8 9
Если заголовок находится не в первой строке, передайте номер строки в
header. Это пропустит предшествующие строки:
In [57]: data = "skip this skip it\na,b,c\n1,2,3\n4,5,6\n7,8,9"
In [58]: pd.read_csv(StringIO(data), header=1)
Out[58]:
a b c
0 1 2 3
1 4 5 6
2 7 8 9
Примечание
Поведение по умолчанию — определение имен столбцов: если имена не
переданы, поведение идентично header=0 и имена столбцов
выводятся из первой непустой строки файла, если имена
столбцов переданы явно, то поведение идентично
header=None.
Парсинг дублирующихся имен#
Если файл или заголовок содержат повторяющиеся имена, pandas по умолчанию различает их, чтобы предотвратить перезапись данных:
In [59]: data = "a,b,a\n0,1,2\n3,4,5"
In [60]: pd.read_csv(StringIO(data))
Out[60]:
a b a.1
0 0 1 2
1 3 4 5
Дублирующихся данных больше нет, потому что дублирующиеся столбцы 'X', …, 'X' становятся 'X', 'X.1', …, 'X.N'.
Фильтрация столбцов (usecols)#
The usecols аргумент позволяет выбрать любое подмножество столбцов в
файле, используя имена столбцов, номера позиций или вызываемый объект:
In [61]: data = "a,b,c,d\n1,2,3,foo\n4,5,6,bar\n7,8,9,baz"
In [62]: pd.read_csv(StringIO(data))
Out[62]:
a b c d
0 1 2 3 foo
1 4 5 6 bar
2 7 8 9 baz
In [63]: pd.read_csv(StringIO(data), usecols=["b", "d"])
Out[63]:
b d
0 2 foo
1 5 bar
2 8 baz
In [64]: pd.read_csv(StringIO(data), usecols=[0, 2, 3])
Out[64]:
a c d
0 1 3 foo
1 4 6 bar
2 7 9 baz
In [65]: pd.read_csv(StringIO(data), usecols=lambda x: x.upper() in ["A", "C"])
Out[65]:
a c
0 1 3
1 4 6
2 7 9
The usecols аргумент также может использоваться для указания, какие столбцы не
использовать в конечном результате:
In [66]: pd.read_csv(StringIO(data), usecols=lambda x: x not in ["a", "c"])
Out[66]:
b d
0 2 foo
1 5 bar
2 8 baz
В этом случае вызываемый объект указывает, что мы исключаем столбцы "a" и "c" из вывода.
Работа с Unicode данными#
The encoding аргумент следует использовать для закодированных юникодных данных, что
приведет к декодированию байтовых строк в юникод в результате:
In [86]: from io import BytesIO
In [87]: data = b"word,length\n" b"Tr\xc3\xa4umen,7\n" b"Gr\xc3\xbc\xc3\x9fe,5"
In [88]: data = data.decode("utf8").encode("latin-1")
In [89]: df = pd.read_csv(BytesIO(data), encoding="latin-1")
In [90]: df
Out[90]:
word length
0 Träumen 7
1 Grüße 5
In [91]: df["word"][1]
Out[91]: 'Grüße'
Некоторые форматы, которые кодируют все символы как несколько байтов, например UTF-16, не будут корректно разобраны без указания кодировки. Полный список стандартных кодировок Python.
Столбцы индекса и завершающие разделители#
Если файл содержит на один столбец данных больше, чем количество имен столбцов,
первый столбец будет использоваться как DataFrameимена строк:
In [92]: data = "a,b,c\n4,apple,bat,5.7\n8,orange,cow,10"
In [93]: pd.read_csv(StringIO(data))
Out[93]:
a b c
4 apple bat 5.7
8 orange cow 10.0
In [94]: data = "index,a,b,c\n4,apple,bat,5.7\n8,orange,cow,10"
In [95]: pd.read_csv(StringIO(data), index_col=0)
Out[95]:
a b c
index
4 apple bat 5.7
8 orange cow 10.0
Обычно этого поведения можно достичь с помощью index_col опция.
Существуют некоторые исключительные случаи, когда файл был подготовлен с разделителями в
конце каждой строки данных, что сбивает парсер с толку. Чтобы явно отключить
вывод столбца индекса и отбросить последний столбец, передайте index_col=False:
In [96]: data = "a,b,c\n4,apple,bat,\n8,orange,cow,"
In [97]: print(data)
a,b,c
4,apple,bat,
8,orange,cow,
In [98]: pd.read_csv(StringIO(data))
Out[98]:
a b c
4 apple bat NaN
8 orange cow NaN
In [99]: pd.read_csv(StringIO(data), index_col=False)
Out[99]:
a b c
0 4 apple bat
1 8 orange cow
Если подмножество данных анализируется с использованием usecols опция,
index_col спецификация основана на этом подмножестве, а не на исходных данных.
In [100]: data = "a,b,c\n4,apple,bat,\n8,orange,cow,"
In [101]: print(data)
a,b,c
4,apple,bat,
8,orange,cow,
In [102]: pd.read_csv(StringIO(data), usecols=["b", "c"])
Out[102]:
b c
4 bat NaN
8 cow NaN
In [103]: pd.read_csv(StringIO(data), usecols=["b", "c"], index_col=0)
Out[103]:
b c
4 bat NaN
8 cow NaN
Обработка дат#
Указание столбцов с датами#
Для более удобной работы с данными даты и времени, read_csv()
использует ключевые аргументы parse_dates и date_format
чтобы позволить пользователям указывать различные столбцы и форматы даты/времени для преобразования
входных текстовых данных в datetime объекты.
Самый простой случай — просто передать parse_dates=True:
In [104]: with open("foo.csv", mode="w") as f:
.....: f.write("date,A,B,C\n20090101,a,1,2\n20090102,b,3,4\n20090103,c,4,5")
.....:
# Use a column as an index, and parse it as dates.
In [105]: df = pd.read_csv("foo.csv", index_col=0, parse_dates=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
# These are Python datetime objects
In [107]: df.index
Out[107]: DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], dtype='datetime64[ns]', name='date', freq=None)
Часто бывает, что мы хотим хранить дату и время отдельно или хранить различные поля даты отдельно. the parse_dates ключевое слово может быть
использовано для указания комбинации столбцов для извлечения дат и/или времени.
Вы можете указать список списков столбцов для parse_dates, результирующие столбцы дат
будут добавлены в начало вывода (чтобы не повлиять на существующий порядок
столбцов), и новые имена столбцов будут конкатенацией имен
составных столбцов:
In [108]: data = (
.....: "KORD,19990127, 19:00:00, 18:56:00, 0.8100\n"
.....: "KORD,19990127, 20:00:00, 19:56:00, 0.0100\n"
.....: "KORD,19990127, 21:00:00, 20:56:00, -0.5900\n"
.....: "KORD,19990127, 21:00:00, 21:18:00, -0.9900\n"
.....: "KORD,19990127, 22:00:00, 21:56:00, -0.5900\n"
.....: "KORD,19990127, 23:00:00, 22:56:00, -0.5900"
.....: )
.....:
In [109]: with open("tmp.csv", "w") as fh:
.....: fh.write(data)
.....:
In [110]: df = pd.read_csv("tmp.csv", header=None, parse_dates=[[1, 2], [1, 3]])
In [111]: df
Out[111]:
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 [112]: df = pd.read_csv(
.....: "tmp.csv", header=None, parse_dates=[[1, 2], [1, 3]], keep_date_col=True
.....: )
.....:
In [113]: df
Out[113]:
1_2 1_3 0 ... 2 3 4
0 1999-01-27 19:00:00 1999-01-27 18:56:00 KORD ... 19:00:00 18:56:00 0.81
1 1999-01-27 20:00:00 1999-01-27 19:56:00 KORD ... 20:00:00 19:56:00 0.01
2 1999-01-27 21:00:00 1999-01-27 20:56:00 KORD ... 21:00:00 20:56:00 -0.59
3 1999-01-27 21:00:00 1999-01-27 21:18:00 KORD ... 21:00:00 21:18:00 -0.99
4 1999-01-27 22:00:00 1999-01-27 21:56:00 KORD ... 22:00:00 21:56:00 -0.59
5 1999-01-27 23:00:00 1999-01-27 22:56:00 KORD ... 23:00:00 22:56:00 -0.59
[6 rows x 7 columns]
Обратите внимание, что если вы хотите объединить несколько столбцов в один столбец даты, должен использоваться вложенный список. Другими словами, parse_dates=[1, 2] указывает, что
второй и третий столбцы должны быть обработаны как отдельные столбцы дат,
в то время как parse_dates=[[1, 2]] означает, что два столбца должны быть разобраны в один столбец.
Вы также можете использовать словарь для указания пользовательских имен столбцов:
In [114]: date_spec = {"nominal": [1, 2], "actual": [1, 3]}
In [115]: df = pd.read_csv("tmp.csv", header=None, parse_dates=date_spec)
In [116]: df
Out[116]:
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 [117]: date_spec = {"nominal": [1, 2], "actual": [1, 3]}
In [118]: df = pd.read_csv(
.....: "tmp.csv", header=None, parse_dates=date_spec, index_col=0
.....: ) # index is the nominal column
.....:
In [119]: df
Out[119]:
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
Примечание
Если столбец или индекс содержит неразбираемую дату, весь столбец или индекс будет возвращен без изменений как тип данных object. Для нестандартного разбора даты и времени используйте to_datetime() после pd.read_csv.
Примечание
read_csv имеет быстрый путь для разбора строк даты и времени в формате iso8601, например "2000-01-01T00:01:02+00:00" и аналогичные варианты. Если вы можете организовать хранение дат и времени в ваших данных в этом формате, время загрузки будет значительно быстрее, наблюдалось ускорение ~20x.
Устарело с версии 2.2.0: Объединение столбцов дат внутри read_csv устарело. Используйте pd.to_datetime
на соответствующих результирующих столбцах.
Функции парсинга дат#
Наконец, парсер позволяет указать пользовательский date_format.
С точки зрения производительности, вы должны попробовать эти методы разбора дат в порядке:
Если вы знаете формат, используйте
date_format, например:date_format="%d/%m/%Y"илиdate_format={column_name: "%d/%m/%Y"}.Если у вас разные форматы для разных столбцов или вы хотите передать дополнительные параметры (такие как
utc) вto_datetime, тогда вам следует прочитать ваши данные какobjectdtype, а затем используйтеto_datetime.
Разбор CSV со смешанными часовыми поясами#
pandas не может нативно представлять столбец или индекс со смешанными часовыми поясами. Если ваш CSV-файл содержит столбцы со смесью часовых поясов, результат по умолчанию будет столбцом типа object со строками, даже с parse_dates.
Чтобы разобрать значения со смешанными часовыми поясами как столбец даты и времени, прочитайте как object тип данных и
затем вызвать to_datetime() с utc=True.
In [120]: content = """\
.....: a
.....: 2000-01-01T00:00:00+05:00
.....: 2000-01-01T00:00:00+06:00"""
.....:
In [121]: df = pd.read_csv(StringIO(content))
In [122]: df["a"] = pd.to_datetime(df["a"], utc=True)
In [123]: df["a"]
Out[123]:
0 1999-12-31 19:00:00+00:00
1 1999-12-31 18:00:00+00:00
Name: a, dtype: datetime64[ns, UTC]
Вывод формата даты и времени#
Вот несколько примеров строк даты и времени, которые могут быть распознаны (все представляют 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/December/2011 00:00:00”
Обратите внимание, что определение формата чувствительно к dayfirst. С
dayfirst=True, он предположит, что "01/12/2011" — это 1 декабря. С
dayfirst=False (по умолчанию) он предположит, что "01/12/2011" — это 12 января.
Если попытаться разобрать столбец строк с датами, pandas попытается угадать формат по первому не-NaN элементу, а затем разберёт остальную часть столбца с этим форматом. Если pandas не удаётся угадать формат (например, если ваша первая строка —
'01 December US/Pacific 2000'), тогда будет выдано предупреждение, и каждая строка будет проанализирована индивидуально с помощью dateutil.parser.parse. Самый безопасный
способ разбора дат — явно установить format=.
In [124]: df = pd.read_csv(
.....: "foo.csv",
.....: index_col=0,
.....: parse_dates=True,
.....: )
.....:
In [125]: df
Out[125]:
A B C
date
2009-01-01 a 1 2
2009-01-02 b 3 4
2009-01-03 c 4 5
В случае, если у вас смешанные форматы даты и времени в одном столбце, вы можете передать format='mixed'
In [126]: data = StringIO("date\n12 Jan 2000\n2000-01-13\n")
In [127]: df = pd.read_csv(data)
In [128]: df['date'] = pd.to_datetime(df['date'], format='mixed')
In [129]: df
Out[129]:
date
0 2000-01-12
1 2000-01-13
или, если все ваши форматы даты и времени соответствуют ISO8601 (возможно, не одинаково отформатированы):
In [130]: data = StringIO("date\n2020-01-01\n2020-01-01 03:00\n")
In [131]: df = pd.read_csv(data)
In [132]: df['date'] = pd.to_datetime(df['date'], format='ISO8601')
In [133]: df
Out[133]:
date
0 2020-01-01 00:00:00
1 2020-01-01 03:00:00
Международные форматы дат#
Хотя американские форматы дат обычно имеют вид ММ/ДД/ГГГГ, многие международные форматы используют
ДД/ММ/ГГГГ. Для удобства, dayfirst предоставлено ключевое слово:
In [134]: data = "date,value,cat\n1/6/2000,5,a\n2/6/2000,10,b\n3/6/2000,15,c"
In [135]: print(data)
date,value,cat
1/6/2000,5,a
2/6/2000,10,b
3/6/2000,15,c
In [136]: with open("tmp.csv", "w") as fh:
.....: fh.write(data)
.....:
In [137]: pd.read_csv("tmp.csv", parse_dates=[0])
Out[137]:
date value cat
0 2000-01-06 5 a
1 2000-02-06 10 b
2 2000-03-06 15 c
In [138]: pd.read_csv("tmp.csv", dayfirst=True, parse_dates=[0])
Out[138]:
date value cat
0 2000-06-01 5 a
1 2000-06-02 10 b
2 2000-06-03 15 c
Запись CSV в бинарные файловые объекты#
Добавлено в версии 1.2.0.
df.to_csv(..., mode="wb") позволяет записывать CSV в файловый объект,
открытый в бинарном режиме. В большинстве случаев указывать не требуется
mode поскольку Pandas автоматически определит, открыт ли файловый объект в текстовом или бинарном режиме.
In [139]: import io
In [140]: data = pd.DataFrame([0, 1, 2])
In [141]: buffer = io.BytesIO()
In [142]: data.to_csv(buffer, encoding="utf-8", compression="gzip")
Указание метода преобразования чисел с плавающей точкой#
Параметр float_precision может быть указан для использования конкретного преобразователя с плавающей запятой во время разбора с помощью C-движка. Варианты: обычный преобразователь, высокоточный преобразователь и преобразователь с гарантией обратного преобразования (который гарантирует корректное преобразование значений после записи в файл). Например:
In [143]: val = "0.3066101993807095471566981359501369297504425048828125"
In [144]: data = "a,b,c\n1,2,{0}".format(val)
In [145]: abs(
.....: pd.read_csv(
.....: StringIO(data),
.....: engine="c",
.....: float_precision=None,
.....: )["c"][0] - float(val)
.....: )
.....:
Out[145]: 5.551115123125783e-17
In [146]: abs(
.....: pd.read_csv(
.....: StringIO(data),
.....: engine="c",
.....: float_precision="high",
.....: )["c"][0] - float(val)
.....: )
.....:
Out[146]: 5.551115123125783e-17
In [147]: abs(
.....: pd.read_csv(StringIO(data), engine="c", float_precision="round_trip")["c"][0]
.....: - float(val)
.....: )
.....:
Out[147]: 0.0
Разделители тысяч#
Для больших чисел, записанных с разделителем тысяч, можно
установить thousands ключевое слово в строку длиной 1, чтобы целые числа парсились корректно:
По умолчанию числа с разделителем тысяч будут разобраны как строки:
In [148]: data = (
.....: "ID|level|category\n"
.....: "Patient1|123,000|x\n"
.....: "Patient2|23,000|y\n"
.....: "Patient3|1,234,018|z"
.....: )
.....:
In [149]: with open("tmp.csv", "w") as fh:
.....: fh.write(data)
.....:
In [150]: df = pd.read_csv("tmp.csv", sep="|")
In [151]: df
Out[151]:
ID level category
0 Patient1 123,000 x
1 Patient2 23,000 y
2 Patient3 1,234,018 z
In [152]: df.level.dtype
Out[152]: dtype('O')
The thousands ключевое слово позволяет правильно анализировать целые числа:
In [153]: df = pd.read_csv("tmp.csv", sep="|", thousands=",")
In [154]: df
Out[154]:
ID level category
0 Patient1 123000 x
1 Patient2 23000 y
2 Patient3 1234018 z
In [155]: df.level.dtype
Out[155]: dtype('int64')
значения NA#
Чтобы контролировать, какие значения парсятся как пропущенные (которые обозначаются
NaN), укажите строку в na_values. Если вы указываете список строк,
то все значения в нем считаются пропущенными. Если вы указываете
число (a float, например 5.0 или integer как 5), соответствующие эквивалентные значения также будут подразумевать отсутствующее значение (в данном случае фактически [5.0, 5] распознаются как NaN).
Чтобы полностью переопределить значения по умолчанию, которые распознаются как пропущенные, укажите keep_default_na=False.
Рассмотрим несколько примеров:
pd.read_csv("path_to_file.csv", na_values=[5])
В примере выше 5 и 5.0 будет распознан как NaN, в
дополнение к значениям по умолчанию. Строка сначала будет интерпретирована как числовая
5, затем как NaN.
pd.read_csv("path_to_file.csv", keep_default_na=False, na_values=[""])
Выше только пустое поле будет распознано как NaN.
pd.read_csv("path_to_file.csv", keep_default_na=False, na_values=["NA", "0"])
Выше оба NA и 0 поскольку строки являются NaN.
pd.read_csv("path_to_file.csv", na_values=["Nope"])
Значения по умолчанию, в дополнение к строке "Nope" распознаются как
NaN.
Бесконечность#
inf подобные значения будут разобраны как np.inf (положительная бесконечность) и -inf как -np.inf (отрицательная бесконечность).
Они будут игнорировать регистр значения, что означает Inf, также будет разобрано как np.inf.
Логические значения#
Общие значения True, False, TRUE, и FALSE все распознаются как булевы. Иногда может потребоваться распознать другие значения как булевы. Для этого используйте true_values и false_values
опции следующим образом:
In [156]: data = "a,b,c\n1,Yes,2\n3,No,4"
In [157]: print(data)
a,b,c
1,Yes,2
3,No,4
In [158]: pd.read_csv(StringIO(data))
Out[158]:
a b c
0 1 Yes 2
1 3 No 4
In [159]: pd.read_csv(StringIO(data), true_values=["Yes"], false_values=["No"])
Out[159]:
a b c
0 1 True 2
1 3 False 4
Обработка "плохих" строк#
Некоторые файлы могут содержать некорректные строки с слишком малым или слишком большим количеством полей. Строки с недостаточным количеством полей будут заполнены значениями NA в конечных полях. Строки с избыточным количеством полей по умолчанию вызовут ошибку:
In [160]: data = "a,b,c\n1,2,3\n4,5,6,7\n8,9,10"
In [161]: pd.read_csv(StringIO(data))
---------------------------------------------------------------------------
ParserError Traceback (most recent call last)
Cell In[161], line 1
----> 1 pd.read_csv(StringIO(data))
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1026, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)
1013 kwds_defaults = _refine_defaults_read(
1014 dialect,
1015 delimiter,
(...)
1022 dtype_backend=dtype_backend,
1023 )
1024 kwds.update(kwds_defaults)
-> 1026 return _read(filepath_or_buffer, kwds)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:626, in _read(filepath_or_buffer, kwds)
623 return parser
625 with parser:
--> 626 return parser.read(nrows)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1923, in TextFileReader.read(self, nrows)
1916 nrows = validate_integer("nrows", nrows)
1917 try:
1918 # error: "ParserBase" has no attribute "read"
1919 (
1920 index,
1921 columns,
1922 col_dict,
-> 1923 ) = self._engine.read( # type: ignore[attr-defined]
1924 nrows
1925 )
1926 except Exception:
1927 self.close()
File ~/work/pandas/pandas/pandas/io/parsers/c_parser_wrapper.py:234, in CParserWrapper.read(self, nrows)
232 try:
233 if self.low_memory:
--> 234 chunks = self._reader.read_low_memory(nrows)
235 # destructive to chunks
236 data = _concatenate_chunks(chunks)
File ~/work/pandas/pandas/pandas/_libs/parsers.pyx:838, in pandas._libs.parsers.TextReader.read_low_memory()
File ~/work/pandas/pandas/pandas/_libs/parsers.pyx:905, in pandas._libs.parsers.TextReader._read_rows()
File ~/work/pandas/pandas/pandas/_libs/parsers.pyx:874, in pandas._libs.parsers.TextReader._tokenize_rows()
File ~/work/pandas/pandas/pandas/_libs/parsers.pyx:891, in pandas._libs.parsers.TextReader._check_tokenize_status()
File ~/work/pandas/pandas/pandas/_libs/parsers.pyx:2061, in pandas._libs.parsers.raise_parser_error()
ParserError: Error tokenizing data. C error: Expected 3 fields in line 3, saw 4
Вы можете выбрать пропуск некорректных строк:
In [162]: data = "a,b,c\n1,2,3\n4,5,6,7\n8,9,10"
In [163]: pd.read_csv(StringIO(data), on_bad_lines="skip")
Out[163]:
a b c
0 1 2 3
1 8 9 10
Добавлено в версии 1.4.0.
Или передайте вызываемую функцию для обработки плохой строки, если engine="python".
Плохая строка будет списком строк, разделенных sep:
In [164]: external_list = []
In [165]: def bad_lines_func(line):
.....: external_list.append(line)
.....: return line[-3:]
.....:
In [166]: external_list
Out[166]: []
Примечание
Вызываемая функция будет обрабатывать только строку со слишком большим количеством полей. Плохие строки, вызванные другими ошибками, будут молча пропущены.
In [167]: bad_lines_func = lambda line: print(line)
In [168]: data = 'name,type\nname a,a is of type a\nname b,"b\" is of type b"'
In [169]: data
Out[169]: 'name,type\nname a,a is of type a\nname b,"b" is of type b"'
In [170]: pd.read_csv(StringIO(data), on_bad_lines=bad_lines_func, engine="python")
Out[170]:
name type
0 name a a is of type a
Строка не была обработана в этом случае, так как "плохая строка" здесь вызвана escape-символом.
Вы также можете использовать usecols параметр для исключения лишних данных столбцов,
которые появляются в некоторых строках, но не в других:
In [171]: pd.read_csv(StringIO(data), usecols=[0, 1, 2])
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[171], line 1
----> 1 pd.read_csv(StringIO(data), usecols=[0, 1, 2])
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1026, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)
1013 kwds_defaults = _refine_defaults_read(
1014 dialect,
1015 delimiter,
(...)
1022 dtype_backend=dtype_backend,
1023 )
1024 kwds.update(kwds_defaults)
-> 1026 return _read(filepath_or_buffer, kwds)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:620, in _read(filepath_or_buffer, kwds)
617 _validate_names(kwds.get("names", None))
619 # Create the parser.
--> 620 parser = TextFileReader(filepath_or_buffer, **kwds)
622 if chunksize or iterator:
623 return parser
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1620, in TextFileReader.__init__(self, f, engine, **kwds)
1617 self.options["has_index_names"] = kwds["has_index_names"]
1619 self.handles: IOHandles | None = None
-> 1620 self._engine = self._make_engine(f, self.engine)
File ~/work/pandas/pandas/pandas/io/parsers/readers.py:1898, in TextFileReader._make_engine(self, f, engine)
1895 raise ValueError(msg)
1897 try:
-> 1898 return mapping[engine](f, **self.options)
1899 except Exception:
1900 if self.handles is not None:
File ~/work/pandas/pandas/pandas/io/parsers/c_parser_wrapper.py:155, in CParserWrapper.__init__(self, src, **kwds)
152 # error: Cannot determine type of 'names'
153 if len(self.names) < len(usecols): # type: ignore[has-type]
154 # error: Cannot determine type of 'names'
--> 155 self._validate_usecols_names(
156 usecols,
157 self.names, # type: ignore[has-type]
158 )
160 # error: Cannot determine type of 'names'
161 self._validate_parse_dates_presence(self.names) # type: ignore[has-type]
File ~/work/pandas/pandas/pandas/io/parsers/base_parser.py:988, in ParserBase._validate_usecols_names(self, usecols, names)
986 missing = [c for c in usecols if c not in names]
987 if len(missing) > 0:
--> 988 raise ValueError(
989 f"Usecols do not match columns, columns expected but not found: "
990 f"{missing}"
991 )
993 return usecols
ValueError: Usecols do not match columns, columns expected but not found: [0, 1, 2]
Если вы хотите сохранить все данные, включая строки с слишком большим количеством полей, вы можете указать достаточное количество names. Это гарантирует, что строки с недостаточным
количеством полей будут заполнены NaN.
In [172]: pd.read_csv(StringIO(data), names=['a', 'b', 'c', 'd'])
Out[172]:
a b c d
0 name type NaN NaN
1 name a a is of type a NaN NaN
2 name b b is of type b" NaN NaN
Диалект#
The dialect ключевое слово дает большую гибкость в указании формата файла.
По умолчанию используется диалект Excel, но вы можете указать либо имя диалекта,
либо csv.Dialect экземпляр.
Предположим, у вас были данные с незакрытыми кавычками:
In [173]: data = "label1,label2,label3\n" 'index1,"a,c,e\n' "index2,b,d,f"
In [174]: print(data)
label1,label2,label3
index1,"a,c,e
index2,b,d,f
По умолчанию, read_csv использует диалект Excel и рассматривает двойные кавычки как
символ кавычки, что приводит к сбою, когда он находит новую строку до того,
как найдет закрывающую двойную кавычку.
Мы можем обойти это, используя dialect:
In [175]: import csv
In [176]: dia = csv.excel()
In [177]: dia.quoting = csv.QUOTE_NONE
In [178]: pd.read_csv(StringIO(data), dialect=dia)
Out[178]:
label1 label2 label3
index1 "a c e
index2 b d f
Все параметры диалекта могут быть указаны отдельно ключевыми аргументами:
In [179]: data = "a,b,c~1,2,3~4,5,6"
In [180]: pd.read_csv(StringIO(data), lineterminator="~")
Out[180]:
a b c
0 1 2 3
1 4 5 6
Ещё одна распространённая опция диалекта — skipinitialspace, чтобы пропустить любой пробел
после разделителя:
In [181]: data = "a, b, c\n1, 2, 3\n4, 5, 6"
In [182]: print(data)
a, b, c
1, 2, 3
4, 5, 6
In [183]: pd.read_csv(StringIO(data), skipinitialspace=True)
Out[183]:
a b c
0 1 2 3
1 4 5 6
Парсеры стараются "поступать правильно" и не быть хрупкими. Вывод типа данных — довольно важная задача. Если столбец можно преобразовать в целочисленный тип данных без изменения содержимого, парсер сделает это. Любые нечисловые столбцы будут переданы как тип object, как и остальные объекты pandas.
Кавычки и экранирующие символы#
Кавычки (и другие escape-символы) во встроенных полях могут обрабатываться различными
способами. Один из способов — использовать обратные слеши; для правильного разбора этих данных вы
должны передать escapechar опция:
In [184]: data = 'a,b\n"hello, \\"Bob\\", nice to see you",5'
In [185]: print(data)
a,b
"hello, \"Bob\", nice to see you",5
In [186]: pd.read_csv(StringIO(data), escapechar="\\")
Out[186]:
a b
0 hello, "Bob", nice to see you 5
Файлы с колонками фиксированной ширины#
В то время как read_csv() читает разделённые данные, то read_fwf() pandas.tseries.offsets.WeekOfMonth.is_anchored read_fwf в основном такие же, как read_csv с двумя дополнительными параметрами и
другим использованием delimiter параметр:
colspecs: Список пар (кортежей), задающих границы полей фиксированной ширины каждой строки как полуоткрытые интервалы (т.е., [от, до[). Строковое значение 'infer' можно использовать, чтобы указать парсеру попытаться определить спецификации столбцов из первых 100 строк данных. Поведение по умолчанию, если не указано, — определение.widths: Список ширины полей, который можно использовать вместо 'colspecs', если интервалы непрерывны.delimiter: Символы, которые следует считать заполняющими символами в файле фиксированной ширины. Могут использоваться для указания заполняющего символа полей, если это не пробелы (например, '~').
Рассмотрим типичный файл данных фиксированной ширины:
In [187]: data1 = (
.....: "id8141 360.242940 149.910199 11950.7\n"
.....: "id1594 444.953632 166.985655 11788.4\n"
.....: "id1849 364.136849 183.628767 11806.2\n"
.....: "id1230 413.836124 184.375703 11916.8\n"
.....: "id1948 502.953953 173.237159 12468.3"
.....: )
.....:
In [188]: with open("bar.csv", "w") as f:
.....: f.write(data1)
.....:
Чтобы разобрать этот файл в DataFrame, нам просто нужно предоставить спецификации колонок в read_fwf функция вместе с именем файла:
# Column specifications are a list of half-intervals
In [189]: colspecs = [(0, 6), (8, 20), (21, 33), (34, 43)]
In [190]: df = pd.read_fwf("bar.csv", colspecs=colspecs, header=None, index_col=0)
In [191]: df
Out[191]:
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 [192]: widths = [6, 14, 13, 10]
In [193]: df = pd.read_fwf("bar.csv", widths=widths, header=None)
In [194]: df
Out[194]:
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
Парсер сам обработает лишние пробелы вокруг столбцов, поэтому наличие дополнительного разделения между столбцами в файле допустимо.
По умолчанию, read_fwf попытается определить colspecs используя первые 100 строк файла. Это можно сделать только в случаях, когда столбцы выровнены и правильно разделены предоставленным delimiter (разделитель по умолчанию
является пробелом).
In [195]: df = pd.read_fwf("bar.csv", header=None, index_col=0)
In [196]: df
Out[196]:
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
read_fwf поддерживает dtype параметр для указания типов разобранных столбцов, отличных от выведенного типа.
In [197]: pd.read_fwf("bar.csv", header=None, index_col=0).dtypes
Out[197]:
1 float64
2 float64
3 float64
dtype: object
In [198]: pd.read_fwf("bar.csv", header=None, dtype={2: "object"}).dtypes
Out[198]:
0 object
1 float64
2 object
3 float64
dtype: object
Индексы#
Файлы с 'неявным' индексным столбцом#
Рассмотрим файл с одним элементом меньше в заголовке, чем количество столбцов данных:
In [199]: data = "A,B,C\n20090101,a,1,2\n20090102,b,3,4\n20090103,c,4,5"
In [200]: print(data)
A,B,C
20090101,a,1,2
20090102,b,3,4
20090103,c,4,5
In [201]: with open("foo.csv", "w") as f:
.....: f.write(data)
.....:
В этом особом случае, read_csv предполагает, что первый столбец должен использоваться
в качестве индекса DataFrame:
In [202]: pd.read_csv("foo.csv")
Out[202]:
A B C
20090101 a 1 2
20090102 b 3 4
20090103 c 4 5
Обратите внимание, что даты не были автоматически разобраны. В этом случае вам нужно сделать, как раньше:
In [203]: df = pd.read_csv("foo.csv", parse_dates=True)
In [204]: df.index
Out[204]: DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], dtype='datetime64[ns]', freq=None)
Чтение индекса с MultiIndex#
Предположим, у вас есть данные, индексированные двумя столбцами:
In [205]: data = 'year,indiv,zit,xit\n1977,"A",1.2,.6\n1977,"B",1.5,.5'
In [206]: print(data)
year,indiv,zit,xit
1977,"A",1.2,.6
1977,"B",1.5,.5
In [207]: with open("mindex_ex.csv", mode="w") as f:
.....: f.write(data)
.....:
The index_col аргумент для read_csv может принимать список
номеров столбцов для преобразования нескольких столбцов в MultiIndex для индекса
возвращаемого объекта:
In [208]: df = pd.read_csv("mindex_ex.csv", index_col=[0, 1])
In [209]: df
Out[209]:
zit xit
year indiv
1977 A 1.2 0.6
B 1.5 0.5
In [210]: df.loc[1977]
Out[210]:
zit xit
indiv
A 1.2 0.6
B 1.5 0.5
Чтение столбцов с MultiIndex#
Указав список позиций строк для header аргумент, вы
можете прочитать в MultiIndex для столбцов. Указание несмежных
строк пропустит промежуточные строки.
In [211]: mi_idx = pd.MultiIndex.from_arrays([[1, 2, 3, 4], list("abcd")], names=list("ab"))
In [212]: mi_col = pd.MultiIndex.from_arrays([[1, 2], list("ab")], names=list("cd"))
In [213]: df = pd.DataFrame(np.ones((4, 2)), index=mi_idx, columns=mi_col)
In [214]: df.to_csv("mi.csv")
In [215]: print(open("mi.csv").read())
c,,1,2
d,,a,b
a,b,,
1,a,1.0,1.0
2,b,1.0,1.0
3,c,1.0,1.0
4,d,1.0,1.0
In [216]: pd.read_csv("mi.csv", header=[0, 1, 2, 3], index_col=[0, 1])
Out[216]:
c 1 2
d a b
a Unnamed: 2_level_2 Unnamed: 3_level_2
1 1.0 1.0
2 b 1.0 1.0
3 c 1.0 1.0
4 d 1.0 1.0
read_csv также может интерпретировать более распространенный формат
многоколоночных индексов.
In [217]: data = ",a,a,a,b,c,c\n,q,r,s,t,u,v\none,1,2,3,4,5,6\ntwo,7,8,9,10,11,12"
In [218]: print(data)
,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 [219]: with open("mi2.csv", "w") as fh:
.....: fh.write(data)
.....:
In [220]: pd.read_csv("mi2.csv", header=[0, 1], index_col=0)
Out[220]:
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 [221]: df = pd.DataFrame(np.random.randn(10, 4))
In [222]: df.to_csv("tmp2.csv", sep=":", index=False)
In [223]: pd.read_csv("tmp2.csv", sep=None, engine="python")
Out[223]:
0 1 2 3
0 0.469112 -0.282863 -1.509059 -1.135632
1 1.212112 -0.173215 0.119209 -1.044236
2 -0.861849 -2.104569 -0.494929 1.071804
3 0.721555 -0.706771 -1.039575 0.271860
4 -0.424972 0.567020 0.276232 -1.087401
5 -0.673690 0.113648 -1.478427 0.524988
6 0.404705 0.577046 -1.715002 -1.039268
7 -0.370647 -1.157892 -1.344312 0.844885
8 1.075770 -0.109050 1.643563 -1.469388
9 0.357021 -0.674600 -1.776904 -0.968914
Чтение нескольких файлов для создания одного DataFrame#
Лучше использовать concat() для объединения нескольких файлов.
См. cookbook для примера.
Итерация по файлам по частям#
Предположим, вы хотите лениво итерироваться по (потенциально очень большому) файлу, а не читать весь файл в память, как в следующем примере:
In [224]: df = pd.DataFrame(np.random.randn(10, 4))
In [225]: df.to_csv("tmp.csv", index=False)
In [226]: table = pd.read_csv("tmp.csv")
In [227]: table
Out[227]:
0 1 2 3
0 -1.294524 0.413738 0.276662 -0.472035
1 -0.013960 -0.362543 -0.006154 -0.923061
2 0.895717 0.805244 -1.206412 2.565646
3 1.431256 1.340309 -1.170299 -0.226169
4 0.410835 0.813850 0.132003 -0.827317
5 -0.076467 -1.187678 1.130127 -1.436737
6 -1.413681 1.607920 1.024180 0.569605
7 0.875906 -2.211372 0.974466 -2.006747
8 -0.410001 -0.078638 0.545952 -1.219217
9 -1.226825 0.769804 -1.281247 -0.727707
Указав chunksize to read_csv, возвращаемое значение будет итерируемым объектом типа TextFileReader:
In [228]: with pd.read_csv("tmp.csv", chunksize=4) as reader:
.....: print(reader)
.....: for chunk in reader:
.....: print(chunk)
.....:
0 1 2 3
0 -1.294524 0.413738 0.276662 -0.472035
1 -0.013960 -0.362543 -0.006154 -0.923061
2 0.895717 0.805244 -1.206412 2.565646
3 1.431256 1.340309 -1.170299 -0.226169
0 1 2 3
4 0.410835 0.813850 0.132003 -0.827317
5 -0.076467 -1.187678 1.130127 -1.436737
6 -1.413681 1.607920 1.024180 0.569605
7 0.875906 -2.211372 0.974466 -2.006747
0 1 2 3
8 -0.410001 -0.078638 0.545952 -1.219217
9 -1.226825 0.769804 -1.281247 -0.727707
Изменено в версии 1.2: read_csv/json/sas возвращает контекстный менеджер при итерации по файлу.
Указание iterator=True также вернет TextFileReader объект:
In [229]: with pd.read_csv("tmp.csv", iterator=True) as reader:
.....: print(reader.get_chunk(5))
.....:
0 1 2 3
0 -1.294524 0.413738 0.276662 -0.472035
1 -0.013960 -0.362543 -0.006154 -0.923061
2 0.895717 0.805244 -1.206412 2.565646
3 1.431256 1.340309 -1.170299 -0.226169
4 0.410835 0.813850 0.132003 -0.827317
Указание парсера#
Pandas в настоящее время поддерживает три движка: C-движок, python-движок и экспериментальный
pyarrow-движок (требует pyarrow пакет). В целом, движок pyarrow самый быстрый на больших нагрузках и эквивалентен по скорости движку C на большинстве других нагрузок. Движок python, как правило, медленнее, чем pyarrow и C на большинстве нагрузок. Однако, движок pyarrow гораздо менее надёжен, чем движок C, который имеет меньше функций по сравнению с движком Python.
По возможности, pandas использует C-парсер (указанный как engine='c'), но может
вернуться к Python, если указаны неподдерживаемые C опции.
В настоящее время параметры, не поддерживаемые движками C и pyarrow, включают:
sepотличный от одного символа (например, разделители regex)skipfootersep=Noneсdelim_whitespace=False
Указание любого из вышеперечисленных параметров приведет к созданию ParserWarning если только
движок python не выбран явно с помощью engine='python'.
Параметры, неподдерживаемые движком pyarrow, которые не охвачены списком выше, включают:
float_precisionchunksizecommentnrowsthousandsmemory_mapdialecton_bad_linesdelim_whitespacequotinglineterminatorconvertersdecimaliteratordayfirstinfer_datetime_formatverboseskipinitialspacelow_memory
Указание этих опций с engine='pyarrow' вызовет ValueError.
Чтение/запись удаленных файлов#
Вы можете передать URL для чтения или записи удаленных файлов во многие функции ввода-вывода pandas - следующий пример показывает чтение CSV файла:
df = pd.read_csv("https://download.bls.gov/pub/time.series/cu/cu.item", sep="\t")
Добавлено в версии 1.3.0.
Пользовательский заголовок может быть отправлен вместе с HTTP(s) запросами, передавая словарь
сопоставлений ключ-значение заголовка в storage_options аргумент ключевого слова, как показано ниже:
headers = {"User-Agent": "pandas"}
df = pd.read_csv(
"https://download.bls.gov/pub/time.series/cu/cu.item",
sep="\t",
storage_options=headers
)
Все URL-адреса, которые не являются локальными файлами или HTTP(s), обрабатываются fsspec, если установлен, и его различные реализации файловой системы (включая Amazon S3, Google Cloud, SSH, FTP, webHDFS…). Некоторые из этих реализаций потребуют установки дополнительных пакетов, например, URL-адреса S3 требуют s3fs библиотека:
df = pd.read_json("s3://pandas-test/adatafile.json")
При работе с удаленными системами хранения данных может потребоваться дополнительная настройка с использованием переменных окружения или конфигурационных файлов в специальных местах. Например, для доступа к данным в вашем S3-бакете потребуется определить учетные данные одним из нескольких способов, перечисленных в Документация S3Fs. То же самое верно
для нескольких бэкендов хранения, и вы должны перейти по ссылкам
на fsimpl1 для встроенных реализаций fsspec и fsimpl2
для тех, кто не включен в основной fsspec
распределение.
Вы также можете передавать параметры напрямую драйверу бэкенда. Поскольку fsspec не
использует AWS_S3_HOST переменную окружения, мы можем напрямую определить словарь, содержащий endpoint_url, и передать объект в параметр storage option:
storage_options = {"client_kwargs": {"endpoint_url": "http://127.0.0.1:5555"}}}
df = pd.read_json("s3://pandas-test/test-1", storage_options=storage_options)
Дополнительные примеры конфигураций и документацию можно найти на Документация S3Fs.
Если вы делаете не имея учетные данные S3, вы все равно можете получить доступ к публичным данным, указав анонимное соединение, например
Добавлено в версии 1.2.0.
pd.read_csv(
"s3://ncei-wcsd-archive/data/processed/SH1305/18kHz/SaKe2013"
"-D20130523-T080854_to_SaKe2013-D20130523-T085643.csv",
storage_options={"anon": True},
)
fsspec также позволяет использовать сложные URL-адреса для доступа к данным в сжатых
архивах, локального кэширования файлов и многого другого. Чтобы локально кэшировать приведенный выше
пример, вы должны изменить вызов на
pd.read_csv(
"simplecache::s3://ncei-wcsd-archive/data/processed/SH1305/18kHz/"
"SaKe2013-D20130523-T080854_to_SaKe2013-D20130523-T085643.csv",
storage_options={"s3": {"anon": True}},
)
где мы указываем, что параметр "anon" предназначен для части "s3" реализации, а не для реализации кэширования. Обратите внимание, что это кэширует во временный каталог только на время сеанса, но вы также можете указать постоянное хранилище.
Запись данных#
Запись в формате CSV#
The Series и DataFrame объекты имеют метод экземпляра to_csv который
позволяет сохранять содержимое объекта в виде файла с разделителями-запятыми. Функция
принимает несколько аргументов. Только первый является обязательным.
path_or_buf: Строковый путь к файлу для записи или файловый объект. Если это файловый объект, он должен быть открыт сnewline=''sep: Разделитель полей для выходного файла (по умолчанию “,”)na_rep: Строковое представление пропущенного значения (по умолчанию '')float_format: Строка формата для чисел с плавающей точкойcolumns: Столбцы для записи (по умолчанию None)header: Следует ли выводить имена столбцов (по умолчанию True)index: записывать ли имена строк (индекса) (по умолчанию True)index_label: Метка(и) столбца для столбца(ов) индекса, если требуется. Если None (по умолчанию), иheaderиindexравны True, тогда используются имена индексов. (Последовательность должна быть задана, еслиDataFrameиспользует MultiIndex).mode: режим записи Python, по умолчанию ‘w’encoding: строка, представляющая кодировку для использования, если содержимое не ASCII, для версий Python до 3lineterminator: Последовательность символов, обозначающая конец строки (по умолчаниюos.linesep)quoting: Установите правила кавычек как в модуле csv (по умолчанию csv.QUOTE_MINIMAL). Обратите внимание, что если вы установилиfloat_formatзатем числа с плавающей точкой преобразуются в строки и csv.QUOTE_NONNUMERIC будет рассматривать их как нечисловыеquotechar: Символ, используемый для цитирования полей (по умолчанию '"')doublequote: Управление кавычками дляquotecharв полях (по умолчанию True)escapechar: Символ, используемый для экранированияsepиquotecharкогда уместно (по умолчанию None)chunksize: Количество строк для записи за разdate_format: Строка формата для объектов datetime
Запись форматированной строки#
The DataFrame объект имеет метод экземпляра to_string которая позволяет контролировать строковое представление объекта. Все аргументы необязательны:
bufпо умолчанию None, например, объект StringIOcolumnsпо умолчанию None, какие столбцы записыватьcol_spaceпо умолчанию None, минимальная ширина каждого столбца.na_repпо умолчаниюNaN, представление значения NAformattersпо умолчанию None, словарь (по столбцам) функций, каждая из которых принимает один аргумент и возвращает форматированную строкуfloat_formatпо умолчанию None, функция, которая принимает один (float) аргумент и возвращает форматированную строку; применяется к числам с плавающей точкой вDataFrame.sparsifyпо умолчанию True, установите False дляDataFrameс иерархическим индексом для вывода каждого ключа MultiIndex в каждой строке.index_namesпо умолчанию True, будет выводить имена индексовindexпо умолчанию True, будет выводить индекс (т.е. метки строк)headerпо умолчанию True, будет печатать метки столбцовjustifyпо умолчаниюleft, будет печатать заголовки колонок выровненными по левому или правому краю
The Series объект также имеет to_string метод, но только с buf,
na_rep, float_format аргументы. Также есть length аргумент
который, если установлен в True, также будет выводить длину Series.
JSON#
Чтение и запись JSON форматировать файлы и строки.
Запись JSON#
A Series или DataFrame может быть преобразован в допустимую строку JSON. Используйте to_json
с необязательными параметрами:
path_or_buf: путь или буфер для записи вывода. Это может бытьNoneв этом случае возвращается строка JSON.orient:Series:по умолчанию
indexдопустимые значения: {
split,records,index}
DataFrame:по умолчанию
columnsдопустимые значения: {
split,records,index,columns,values,table}
Формат строки JSON
splitсловарь вида {index -> [index]; columns -> [columns]; data -> [values]}
recordsсписок вида [{column -> value}; … ]
indexсловарь вида {индекс -> {столбец -> значение}}
columnsсловарь вида {столбец -> {индекс -> значение}}
valuesтолько массив значений
tableсоблюдая JSON Схема таблицы
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ориентация, затем будет записывать каждую запись в строку как json.mode: строка, режим записи при записи в путь. 'w' для записи, 'a' для добавления. По умолчанию 'w'
Примечание NaN's, NaTи None будет преобразовано в null и datetime объекты будут преобразованы на основе date_format и date_unit параметры.
In [230]: dfj = pd.DataFrame(np.random.randn(5, 2), columns=list("AB"))
In [231]: json = dfj.to_json()
In [232]: json
Out[232]: '{"A":{"0":-0.1213062281,"1":0.6957746499,"2":0.9597255933,"3":-0.6199759194,"4":-0.7323393705},"B":{"0":-0.0978826728,"1":0.3417343559,"2":-1.1103361029,"3":0.1497483186,"4":0.6877383895}}'
Параметры ориентации#
Существует несколько различных вариантов формата результирующего JSON-файла / строки. Рассмотрим следующие DataFrame и Series:
In [233]: dfjo = pd.DataFrame(
.....: dict(A=range(1, 4), B=range(4, 7), C=range(7, 10)),
.....: columns=list("ABC"),
.....: index=list("xyz"),
.....: )
.....:
In [234]: dfjo
Out[234]:
A B C
x 1 4 7
y 2 5 8
z 3 6 9
In [235]: sjo = pd.Series(dict(x=15, y=16, z=17), name="D")
In [236]: sjo
Out[236]:
x 15
y 16
z 17
Name: D, dtype: int64
Ориентированный на столбцы (по умолчанию для DataFrame) сериализует данные как вложенные объекты JSON с метками столбцов в качестве основного индекса:
In [237]: dfjo.to_json(orient="columns")
Out[237]: '{"A":{"x":1,"y":2,"z":3},"B":{"x":4,"y":5,"z":6},"C":{"x":7,"y":8,"z":9}}'
# Not available for Series
Ориентированный на индекс (по умолчанию для Series) аналогично ориентированному на столбцы
но метки индекса теперь являются основными:
In [238]: dfjo.to_json(orient="index")
Out[238]: '{"x":{"A":1,"B":4,"C":7},"y":{"A":2,"B":5,"C":8},"z":{"A":3,"B":6,"C":9}}'
In [239]: sjo.to_json(orient="index")
Out[239]: '{"x":15,"y":16,"z":17}'
Ориентированный на записи сериализует данные в JSON-массив записей столбец -> значение,
метки индекса не включаются. Это полезно для передачи DataFrame данные для библиотек построения графиков
, например, библиотека JavaScript d3.js:
In [240]: dfjo.to_json(orient="records")
Out[240]: '[{"A":1,"B":4,"C":7},{"A":2,"B":5,"C":8},{"A":3,"B":6,"C":9}]'
In [241]: sjo.to_json(orient="records")
Out[241]: '[15,16,17]'
Ориентированный на значения является базовым вариантом, который сериализует во вложенные JSON-массивы только значений, метки столбцов и индексов не включаются:
In [242]: dfjo.to_json(orient="values")
Out[242]: '[[1,4,7],[2,5,8],[3,6,9]]'
# Not available for Series
Ориентированный на разделение сериализуется в объект JSON, содержащий отдельные записи для значений, индекса и столбцов. Имя также включено для Series:
In [243]: dfjo.to_json(orient="split")
Out[243]: '{"columns":["A","B","C"],"index":["x","y","z"],"data":[[1,4,7],[2,5,8],[3,6,9]]}'
In [244]: sjo.to_json(orient="split")
Out[244]: '{"name":"D","index":["x","y","z"],"data":[15,16,17]}'
Ориентированный на таблицы сериализуется в JSON Схема таблицы, позволяя сохранять метаданные, включая, но не ограничиваясь, типы данных и имена индексов.
Примечание
Любой параметр ориентации, который кодируется в объект JSON, не сохранит порядок
индекса и меток столбцов при сериализации туда и обратно. Если вы хотите сохранить
порядок меток, используйте split опция, так как использует упорядоченные контейнеры.
Обработка дат#
Запись в формате даты ISO:
In [245]: dfd = pd.DataFrame(np.random.randn(5, 2), columns=list("AB"))
In [246]: dfd["date"] = pd.Timestamp("20130101")
In [247]: dfd = dfd.sort_index(axis=1, ascending=False)
In [248]: json = dfd.to_json(date_format="iso")
In [249]: json
Out[249]: '{"date":{"0":"2013-01-01T00:00:00.000","1":"2013-01-01T00:00:00.000","2":"2013-01-01T00:00:00.000","3":"2013-01-01T00:00:00.000","4":"2013-01-01T00:00:00.000"},"B":{"0":0.403309524,"1":0.3016244523,"2":-1.3698493577,"3":1.4626960492,"4":-0.8265909164},"A":{"0":0.1764443426,"1":-0.1549507744,"2":-2.1798606054,"3":-0.9542078401,"4":-1.7431609117}}'
Запись в формате даты ISO с микросекундами:
In [250]: json = dfd.to_json(date_format="iso", date_unit="us")
In [251]: json
Out[251]: '{"date":{"0":"2013-01-01T00:00:00.000000","1":"2013-01-01T00:00:00.000000","2":"2013-01-01T00:00:00.000000","3":"2013-01-01T00:00:00.000000","4":"2013-01-01T00:00:00.000000"},"B":{"0":0.403309524,"1":0.3016244523,"2":-1.3698493577,"3":1.4626960492,"4":-0.8265909164},"A":{"0":0.1764443426,"1":-0.1549507744,"2":-2.1798606054,"3":-0.9542078401,"4":-1.7431609117}}'
Метки времени эпохи, в секундах:
In [252]: json = dfd.to_json(date_format="epoch", date_unit="s")
In [253]: json
Out[253]: '{"date":{"0":1,"1":1,"2":1,"3":1,"4":1},"B":{"0":0.403309524,"1":0.3016244523,"2":-1.3698493577,"3":1.4626960492,"4":-0.8265909164},"A":{"0":0.1764443426,"1":-0.1549507744,"2":-2.1798606054,"3":-0.9542078401,"4":-1.7431609117}}'
Запись в файл с индексом даты и столбцом даты:
In [254]: dfj2 = dfj.copy()
In [255]: dfj2["date"] = pd.Timestamp("20130101")
In [256]: dfj2["ints"] = list(range(5))
In [257]: dfj2["bools"] = True
In [258]: dfj2.index = pd.date_range("20130101", periods=5)
In [259]: dfj2.to_json("test.json")
In [260]: with open("test.json") as fh:
.....: print(fh.read())
.....:
{"A":{"1356998400000":-0.1213062281,"1357084800000":0.6957746499,"1357171200000":0.9597255933,"1357257600000":-0.6199759194,"1357344000000":-0.7323393705},"B":{"1356998400000":-0.0978826728,"1357084800000":0.3417343559,"1357171200000":-1.1103361029,"1357257600000":0.1497483186,"1357344000000":0.6877383895},"date":{"1356998400000":1356,"1357084800000":1356,"1357171200000":1356,"1357257600000":1356,"1357344000000":1356},"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метод и вызвать его. AtoDictметод должен возвращать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 [261]: pd.DataFrame([1.0, 2.0, complex(1.0, 2.0)]).to_json(default_handler=str)
Out[261]: '{"0":{"0":"(1+0j)","1":"(2+0j)","2":"(1+2j)"}}'
Чтение JSON#
Чтение строки JSON в объект pandas может принимать ряд параметров.
Парсер попытается разобрать DataFrame if typ не предоставлен или является None. Чтобы явно принудительно Series при разборе, передайте typ=series
filepath_or_buffer: a VALID Строка JSON или файловый дескриптор / StringIO. Строка может быть URL. Допустимые схемы URL включают http, ftp, S3 и file. Для URL файлов ожидается хост. Например, локальный файл может быть file://localhost/path/to/table.jsontyp: тип объекта для восстановления (series или frame), по умолчанию ‘frame’orient:- Series :
по умолчанию
indexдопустимые значения: {
split,records,index}
- DataFrame
по умолчанию
columnsдопустимые значения: {
split,records,index,columns,values,table}
Формат строки JSON
splitсловарь вида {index -> [index]; columns -> [columns]; data -> [values]}
recordsсписок вида [{column -> value} …]
indexсловарь вида {индекс -> {столбец -> значение}}
columnsсловарь вида {столбец -> {индекс -> значение}}
valuesтолько массив значений
tableсоблюдая JSON Схема таблицы
dtype: если True, выводить типы данных; если словарь столбца к типу данных, то использовать их; еслиFalse, тогда не выводить типы данных вообще, по умолчанию True, применяется только к данным.convert_axes: boolean, попытаться преобразовать оси к правильным типам данных, по умолчаниюTrueconvert_dates: список столбцов для разбора дат; еслиTrue, затем попытаться разобрать столбцы с датами, по умолчаниюTrue.keep_default_dates: boolean, по умолчаниюTrue. Если парсинг дат, то парсить столбцы с датами по умолчанию.precise_float: boolean, по умолчаниюFalse. Установите для использования функции более высокой точности (strtod) при декодировании строки в значения double. По умолчанию (False) заключается в использовании быстрой, но менее точной встроенной функциональности.date_unit: строка, единица времени для определения при конвертации дат. По умолчанию None. По умолчанию будет определена точность временной метки, если это нежелательно, то передайте одно из значений 's', 'ms', 'us' или 'ns' для принудительной установки точности временной метки в секунды, миллисекунды, микросекунды или наносекунды соответственно.lines: читает файл как один объект JSON на строку.encoding: Кодировка, используемая для декодирования байтов py3.chunksize: при использовании в сочетании сlines=True, возвращаетpandas.api.typing.JsonReaderкоторый читаетchunksizeстрок за итерацию.engine: Либо"ujson", встроенный парсер JSON, или"pyarrow"который передается в pyarrowpyarrow.json.read_json."pyarrow"доступно только когдаlines=True
Парсер вызовет один из ValueError/TypeError/AssertionError если JSON не может быть разобран.
Если не по умолчанию orient использовался при кодировании в JSON, обязательно передайте ту же
опцию здесь, чтобы декодирование давало разумные результаты, см. Параметры ориентации для обзора.
Преобразование данных#
Значение по умолчанию для 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 [262]: from io import StringIO
In [263]: pd.read_json(StringIO(json))
Out[263]:
date B A
0 1 0.403310 0.176444
1 1 0.301624 -0.154951
2 1 -1.369849 -2.179861
3 1 1.462696 -0.954208
4 1 -0.826591 -1.743161
Чтение из файла:
In [264]: pd.read_json("test.json")
Out[264]:
A B date ints bools
2013-01-01 -0.121306 -0.097883 1356 0 True
2013-01-02 0.695775 0.341734 1356 1 True
2013-01-03 0.959726 -1.110336 1356 2 True
2013-01-04 -0.619976 0.149748 1356 3 True
2013-01-05 -0.732339 0.687738 1356 4 True
Не преобразовывать никакие данные (но всё равно преобразовывать оси и даты):
In [265]: pd.read_json("test.json", dtype=object).dtypes
Out[265]:
A object
B object
date object
ints object
bools object
dtype: object
Указать типы данных для преобразования:
In [266]: pd.read_json("test.json", dtype={"A": "float32", "bools": "int8"}).dtypes
Out[266]:
A float32
B float64
date int64
ints int64
bools int8
dtype: object
Сохранять строковые индексы:
In [267]: from io import StringIO
In [268]: si = pd.DataFrame(
.....: np.zeros((4, 4)), columns=list(range(4)), index=[str(i) for i in range(4)]
.....: )
.....:
In [269]: si
Out[269]:
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 [270]: si.index
Out[270]: Index(['0', '1', '2', '3'], dtype='object')
In [271]: si.columns
Out[271]: Index([0, 1, 2, 3], dtype='int64')
In [272]: json = si.to_json()
In [273]: sij = pd.read_json(StringIO(json), convert_axes=False)
In [274]: sij
Out[274]:
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 [275]: sij.index
Out[275]: Index(['0', '1', '2', '3'], dtype='object')
In [276]: sij.columns
Out[276]: Index(['0', '1', '2', '3'], dtype='object')
Даты, записанные в наносекундах, должны считываться в наносекундах:
In [277]: from io import StringIO
In [278]: json = dfj2.to_json(date_unit="ns")
# Try to parse timestamps as milliseconds -> Won't Work
In [279]: dfju = pd.read_json(StringIO(json), date_unit="ms")
In [280]: dfju
Out[280]:
A B date ints bools
1356998400000000000 -0.121306 -0.097883 1356998400 0 True
1357084800000000000 0.695775 0.341734 1356998400 1 True
1357171200000000000 0.959726 -1.110336 1356998400 2 True
1357257600000000000 -0.619976 0.149748 1356998400 3 True
1357344000000000000 -0.732339 0.687738 1356998400 4 True
# Let pandas detect the correct precision
In [281]: dfju = pd.read_json(StringIO(json))
In [282]: dfju
Out[282]:
A B date ints bools
2013-01-01 -0.121306 -0.097883 2013-01-01 0 True
2013-01-02 0.695775 0.341734 2013-01-01 1 True
2013-01-03 0.959726 -1.110336 2013-01-01 2 True
2013-01-04 -0.619976 0.149748 2013-01-01 3 True
2013-01-05 -0.732339 0.687738 2013-01-01 4 True
# Or specify that all timestamps are in nanoseconds
In [283]: dfju = pd.read_json(StringIO(json), date_unit="ns")
In [284]: dfju
Out[284]:
A B date ints bools
2013-01-01 -0.121306 -0.097883 1356998400 0 True
2013-01-02 0.695775 0.341734 1356998400 1 True
2013-01-03 0.959726 -1.110336 1356998400 2 True
2013-01-04 -0.619976 0.149748 1356998400 3 True
2013-01-05 -0.732339 0.687738 1356998400 4 True
Установкой dtype_backend аргумент позволяет управлять типами данных по умолчанию для результирующего DataFrame.
In [285]: data = (
.....: '{"a":{"0":1,"1":3},"b":{"0":2.5,"1":4.5},"c":{"0":true,"1":false},"d":{"0":"a","1":"b"},'
.....: '"e":{"0":null,"1":6.0},"f":{"0":null,"1":7.5},"g":{"0":null,"1":true},"h":{"0":null,"1":"a"},'
.....: '"i":{"0":"12-31-2019","1":"12-31-2019"},"j":{"0":null,"1":null}}'
.....: )
.....:
In [286]: df = pd.read_json(StringIO(data), dtype_backend="pyarrow")
In [287]: df
Out[287]:
a b c d e f g h i j
0 1 2.5 True a 12-31-2019 None
1 3 4.5 False b 6 7.5 True a 12-31-2019 None
In [288]: df.dtypes
Out[288]:
a int64[pyarrow]
b double[pyarrow]
c bool[pyarrow]
d string[pyarrow]
e int64[pyarrow]
f double[pyarrow]
g bool[pyarrow]
h string[pyarrow]
i string[pyarrow]
j null[pyarrow]
dtype: object
Нормализация#
pandas предоставляет служебную функцию для преобразования словаря или списка словарей в нормализовать этих полуструктурированных данных в плоскую таблицу.
In [289]: data = [
.....: {"id": 1, "name": {"first": "Coleen", "last": "Volk"}},
.....: {"name": {"given": "Mark", "family": "Regner"}},
.....: {"id": 2, "name": "Faye Raker"},
.....: ]
.....:
In [290]: pd.json_normalize(data)
Out[290]:
id name.first name.last name.given name.family name
0 1.0 Coleen Volk NaN NaN NaN
1 NaN NaN NaN Mark Regner NaN
2 2.0 NaN NaN NaN NaN Faye Raker
In [291]: data = [
.....: {
.....: "state": "Florida",
.....: "shortname": "FL",
.....: "info": {"governor": "Rick Scott"},
.....: "county": [
.....: {"name": "Dade", "population": 12345},
.....: {"name": "Broward", "population": 40000},
.....: {"name": "Palm Beach", "population": 60000},
.....: ],
.....: },
.....: {
.....: "state": "Ohio",
.....: "shortname": "OH",
.....: "info": {"governor": "John Kasich"},
.....: "county": [
.....: {"name": "Summit", "population": 1234},
.....: {"name": "Cuyahoga", "population": 1337},
.....: ],
.....: },
.....: ]
.....:
In [292]: pd.json_normalize(data, "county", ["state", "shortname", ["info", "governor"]])
Out[292]:
name population state shortname info.governor
0 Dade 12345 Florida FL Rick Scott
1 Broward 40000 Florida FL Rick Scott
2 Palm Beach 60000 Florida FL Rick Scott
3 Summit 1234 Ohio OH John Kasich
4 Cuyahoga 1337 Ohio OH John Kasich
Параметр max_level обеспечивает больший контроль над тем, на каком уровне завершить нормализацию. При max_level=1 следующий фрагмент нормализует до 1-го уровня вложенности предоставленного словаря.
In [293]: data = [
.....: {
.....: "CreatedBy": {"Name": "User001"},
.....: "Lookup": {
.....: "TextField": "Some text",
.....: "UserField": {"Id": "ID001", "Name": "Name001"},
.....: },
.....: "Image": {"a": "b"},
.....: }
.....: ]
.....:
In [294]: pd.json_normalize(data, max_level=1)
Out[294]:
CreatedBy.Name Lookup.TextField Lookup.UserField Image.a
0 User001 Some text {'Id': 'ID001', 'Name': 'Name001'} b
JSON с разделителями строк#
pandas может читать и записывать файлы JSON с разделителями строк, которые распространены в конвейерах обработки данных с использованием Hadoop или Spark.
Для JSON-файлов с разделителями строк pandas также может возвращать итератор, который читает chunksize строк за раз. Это может быть полезно для больших файлов или чтения из потока.
In [295]: from io import StringIO
In [296]: jsonl = """
.....: {"a": 1, "b": 2}
.....: {"a": 3, "b": 4}
.....: """
.....:
In [297]: df = pd.read_json(StringIO(jsonl), lines=True)
In [298]: df
Out[298]:
a b
0 1 2
1 3 4
In [299]: df.to_json(orient="records", lines=True)
Out[299]: '{"a":1,"b":2}\n{"a":3,"b":4}\n'
# reader is an iterator that returns ``chunksize`` lines each iteration
In [300]: with pd.read_json(StringIO(jsonl), lines=True, chunksize=1) as reader:
.....: reader
.....: for chunk in reader:
.....: print(chunk)
.....:
Empty DataFrame
Columns: []
Index: []
a b
0 1 2
a b
1 3 4
JSON с ограничением строк также можно прочитать с помощью ридера pyarrow, указав engine="pyarrow".
In [301]: from io import BytesIO
In [302]: df = pd.read_json(BytesIO(jsonl.encode()), lines=True, engine="pyarrow")
In [303]: df
Out[303]:
a b
0 1 2
1 3 4
Добавлено в версии 2.0.0.
Схема таблицы#
Схема таблицы это спецификация для описания табличных наборов данных как JSON-объекта. JSON включает информацию о названиях полей, типах и других атрибутах. Вы можете использовать параметр orient table для построения
JSON-строки с двумя полями, schema и data.
In [304]: df = pd.DataFrame(
.....: {
.....: "A": [1, 2, 3],
.....: "B": ["a", "b", "c"],
.....: "C": pd.date_range("2016-01-01", freq="d", periods=3),
.....: },
.....: index=pd.Index(range(3), name="idx"),
.....: )
.....:
In [305]: df
Out[305]:
A B C
idx
0 1 a 2016-01-01
1 2 b 2016-01-02
2 3 c 2016-01-03
In [306]: df.to_json(orient="table", date_format="iso")
Out[306]: '{"schema":{"fields":[{"name":"idx","type":"integer"},{"name":"A","type":"integer"},{"name":"B","type":"string"},{"name":"C","type":"datetime"}],"primaryKey":["idx"],"pandas_version":"1.4.0"},"data":[{"idx":0,"A":1,"B":"a","C":"2016-01-01T00:00:00.000"},{"idx":1,"A":2,"B":"b","C":"2016-01-02T00:00:00.000"},{"idx":2,"A":3,"B":"c","C":"2016-01-03T00:00:00.000"}]}'
The schema поле содержит fields ключ, который сам содержит
список пар имя столбца - тип, включая Index или MultiIndex
(см. ниже список типов).
schema поле также содержит primaryKey поля, если (Multi)index
уникален.
Второе поле, data, содержит сериализованные данные с records
ориентация.
Индекс включен, и любые даты и время отформатированы в соответствии со стандартом ISO 8601, как требуется спецификацией Table Schema.
Полный список поддерживаемых типов описан в спецификации Table Schema. Эта таблица показывает соответствие типов pandas:
тип pandas |
Тип схемы таблицы |
|---|---|
int64 |
целое число |
float64 |
число |
bool |
логический |
datetime64[ns] |
datetime |
timedelta64[ns] |
длительность |
категориальный |
любой |
object |
str |
Несколько замечаний о сгенерированной схеме таблицы:
The
schemaобъект содержитpandas_versionполе. Это содержит версию диалекта схемы pandas и будет увеличиваться с каждой ревизией.Все даты преобразуются в UTC при сериализации. Даже значения без временной зоны, которые обрабатываются как UTC со смещением 0.
In [307]: from pandas.io.json import build_table_schema In [308]: s = pd.Series(pd.date_range("2016", periods=4)) In [309]: build_table_schema(s) Out[309]: {'fields': [{'name': 'index', 'type': 'integer'}, {'name': 'values', 'type': 'datetime'}], 'primaryKey': ['index'], 'pandas_version': '1.4.0'}
даты и время с часовым поясом (перед сериализацией), включите дополнительное поле
tzс названием часового пояса (например,'US/Central').In [310]: s_tz = pd.Series(pd.date_range("2016", periods=12, tz="US/Central")) In [311]: build_table_schema(s_tz) Out[311]: {'fields': [{'name': 'index', 'type': 'integer'}, {'name': 'values', 'type': 'datetime', 'tz': 'US/Central'}], 'primaryKey': ['index'], 'pandas_version': '1.4.0'}
Периоды преобразуются в метки времени перед сериализацией и поэтому имеют такое же поведение преобразования в UTC. Кроме того, периоды будут содержать дополнительное поле
freqс частотой периода, например.'A-DEC'.In [312]: s_per = pd.Series(1, index=pd.period_range("2016", freq="Y-DEC", periods=4)) In [313]: build_table_schema(s_per) Out[313]: {'fields': [{'name': 'index', 'type': 'datetime', 'freq': 'YE-DEC'}, {'name': 'values', 'type': 'integer'}], 'primaryKey': ['index'], 'pandas_version': '1.4.0'}
Категориальные данные используют
anyтип иenumограничение, перечисляющее набор возможных значений. Кроме того,orderedполе включено:In [314]: s_cat = pd.Series(pd.Categorical(["a", "b", "a"])) In [315]: build_table_schema(s_cat) Out[315]: {'fields': [{'name': 'index', 'type': 'integer'}, {'name': 'values', 'type': 'any', 'constraints': {'enum': ['a', 'b']}, 'ordered': False}], 'primaryKey': ['index'], 'pandas_version': '1.4.0'}
A
primaryKeyполе, содержащее массив меток, включено если индекс уникален:In [316]: s_dupe = pd.Series([1, 2], index=[1, 1]) In [317]: build_table_schema(s_dupe) Out[317]: {'fields': [{'name': 'index', 'type': 'integer'}, {'name': 'values', 'type': 'integer'}], 'pandas_version': '1.4.0'}
The
primaryKeyповедение одинаково с MultiIndex, но в этом случаеprimaryKeyявляется массивом:In [318]: s_multi = pd.Series(1, index=pd.MultiIndex.from_product([("a", "b"), (0, 1)])) In [319]: build_table_schema(s_multi) Out[319]: {'fields': [{'name': 'level_0', 'type': 'string'}, {'name': 'level_1', 'type': 'integer'}, {'name': 'values', 'type': 'integer'}], 'primaryKey': FrozenList(['level_0', 'level_1']), 'pandas_version': '1.4.0'}
Именование по умолчанию примерно следует этим правилам:
Для серий,
object.nameиспользуется. Если его нет, то имяvaluesДля
DataFrames, используется строковое представление имени столбцаДля
Index(неMultiIndex),index.nameиспользуется, с резервным вариантомindexесли это None.Для
MultiIndex,mi.namesиспользуется. Если какой-либо уровень не имеет имени, тоlevel_используется.
read_json также принимает orient='table' в качестве аргумента. Это позволяет сохранять метаданные, такие как типы данных и имена индексов, в
обратно совместимом виде.
In [320]: df = pd.DataFrame(
.....: {
.....: "foo": [1, 2, 3, 4],
.....: "bar": ["a", "b", "c", "d"],
.....: "baz": pd.date_range("2018-01-01", freq="d", periods=4),
.....: "qux": pd.Categorical(["a", "b", "c", "c"]),
.....: },
.....: index=pd.Index(range(4), name="idx"),
.....: )
.....:
In [321]: df
Out[321]:
foo bar baz qux
idx
0 1 a 2018-01-01 a
1 2 b 2018-01-02 b
2 3 c 2018-01-03 c
3 4 d 2018-01-04 c
In [322]: df.dtypes
Out[322]:
foo int64
bar object
baz datetime64[ns]
qux category
dtype: object
In [323]: df.to_json("test.json", orient="table")
In [324]: new_df = pd.read_json("test.json", orient="table")
In [325]: new_df
Out[325]:
foo bar baz qux
idx
0 1 a 2018-01-01 a
1 2 b 2018-01-02 b
2 3 c 2018-01-03 c
3 4 d 2018-01-04 c
In [326]: new_df.dtypes
Out[326]:
foo int64
bar object
baz datetime64[ns]
qux category
dtype: object
Обратите внимание, что строковый литерал 'index' в качестве имени Index
не является двусторонним преобразованием, как и любые имена, начинающиеся с 'level_' внутри
MultiIndex. Они используются по умолчанию в DataFrame.to_json() для
указания пропущенных значений, и последующее чтение не может определить намерение.
In [327]: df.index.name = "index"
In [328]: df.to_json("test.json", orient="table")
In [329]: new_df = pd.read_json("test.json", orient="table")
In [330]: print(new_df.index.name)
None
При использовании orient='table' вместе с пользовательскими ExtensionArray,
сгенерированная схема будет содержать дополнительный extDtype ключу в соответствующем
fields элемент. Этот дополнительный ключ не является стандартным, но позволяет выполнять JSON roundtrips для типов расширений (например, read_json(df.to_json(orient="table"), orient="table")).
The extDtype ключ содержит имя расширения, если вы правильно зарегистрировали
ExtensionDtype, pandas будет использовать указанное имя для поиска в реестре
и повторного преобразования сериализованных данных в ваш пользовательский тип данных.
HTML#
Чтение HTML-контента#
Предупреждение
Мы настоятельно рекомендуем вам прочитать Особенности парсинга HTML таблиц ниже относительно проблем с парсерами BeautifulSoup4/html5lib/lxml.
Верхнеуровневый read_html() функция может принимать HTML-строку/файл/URL и будет преобразовывать HTML-таблицы в список pandas DataFrames.
Рассмотрим несколько примеров.
Примечание
read_html возвращает list of DataFrame объектов, даже если в HTML-содержимом содержится только одна таблица.
Прочитать URL без опций:
In [320]: url = "https://www.fdic.gov/resources/resolutions/bank-failures/failed-bank-list"
In [321]: pd.read_html(url)
Out[321]:
[ Bank NameBank CityCity StateSt ... Acquiring InstitutionAI Closing DateClosing FundFund
0 Almena State Bank Almena KS ... Equity Bank October 23, 2020 10538
1 First City Bank of Florida Fort Walton Beach FL ... United Fidelity Bank, fsb October 16, 2020 10537
2 The First State Bank Barboursville WV ... MVB Bank, Inc. April 3, 2020 10536
3 Ericson State Bank Ericson NE ... Farmers and Merchants Bank February 14, 2020 10535
4 City National Bank of New Jersey Newark NJ ... Industrial Bank November 1, 2019 10534
.. ... ... ... ... ... ... ...
558 Superior Bank, FSB Hinsdale IL ... Superior Federal, FSB July 27, 2001 6004
559 Malta National Bank Malta OH ... North Valley Bank May 3, 2001 4648
560 First Alliance Bank & Trust Co. Manchester NH ... Southern New Hampshire Bank & Trust February 2, 2001 4647
561 National State Bank of Metropolis Metropolis IL ... Banterra Bank of Marion December 14, 2000 4646
562 Bank of Honolulu Honolulu HI ... Bank of the Orient October 13, 2000 4645
[563 rows x 7 columns]]
Примечание
Данные по указанному URL изменяются каждый понедельник, поэтому приведённые выше данные могут незначительно отличаться.
Чтение URL с передачей заголовков вместе с HTTP-запросом:
In [322]: url = 'https://www.sump.org/notes/request/' # HTTP request reflector
In [323]: pd.read_html(url)
Out[323]:
[ 0 1
0 Remote Socket: 51.15.105.256:51760
1 Protocol Version: HTTP/1.1
2 Request Method: GET
3 Request URI: /notes/request/
4 Request Query: NaN,
0 Accept-Encoding: identity
1 Host: www.sump.org
2 User-Agent: Python-urllib/3.8
3 Connection: close]
In [324]: headers = {
In [325]: 'User-Agent':'Mozilla Firefox v14.0',
In [326]: 'Accept':'application/json',
In [327]: 'Connection':'keep-alive',
In [328]: 'Auth':'Bearer 2*/f3+fe68df*4'
In [329]: }
In [340]: pd.read_html(url, storage_options=headers)
Out[340]:
[ 0 1
0 Remote Socket: 51.15.105.256:51760
1 Protocol Version: HTTP/1.1
2 Request Method: GET
3 Request URI: /notes/request/
4 Request Query: NaN,
0 User-Agent: Mozilla Firefox v14.0
1 AcceptEncoding: gzip, deflate, br
2 Accept: application/json
3 Connection: keep-alive
4 Auth: Bearer 2*/f3+fe68df*4]
Примечание
Мы видим выше, что переданные заголовки отражены в HTTP-запросе.
Прочитайте содержимое файла по указанному выше URL и передайте его в read_html
в виде строки:
In [331]: html_str = """
.....:
.....:
.....: A
.....: B
.....: C
.....:
.....:
.....: a
.....: b
.....: c
.....:
.....:
.....: """
.....:
In [332]: with open("tmp.html", "w") as f:
.....: f.write(html_str)
.....:
In [333]: df = pd.read_html("tmp.html")
In [334]: df[0]
Out[334]:
A B C
0 a b c
Вы даже можете передать экземпляр StringIO если вы этого хотите:
In [335]: dfs = pd.read_html(StringIO(html_str))
In [336]: dfs[0]
Out[336]:
A B C
0 a b c
Примечание
Следующие примеры не выполняются IPython-оценщиком из-за того, что наличие множества функций, обращающихся к сети, замедляет сборку документации. Если вы заметили ошибку или пример, который не выполняется, пожалуйста, не стесняйтесь сообщить об этом на страница проблем pandas на GitHub.
Прочитать URL и найти таблицу, содержащую определённый текст:
match = "Metcalf Bank"
df_list = pd.read_html(url, match=match)
Указать строку заголовка (по умолчанию Указать столбец индекса: Укажите количество пропускаемых строк: Указать количество пропускаемых строк с помощью списка ( Укажите атрибут HTML: Укажите значения, которые должны быть преобразованы в NaN: Укажите, сохранять ли стандартный набор значений NaN: Укажите преобразователи для столбцов. Это полезно для числовых текстовых данных, которые имеют
ведущие нули. По умолчанию столбцы, которые являются числовыми, приводятся к числовым
типам, и ведущие нули теряются. Чтобы избежать этого, мы можем преобразовать эти
столбцы в строки. Используйте некоторую комбинацию из вышеперечисленного: Чтение в pandas The Или вы можете передать Однако, если у вас установлены bs4 и html5lib и передать Nathan Goldbaum + Добавлено в версии 1.5.0. Примечание Не все возможные опции для Примечание В среде с поддержкой HTML-рендеринга, такой как Jupyter Notebook, The The The Наконец, Экранировано: Не экранировано: Примечание Некоторые браузеры могут не показывать разницу в отображении двух предыдущих HTML-таблиц. Существуют некоторые проблемы с версиями библиотек, используемых для
парсинга HTML-таблиц в функции ввода-вывода верхнего уровня pandas Проблемы с lxml Преимущества Недостатки lxml делает не не даёт никаких гарантий относительно результатов своего разбора
если только если задано строго допустимая разметка. В свете вышеизложенного, мы решили позволить вам, пользователю, использовать
lxml бэкенд, но этот бэкенд будет использовать html5lib if lxml
не удается разобрать Поэтому настоятельно рекомендуется что вы устанавливаете оба
BeautifulSoup4 и html5lib, так что вы всё равно получите корректный
результат (при условии, что всё остальное корректно), даже если lxml не удается. Проблемы с BeautifulSoup4 используя lxml в качестве бэкенда Указанные выше проблемы также актуальны здесь, поскольку BeautifulSoup4 по сути
просто обёртка вокруг парсерного бэкенда. Проблемы с BeautifulSoup4 используя html5lib в качестве бэкенда Преимущества html5lib гораздо более снисходителен, чем lxml и, следовательно, работает
с реальная разметка гораздо более разумным способом, а не просто, например,
удаляя элемент без уведомления. html5lib автоматически генерирует валидную HTML5-разметку из невалидной разметки. Это чрезвычайно важно для разбора HTML-таблиц, поскольку гарантирует валидный документ. Однако это НЕ означает, что он «корректен», поскольку процесс исправления разметки не имеет единого определения. html5lib является чистым Python и не требует дополнительных шагов сборки, кроме
собственной установки. Недостатки Самый большой недостаток использования html5lib заключается в том, что он медленный как
патока. Однако учтите, что многие таблицы в интернете недостаточно
велики, чтобы время выполнения алгоритма разбора имело значение. Скорее всего,
узким местом будет процесс чтения необработанного текста из URL через интернет,
т.е., ввод-вывод (IO). Для очень больших
таблиц это может быть не так. Добавлено в версии 1.3.0. В настоящее время нет методов для чтения из LaTeX, только методы вывода. Примечание DataFrame и Объекты Styler в настоящее время имеют Ознакомьтесь с документацией для Styler.to_latex,
который содержит примеры условного форматирования и объясняет работу его ключевых
аргументов. Для простого применения достаточно следующего шаблона. Для форматирования значений перед выводом, объедините Styler.format
метод. Добавлено в версии 1.3.0. Верхнеуровневый Примечание Поскольку нет стандартной структуры XML, где типы дизайна могут различаться
многими способами, Давайте рассмотрим несколько примеров. Чтение XML-строки: Прочитать URL без опций: Прочитайте содержимое файла "books.xml" и передайте его в Прочитайте содержимое "books.xml" как экземпляр Даже чтение XML из корзин AWS S3, таких как наборы данных статей NIH NCBI PMC, предоставляющих
биомедицинские и научные журналы по наукам о жизни: С lxml по умолчанию Укажите только элементы или только атрибуты для разбора: XML-документы могут иметь пространства имён с префиксами и пространства имён по умолчанию без префиксов, оба из которых обозначаются специальным атрибутом Например, приведенный ниже XML содержит пространство имен с префиксом, Аналогично, XML-документ может иметь пространство имен по умолчанию без префикса. Не назначение временного префикса вернет пустые узлы и вызовет Однако, если XPath не ссылается на имена узлов, такие как default, Примечание Поскольку показывает атрибут С lxml в качестве парсера, вы можете сгладить вложенные XML-документы с помощью XSLT
скрипта, который также может быть строкой/файлом/URL. В качестве фона, XSLT является специализированным языком, написанным в специальном XML-файле, который может преобразовывать исходные XML-документы в другие XML, HTML, даже текст (CSV, JSON и т.д.) с использованием процессора XSLT. Например, рассмотрим эту несколько вложенную структуру поездок Chicago 'L', где элементы станции и поездок инкапсулируют данные в своих собственных разделах. С помощью XSLT ниже, Для очень больших XML-файлов, размер которых может составлять от сотен мегабайт до гигабайт, Добавлено в версии 1.5.0. Чтобы использовать эту функцию, вы должны передать физический путь к XML-файлу в Добавлено в версии 1.3.0. Примечание Этот метод не поддерживает специальные свойства XML, включая DTD, CData, XSD-схемы, инструкции обработки, комментарии и другие. Поддерживаются только пространства имен на корневом уровне. Однако, Давайте рассмотрим несколько примеров. Запишите XML без опций: Записать XML с новым корневым элементом и именем строки: Записать XML с атрибутами: Напишите смесь элементов и атрибутов: Любой Запись XML с пространством имен по умолчанию: Запись XML с префиксом пространства имён: Записать XML без объявления или с красивым выводом: Написать XML и преобразовать с помощью таблицы стилей: Все XML-документы соответствуют спецификации W3C. Оба По вышеуказанной причине, если ваше приложение строит XML до операций pandas,
используйте соответствующие библиотеки DOM, такие как С очень большими XML-файлами (от нескольких сотен МБ до ГБ) XPath и XSLT
могут стать операциями, интенсивно использующими память. Убедитесь, что у вас достаточно доступной
оперативной памяти для чтения и записи больших XML-файлов (примерно в 5 раз
больше размера текста). Поскольку XSLT является языком программирования, используйте его с осторожностью, так как такие скрипты
могут представлять угрозу безопасности в вашей среде и могут запускать большие или бесконечные
рекурсивные операции. Всегда тестируйте скрипты на небольших фрагментах перед полным запуском. The etree парсер поддерживает всю функциональность как The Примечание Когда Если В противном случае, если В противном случае, если В противном случае В самом простом случае использования, При использовании Для движка openpyxl pandas использует Для движка xlrd, pandas использует Для движка pyxlsb, pandas использует Для движка odf, pandas использует Для движка calamine, pandas использует Для удобства работы с несколькими листами из одного файла The The Основной вариант использования для Обратите внимание, что если одни и те же параметры парсинга используются для всех листов, список имен листов можно просто передать в Примечание Второй аргумент - это Примечание Атрибут ExcelFile Аргументы Значение по умолчанию для возвращает целочисленный массив, который используется для определения того, что выбирается для операции groupby. Передайте целое число для ссылки на индекс листа. Индексы следуют Python-соглашению, начиная с 0. Передайте список строк или целых чисел, чтобы вернуть словарь указанных листов. Передать Используя индекс листа: Использование всех значений по умолчанию: Использование None для получения всех листов: Использование списка для получения нескольких листов: Например, для чтения Если индекс имеет имена уровней, они также будут разобраны с использованием тех же
параметров. Если исходный файл содержит оба Пропущенные значения в столбцах, указанных в Часто пользователи добавляют столбцы для временных вычислений
в Excel, и вы можете не захотеть читать эти столбцы. Вы можете указать набор столбцов и диапазонов Excel, разделённых запятыми, в виде строки: Если Порядок элементов игнорируется, поэтому Если Порядок элементов игнорируется, поэтому Если Значения, похожие на дату и время, обычно автоматически преобразуются в соответствующий
dtype при чтении файла Excel. Но если у вас есть столбец строк, которые
смотри например, даты (но фактически не отформатированы как даты в Excel), вы можете
использовать Содержимое ячеек Excel можно преобразовать с помощью Эта опция обрабатывает пропущенные значения и рассматривает исключения в конвертерах как пропущенные данные. Преобразования применяются к каждой ячейке отдельно, а не к столбцу в целом, поэтому тип данных массива не гарантирован. Например, столбец целых чисел с пропущенными значениями нельзя преобразовать в массив с целочисленным типом данных, потому что NaN строго является числом с плавающей точкой. Вы можете вручную замаскировать пропущенные данные, чтобы восстановить целочисленный тип данных: В качестве альтернативы конвертерам, тип для всего столбца может быть указан с помощью Чтобы написать Файлы с
The Для записи отдельных При использовании Для движка openpyxl pandas использует Для движка xlsxwriter pandas использует Для движка odf, pandas использует pandas поддерживает запись файлов Excel в буферные объекты, такие как Примечание pandas выбирает писатель Excel двумя способами: the расширение имени файла (через значение по умолчанию, указанное в параметрах конфигурации) По умолчанию pandas использует XlsxWriter для Чтобы указать, какой модуль записи вы хотите использовать, вы можете передать аргумент ключевого слова engine в Внешний вид листов Excel, созданных из pandas, можно изменить с помощью следующих параметров на Используя Xlsxwriter движок предоставляет множество опций для управления
форматом листа Excel, созданного с помощью Методы ввода-вывода для Файлы Excel также поддерживает чтение и запись электронных таблиц OpenDocument
с использованием odfpy модуль. Семантика и возможности для чтения и записи электронных таблиц OpenDocument соответствуют тому, что можно сделать для Файлы Excel используя
The Аналогично, The Примечание В настоящее время pandas поддерживает только чтение двоичные файлы Excel. Запись
не реализована. The Удобный способ получения данных — использовать А затем импортировать данные напрямую в The Мы видим, что получили тот же контент, который ранее записали в буфер обмена. Примечание Вам может потребоваться установить xclip или xsel (с PyQt5, PyQt4 или qtpy) в Linux для использования этих методов. Все объекты pandas оснащены The Предупреждение Загрузка данных из pickle-файлов, полученных из ненадежных источников, может быть небезопасной. Предупреждение Тип сжатия может быть явным параметром или определяться по расширению файла.
Если 'infer', то используется Параметр сжатия также может быть Использование явного типа сжатия: Определение типа сжатия по расширению: По умолчанию используется 'infer': Передача опций протоколу сжатия для ускорения сжатия: поддержка pandas для В качестве альтернативы, вы также можете использовать формат сериализации Arrow IPC для передачи объектов pandas по сети. Документацию по pyarrow см. в
здесь. Предупреждение pandas использует PyTables для чтения и записи файлов HDF5, что позволяет
сериализовать данные типа object с помощью pickle. Загрузка данных pickle, полученных из
ненадежных источников, может быть небезопасной. См.: https://docs.python.org/3/library/pickle.html подробнее. Объекты могут быть записаны в файл так же, как добавление пар ключ-значение в словарь: В текущей или последующей сессии Python вы можете извлечь сохранённые объекты: Удаление объекта, указанного ключом: Закрытие Store и использование контекстного менеджера: HDFStore по умолчанию не удаляет строки, которые полностью отсутствуют. Это поведение можно изменить, установив Приведенные выше примеры показывают сохранение с использованием Предупреждение A Этот формат также может быть установлен как опция Примечание Вы также можете создать Ключи к хранилищу могут быть указаны в виде строки. Они могут быть в
иерархическом формате пути (например, Вы можете пройти по иерархии групп, используя Предупреждение Иерархические ключи не могут быть получены через точечный (атрибутный) доступ, как описано выше для элементов, хранящихся в корневом узле. Вместо этого используйте явные строковые ключи: Поддерживается хранение данных смешанных типов. Строки хранятся как
фиксированной ширины с использованием максимального размера добавленного столбца. Последующие попытки
добавления более длинных строк вызовут Передача Хранение MultiIndex Примечание The Запрос указывается с помощью if имя уровня в MultiIndex, с именем по умолчанию Допустимые операторы сравнения: Допустимые логические выражения объединяются с: Эти правила похожи на то, как логические выражения используются в pandas для индексации. Примечание Если передается список/кортеж выражений, они будут объединены через Следующие выражения являются допустимыми: The Правая часть подвыражения (после оператора сравнения) может быть: функции, которые будут вычислены, например, строки, например. дата-подобный, например списки, например переменные, определенные в локальном пространстве имен, например Примечание Передача строки в запрос путём интерполяции её в выражение запроса
не рекомендуется. Просто присвойте интересующую строку переменной
и используйте эту переменную в выражении. Например, сделайте так вместо этого Последний будет не работает и вызовет Если вы должен интерполировать, используйте который будет заключать в кавычки Вот несколько примеров: Используйте логические выражения с встроенной оценкой функций. Используйте встроенную ссылку на столбец. The Примечание Вы можете хранить и запрашивать с использованием Выбор из Если Вы можете создать/изменить индекс для таблицы с помощью Примечание Индексы автоматически создаются для индексируемых объектов
и любых указанных столбцов данных. Это поведение можно отключить, передав
Часто при добавлении больших объемов данных в хранилище полезно отключать создание индекса для каждого добавления, а затем воссоздавать его в конце. Затем создайте индекс после завершения добавления. См. здесь о том, как создать полностью отсортированный индекс (CSI) в существующем хранилище. Вы можете назначить (и проиндексировать) определенные столбцы, которые хотите использовать для выполнения запросов (кроме Есть некоторое снижение производительности при преобразовании множества столбцов в
Вы можете передать Примечание Вы также можете использовать итератор с Обратите внимание, что ключевое слово chunksize применяется к источник строк. Таким образом, если вы выполняете запрос, то chunksize разделит общее количество строк в таблице и применит запрос, возвращая итератор по потенциально неравным по размеру фрагментам. Вот рецепт для генерации запроса и его использования для создания возвращаемых
частей равного размера. Для получения одного индексируемого или столбца данных используйте метод Иногда нужно получить координаты (т.е. позиции индексов) вашего запроса. Это возвращает
Иногда ваш запрос может включать создание списка строк для выбора. Обычно это Если вы хотите проверить сохраненный объект, получите его через
Методы The Если Вы можете удалять из таблицы выборочно, указав Данные упорядочены (на диске) в терминах id_1 id_2 . id_n id_1 . id_n Должно быть понятно, что операция удаления на Предупреждение Обратите внимание, что HDF5 НЕ ОСВОБОЖДАЕТ ПРОСТРАНСТВО в файлах h5
автоматически. Таким образом, многократное удаление (или удаление узлов) и добавление
снова, СКЛОННО УВЕЛИЧИВАТЬ РАЗМЕР ФАЙЛА. Для перепаковать и очистить файл, используйте ptrepack. zlib: Библиотека сжатия по умолчанию.
Классика в области сжатия, обеспечивает хорошие коэффициенты сжатия, но несколько медленная. lzo: Быстрое
сжатие и распаковка. bzip2: Хорошие коэффициенты сжатия. blosc: Быстрое сжатие и
распаковка. Поддержка альтернативных компрессоров blosc: blosc:blosclz Это
компрессор по умолчанию для blosc:lz4:
Компактный, очень популярный и быстрый компрессор. blosc:lz4hc:
Модифицированная версия LZ4, обеспечивает лучшие коэффициенты сжатия за счет скорости. blosc:snappyПопулярный компрессор, используемый во многих местах. blosc:zlib: Классический;
несколько медленнее предыдущих, но
достигающий лучших коэффициентов сжатия. blosc:zstd: Чрезвычайно
сбалансированный кодек; он обеспечивает наилучшие
коэффициенты сжатия среди других вышеупомянутых, и при
достаточно высокой скорости. Если Примечание Если библиотека указана с помощью Включить сжатие для всех объектов в файле: Или сжатие на лету (это относится только к таблицам) в хранилищах, где сжатие не включено: Кроме того Предупреждение Если вы используете блокировки для управления доступом на запись между несколькими процессами, вы
можете захотеть использовать Как только Обратите внимание, что часовые пояса (например, Предупреждение Тип Представляет отсутствующие значения floating : целое число : логический categorical : см. раздел ниже объект : Вы можете записывать данные, содержащие min_itemsize Базовая реализация Передать Передача Примечание Если вы не передаете никакие nan_rep Строковые столбцы будут сериализовать Вы можете передать Вы можете передать Дублирующиеся строки могут быть записаны в таблицы, но отфильтровываются при выборе (с выбором последних элементов; таким образом, таблица уникальна по парам major, minor) A Feather предоставляет бинарную колоночную сериализацию для фреймов данных. Он разработан для эффективного чтения и записи фреймов данных и для легкого обмена данными между языками анализа данных. Feather предназначен для точной сериализации и десериализации DataFrame, поддерживая все типы данных pandas,
включая расширенные типы, такие как категориальные и datetime с tz. Несколько предостережений: Формат НЕ будет записывать Дублирующиеся имена столбцов и нестроковые имена столбцов не поддерживаются Фактические объекты Python в столбцах типа object не поддерживаются. Они вызовут
полезное сообщение об ошибке при попытке сериализации. См. Полная документация. Запись в файл feather. Чтение из файла feather. Apache Parquet предоставляет разделенную бинарную колоночную сериализацию для фреймов данных. Он предназначен для эффективного чтения и записи фреймов данных, а также для легкого обмена данными между языками анализа данных. Parquet может использовать различные методы сжатия для максимального уменьшения размера файла, сохраняя при этом хорошую производительность чтения. Parquet предназначен для точной сериализации и десериализации Несколько предостережений. Дублирующиеся имена столбцов и нестроковые имена столбцов не поддерживаются. The Имена уровней индекса, если указаны, должны быть строками. В The Неподдерживаемые типы включают The Вы можете указать См. документацию для pyarrow и fastparquet. Примечание Эти движки очень похожи и должны читать/записывать почти идентичные файлы формата parquet.
Запись в файл parquet. Чтение из файла parquet. Установкой Примечание Обратите внимание, что это не поддерживается для Чтение только определённых столбцов файла parquet. Сериализация создает файл parquet с три столбцы, если вы используете Этот неожиданный дополнительный столбец заставляет некоторые базы данных, такие как Amazon Redshift, отклонять
файл, потому что этот столбец не существует в целевой таблице. Если вы хотите опустить индексы датафрейма при записи, передайте Это создаёт файл parquet только с двумя ожидаемыми столбцами, Передача Parquet поддерживает разделение данных на основе значений одного или нескольких столбцов. The Аналогично parquet формат, Формат ORC является бинарной колоночной сериализацией
для фреймов данных. Он разработан для эффективного чтения фреймов данных. pandas предоставляет как читатель, так и писатель для
формата ORC, Предупреждение Это настоятельно рекомендуется для установки pyarrow с помощью conda из-за некоторых проблем, вызванных pyarrow. Для поддерживаемых типов данных обратитесь к поддерживаемые функции ORC в Arrow. В настоящее время часовые пояса в столбцах datetime не сохраняются при преобразовании датафрейма в файлы ORC. Запись в файл orc. Чтение из файла orc. Прочитать только определённые столбцы файла orc. The При наличии возможности пользователям следует сначала рассмотреть Apache Arrow ADBC драйверы. Эти драйверы должны обеспечивать наилучшую производительность, обработку null и определение типов. Добавлено в версии 2.2.0: Добавлена нативная поддержка драйверов ADBC Полный список драйверов ADBC и их статус разработки см. в Статус реализации драйвера ADBC
документация. Если драйвер ADBC недоступен или может не хватать функциональности, пользователям следует установить SQLAlchemy вместе с библиотекой драйвера базы данных. Примеры таких драйверов: psycopg2
для PostgreSQL или pymysql для MySQL.
Для SQLite это
включено в стандартную библиотеку Python по умолчанию.
Обзор поддерживаемых драйверов для каждого SQL-диалекта можно найти в
документация SQLAlchemy. Если SQLAlchemy не установлен, вы можете использовать См. также некоторые примеры из кулинарной книги для некоторых продвинутых стратегий. Ключевые функции: Прочитать таблицу базы данных SQL в DataFrame. Прочитать SQL-запрос в DataFrame. Чтение SQL-запроса или таблицы базы данных в DataFrame. Записать записи, хранящиеся в DataFrame, в базу данных SQL. Примечание Функция В следующем примере мы используем SQlite Движок базы данных SQL. Можно использовать временную базу данных SQLite, где данные хранятся
в «памяти». Для подключения с использованием драйвера ADBC вам потребуется установить Для подключения к SQLAlchemy используйте Если вы хотите управлять своими собственными соединениями, вы можете передать одно из них вместо этого. Пример ниже открывает соединение с базой данных, используя контекстный менеджер Python, который автоматически закрывает соединение после завершения блока. См. документация SQLAlchemy
для объяснения того, как обрабатывается подключение к базе данных. Предупреждение Когда вы открываете соединение с базой данных, вы также отвечаете за его закрытие.
Побочные эффекты оставления соединения открытым могут включать блокировку базы данных или
другое нарушающее поведение. Предполагая, что следующие данные находятся в id Дата Col_1 Col_2 Col_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 С некоторыми базами данных запись больших DataFrames может вызывать ошибки из-за
превышения ограничений на размер пакета. Этого можно избежать, установив
Обеспечение согласованного управления типами данных в SQL-базах данных является сложной задачей.
Не каждая SQL-база данных предлагает одинаковые типы, и даже когда они это делают, реализация
определенного типа может различаться способами, которые оказывают тонкое влияние на то, как типы могут быть
сохранены. Для наилучших шансов сохранения типов базы данных пользователям рекомендуется использовать драйверы ADBC, когда они доступны. Система типов Arrow предлагает более широкий набор типов, которые более точно соответствуют типам баз данных, чем историческая система типов pandas/NumPy. Для иллюстрации обратите внимание на этот (неисчерпывающий) список типов, доступных в различных базах данных и бэкендах pandas: numpy/pandas arrow postgres sqlite int16/Int16 int16 SMALLINT INTEGER int32/Int32 int32 INTEGER INTEGER int64/Int64 int64 BIGINT INTEGER float32 float32 REAL REAL float64 float64 DOUBLE PRECISION REAL object string TEXT TEXT bool BOOLEAN datetime64[ns] timestamp(us) ВРЕМЕННАЯ МЕТКА datetime64[ns,tz] timestamp(us,tz) TIMESTAMPTZ date32 ДАТА month_day_nano_interval INTERVAL бинарный BINARY BLOB decimal128 DECIMAL [1] list ARRAY [1] struct Сноски Если вы заинтересованы в максимально возможном сохранении типов базы данных
на протяжении всего жизненного цикла вашего DataFrame, пользователям рекомендуется
использовать Это предотвратит преобразование ваших данных в традиционную систему типов pandas/NumPy,
которая часто преобразует SQL-типы таким образом, что делает невозможным их
обратное преобразование. В случае, если драйвер ADBC недоступен, Вы всегда можете переопределить тип по умолчанию, указав желаемый SQL-тип для любого из столбцов, используя Примечание Из-за ограниченной поддержки timedelta в различных типах баз данных,
столбцы с типом Примечание Столбцы Используя ADBC или SQLAlchemy, В следующей таблице перечислены поддерживаемые типы данных для даты и времени для некоторых распространённых баз данных. Другие диалекты баз данных могут иметь разные типы данных для даты и времени. База данных Типы даты и времени SQL Поддержка часовых поясов SQLite Нет MySQL Нет PostgreSQL Да При записи данных с учетом часового пояса в базы данных, которые не поддерживают часовые пояса,
данные будут записаны как временные метки без учета часового пояса, которые находятся в местном времени
относительно часового пояса. Параметр вызываемый объект с сигнатурой Пример вызываемого объекта с использованием PostgreSQL Предложение COPY: Примечание Для использования Примечание Драйверы ADBC будут напрямую сопоставлять типы базы данных с типами arrow. Для других драйверов
обратите внимание, что pandas выводит типы столбцов из результатов запроса, а не путем поиска
типов данных в физической схеме базы данных. Например, предположим Вы также можете указать имя столбца как И вы можете явно принудительно указать столбцы для парсинга как даты: При необходимости вы можете явно указать строку формата или словарь аргументов
для передачи в Вы можете проверить, существует ли таблица, используя Чтение из и запись в различные схемы поддерживается через Вы можете выполнять запросы с использованием сырого SQL в Конечно, вы можете указать более "сложный" запрос. The Для подключения к SQLAlchemy используйте Для получения дополнительной информации см. примеры SQLAlchemy документация Вы можете использовать конструкции SQLAlchemy для описания вашего запроса. Используйте Если у вас есть описание базы данных SQLAlchemy, вы можете выразить условия where с помощью выражений SQLAlchemy Вы можете комбинировать выражения SQLAlchemy с параметрами, переданными в Использование sqlite поддерживается без использования SQLAlchemy.
Этот режим требует адаптера базы данных Python, который соответствует Python
DB-API. Вы можете создавать соединения следующим образом: А затем выполните следующие запросы: The pandas интегрируется с этим внешним пакетом. если Полную документацию можно найти здесь. Метод Stata файлы данных имеют ограниченную поддержку типов данных; только строки с
244 или менее символами, Примечание Невозможно экспортировать пропущенные значения для целочисленных типов данных. The Stata записыватель корректно обрабатывает другие типы данных, включая Предупреждение Преобразование из Предупреждение Функция верхнего уровня Указание Для более тонкого контроля используйте В настоящее время Параметр Параметр Примечание Примечание Установка Примечание Все Предупреждение Stata поддерживает только строковые метки значений, и поэтому Помеченные данные могут быть аналогично импортированы из Stata файлы данных как Примечание При импорте категориальных данных значения переменных в Stata
файла данных не сохраняются, поскольку Примечание Stata поддерживает частично помеченные серии. Эти серии имеют метки значений для некоторых, но не всех данных. Импорт частично помеченной серии создаст Функция верхнего уровня Файлы SAS содержат только два типа значений: текст ASCII и значения с плавающей точкой (обычно 8 байт, но иногда усеченные). Для файлов xport нет автоматического преобразования типов в целые числа, даты или категориальные. Для файлов SAS7BDAT коды формата могут позволить автоматическое преобразование переменных даты в даты. По умолчанию весь файл читается и возвращается как Укажите Прочитать файл SAS7BDAT: Получить итератор и прочитать файл XPORT по 100 000 строк за раз: The спецификация для формата файла xport доступен на веб-сайте SAS. Официальная документация для формата SAS7BDAT недоступна. Функция верхнего уровня Файлы SPSS содержат имена столбцов. По умолчанию весь файл читается, категориальные столбцы преобразуются в Укажите Прочитать файл SPSS: Извлеките подмножество столбцов, содержащихся в Дополнительная информация о форматах файлов SAV и ZSAV доступна здесь. сам pandas поддерживает ввод-вывод только с ограниченным набором форматов файлов, которые
чисто отображаются на его табличную модель данных. Для чтения и записи других форматов файлов
в pandas и из pandas мы рекомендуем эти пакеты из более широкого сообщества. xarray предоставляет структуры данных, вдохновленные pandas Это неформальное сравнение различных методов ввода-вывода с использованием pandas 0.24.2. Время выполнения зависит от машины, и небольшие различия следует игнорировать. Следующие тестовые функции будут использованы ниже для сравнения производительности нескольких методов ввода-вывода: При записи три самые быстрые функции в плане скорости это При чтении, три верхние функции по скорости - это Файлы или элементы, расположенные внутри
используются для формирования индекса столбцов, если несколько строк содержатся в
тогда создаётся MultiIndex); если указано, строка заголовка берётся
из данных минус разобранные элементы заголовка ( элементов).
dfs = pd.read_html(url, header=0)
dfs = pd.read_html(url, index_col=0)
dfs = pd.read_html(url, skiprows=0)
range работает
также):dfs = pd.read_html(url, skiprows=range(2))
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
dfs = pd.read_html(url, na_values=["No Acquirer"])
dfs = pd.read_html(url, keep_default_na=False)
url_mcc = "https://en.wikipedia.org/wiki/Mobile_country_code?oldid=899173761"
dfs = pd.read_html(
url_mcc,
match="Telekom Albania",
header=0,
converters={"MNC": str},
)
dfs = pd.read_html(url, match="Metcalf Bank", index_col=0)
to_html вывод (с некоторой потерей точности чисел с плавающей запятой):df = pd.DataFrame(np.random.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"])
flavor='lxml' без списка:dfs = pd.read_html(url, "Metcalf Bank", index_col=0, flavor="lxml")
None или ['lxml',
'bs4'] тогда разбор, скорее всего, будет успешным. Обратите внимание, что как только парсинг
успешен, функция вернёт.dfs = pd.read_html(url, "Metcalf Bank", index_col=0, flavor=["lxml", "bs4"])
extract_links="all".In [337]: html_table = """
.....:
.....:
.....: """
.....:
In [338]: df = pd.read_html(
.....: StringIO(html_table),
.....: extract_links="all"
.....: )[0]
.....:
In [339]: df
Out[339]:
(GitHub, None)
0 (pandas, https://github.com/pandas-dev/pandas)
In [340]: df[("GitHub", None)]
Out[340]:
0 (pandas, https://github.com/pandas-dev/pandas)
Name: (GitHub, None), dtype: object
In [341]: df[("GitHub", None)].str[1]
Out[341]:
0 https://github.com/pandas-dev/pandas
Name: (GitHub, None), dtype: object
.....:
.....: GitHub
.....:
.....:
.....: pandas
.....: Запись в HTML-файлы#
DataFrame объекты имеют метод экземпляра to_html который отображает
содержимое DataFrame в виде HTML-таблицы. Аргументы функции такие же,
как в методе to_string описанного выше.DataFrame.to_html показаны здесь для краткости. См. DataFrame.to_html() для
полного набора опций.display(HTML(...))`
отобразит необработанный HTML в окружении.In [342]: from IPython.display import display, HTML
In [343]: df = pd.DataFrame(np.random.randn(2, 2))
In [344]: df
Out[344]:
0 1
0 -0.345352 1.314232
1 0.690579 0.995761
In [345]: html = df.to_html()
In [346]: print(html) # raw html
In [347]: display(HTML(html))
0
1
0
-0.345352
1.314232
1
0.690579
0.995761
columns аргумент ограничит отображаемые столбцы:In [348]: html = df.to_html(columns=[0])
In [349]: print(html)
In [350]: display(HTML(html))
0
0
-0.345352
1
0.690579
float_format принимает вызываемый объект Python для управления точностью значений с плавающей точкой:In [351]: html = df.to_html(float_format="{0:.10f}".format)
In [352]: print(html)
In [353]: display(HTML(html))
0
1
0
-0.3453521949
1.3142323796
1
0.6905793352
0.9957609037
bold_rows будет делать метки строк жирными по умолчанию, но это можно отключить:In [354]: html = df.to_html(bold_rows=False)
In [355]: print(html)
In [356]: display(HTML(html))
0
1
0
-0.345352
1.314232
1
0.690579
0.995761
classes аргумент предоставляет возможность задать результирующей HTML-таблице CSS-классы. Обратите внимание, что эти классы добавлен к существующему
'dataframe' класс.In [357]: print(df.to_html(classes=["awesome_table_class", "even_more_awesome_class"]))
0
1
0
-0.345352
1.314232
1
0.690579
0.995761
render_links аргумент предоставляет возможность добавлять гиперссылки в ячейки,
содержащие URL-адреса.In [358]: url_df = pd.DataFrame(
.....: {
.....: "name": ["Python", "pandas"],
.....: "url": ["https://www.python.org/", "https://pandas.pydata.org"],
.....: }
.....: )
.....:
In [359]: html = url_df.to_html(render_links=True)
In [360]: print(html)
In [361]: display(HTML(html))
name
url
0
Python
https://www.python.org/
1
pandas
https://pandas.pydata.org
escape аргумент позволяет контролировать, экранируются ли символы
"<", ">" и "&" в результирующем HTML (по умолчанию
True). Поэтому чтобы получить HTML без экранированных символов, передайте escape=FalseIn [362]: df = pd.DataFrame({"a": list("&<>"), "b": np.random.randn(3)})
In [363]: html = df.to_html()
In [364]: print(html)
In [365]: display(HTML(html))
a
b
0
&
2.396780
1
<
0.014871
2
>
3.357427
In [366]: html = df.to_html(escape=False)
In [367]: print(html)
In [368]: display(HTML(html))
a
b
0
&
2.396780
1
<
0.014871
2
>
3.357427
Особенности парсинга HTML таблиц#
read_html.
LaTeX#
Запись в файлы LaTeX#
to_latex метод. Мы рекомендуем
использовать Styler.to_latex() метод
вместо DataFrame.to_latex() из-за большей гибкости первого с
условным форматированием и возможной будущей устарелости второго.In [369]: df = pd.DataFrame([[1, 2], [3, 4]], index=["a", "b"], columns=["c", "d"])
In [370]: print(df.style.to_latex())
\begin{tabular}{lrr}
& c & d \\
a & 1 & 2 \\
b & 3 & 4 \\
\end{tabular}
In [371]: print(df.style.format("€ {}").to_latex())
\begin{tabular}{lrr}
& c & d \\
a & € 1 & € 2 \\
b & € 3 & € 4 \\
\end{tabular}
XML#
Чтение XML#
read_xml() функция может принимать XML-строку/файл/URL и будет разбирать узлы и атрибуты в pandas DataFrame.read_xml работает лучше с более плоскими, неглубокими версиями. Если
XML-документ глубоко вложен, используйте stylesheet функция для
преобразования XML в более плоскую версию.In [372]: from io import StringIO
In [373]: xml = """
.....:
In [376]: df = pd.read_xml("https://www.w3schools.com/xml/books.xml")
In [377]: df
Out[377]:
category title author year price cover
0 cooking Everyday Italian Giada De Laurentiis 2005 30.00 None
1 children Harry Potter J K. Rowling 2005 29.99 None
2 web XQuery Kick Start Vaidyanathan Nagarajan 2003 49.99 None
3 web Learning XML Erik T. Ray 2003 39.95 paperback
read_xml
в виде строки:In [378]: file_path = "books.xml"
In [379]: with open(file_path, "w") as f:
.....: f.write(xml)
.....:
In [380]: with open(file_path, "r") as f:
.....: df = pd.read_xml(StringIO(f.read()))
.....:
In [381]: df
Out[381]:
category title author year price
0 cooking Everyday Italian Giada De Laurentiis 2005 30.00
1 children Harry Potter J K. Rowling 2005 29.99
2 web Learning XML Erik T. Ray 2003 39.95
StringIO или
BytesIO и передайте его в read_xml:In [382]: with open(file_path, "r") as f:
.....: sio = StringIO(f.read())
.....:
In [383]: df = pd.read_xml(sio)
In [384]: df
Out[384]:
category title author year price
0 cooking Everyday Italian Giada De Laurentiis 2005 30.00
1 children Harry Potter J K. Rowling 2005 29.99
2 web Learning XML Erik T. Ray 2003 39.95
In [385]: with open(file_path, "rb") as f:
.....: bio = BytesIO(f.read())
.....:
In [386]: df = pd.read_xml(bio)
In [387]: df
Out[387]:
category title author year price
0 cooking Everyday Italian Giada De Laurentiis 2005 30.00
1 children Harry Potter J K. Rowling 2005 29.99
2 web Learning XML Erik T. Ray 2003 39.95
In [388]: df = pd.read_xml(
.....: "s3://pmc-oa-opendata/oa_comm/xml/all/PMC1236943.xml",
.....: xpath=".//journal-meta",
.....: )
.....:
In [389]: df
Out[389]:
journal-id journal-title issn publisher
0 Cardiovasc Ultrasound Cardiovascular Ultrasound 1476-7120 NaN
parser, вы получаете доступ к полнофункциональной XML-библиотеке,
которая расширяет API ElementTree Python. Одним из мощных инструментов является возможность запрашивать
узлы выборочно или условно с более выразительным XPath:In [390]: df = pd.read_xml(file_path, xpath="//book[year=2005]")
In [391]: df
Out[391]:
category title author year price
0 cooking Everyday Italian Giada De Laurentiis 2005 30.00
1 children Harry Potter J K. Rowling 2005 29.99
In [392]: df = pd.read_xml(file_path, elems_only=True)
In [393]: df
Out[393]:
title author year price
0 Everyday Italian Giada De Laurentiis 2005 30.00
1 Harry Potter J K. Rowling 2005 29.99
2 Learning XML Erik T. Ray 2003 39.95
In [394]: df = pd.read_xml(file_path, attrs_only=True)
In [395]: df
Out[395]:
category
0 cooking
1 children
2 web
xmlnsДля парсинга по узлу в контексте пространства имен, xpath должен ссылаться на префикс.doc, и URI на
https://example.com. Чтобы разобрать doc:row узлы,
namespaces должен использоваться.In [396]: xml = """
.....:
ValueError.
Но присваивание любой временное имя для исправления URI позволяет парсинг узлами.In [399]: xml = """
.....:
.....:
/*, затем
namespaces не требуется.xpath определяет родительский элемент контента для парсинга, только непосредственные
потомки, включающие дочерние узлы или текущие атрибуты, парсятся.
Поэтому, read_xml не будет разбирать текст внуков или других
потомков и не будет разбирать атрибуты любого потомка. Чтобы получить
содержимое нижнего уровня, измените xpath на более низкий уровень. Например,In [402]: xml = """
.....:
.....:
sides на shape элемент не был разобран как
ожидалось, поскольку этот атрибут находится на дочернем элементе row элемент
а не row сам элемент. Другими словами, sides атрибут является
потомком уровня внука для row элемент. Однако, xpath
targets row элемент, который охватывает только его дочерние элементы и атрибуты.lxml может преобразовать исходный вложенный документ в более плоский вывод (как показано ниже для демонстрации) для более простого разбора в DataFrame:In [405]: xml = """
.....:
pandas.read_xml()
поддерживает разбор таких больших файлов с использованием lxml’s iterparse и iterparse из etree
которые являются эффективными по памяти методами для итерации по XML-дереву и извлечения определённых элементов и атрибутов без хранения всего дерева в памяти.read_xml и использовать iterparse аргумент.
Файлы не должны быть сжаты или указывать на онлайн-источники, а храниться на локальном диске. Также, iterparse должен быть словарем, где ключ - повторяющиеся узлы в документе (которые становятся строками), а значение - список любых элементов или атрибутов, являющихся потомками (т.е. дочерними, внучатыми) повторяющегося узла. Поскольку XPath не используется в этом методе, потомки не должны иметь одинакового отношения друг к другу. Ниже приведен пример чтения очень большого (12+ ГБ) дампа последних статей Википедии.In [1]: df = pd.read_xml(
... "/path/to/downloaded/enwikisource-latest-pages-articles.xml",
... iterparse = {"page": ["title", "ns", "id"]}
... )
... df
Out[2]:
title ns id
0 Gettysburg Address 0 21450
1 Main Page 0 42950
2 Declaration by United Nations 0 8435
3 Constitution of the United States of America 0 8435
4 Declaration of Independence (Israel) 0 17858
... ... ... ...
3578760 Page:Black cat 1897 07 v2 n10.pdf/17 104 219649
3578761 Page:Black cat 1897 07 v2 n10.pdf/43 104 219649
3578762 Page:Black cat 1897 07 v2 n10.pdf/44 104 219649
3578763 The History of Tom Jones, a Foundling/Book IX 0 12084291
3578764 Page:Shakespeare of Stratford (1926) Yale.djvu/91 104 21450
[3578765 rows x 3 columns]
Запись XML#
DataFrame объекты имеют метод экземпляра to_xml который отображает
содержимое DataFrame как XML-документ.stylesheet
позволяет вносить изменения в дизайн после первоначального вывода.In [410]: geom_df = pd.DataFrame(
.....: {
.....: "shape": ["square", "circle", "triangle"],
.....: "degrees": [360, 360, 180],
.....: "sides": [4, np.nan, 3],
.....: }
.....: )
.....:
In [411]: print(geom_df.to_xml())
In [412]: print(geom_df.to_xml(root_name="geometry", row_name="objects"))
In [413]: print(geom_df.to_xml(attr_cols=geom_df.columns.tolist()))
In [414]: print(
.....: geom_df.to_xml(
.....: index=False,
.....: attr_cols=['shape'],
.....: elem_cols=['degrees', 'sides'])
.....: )
.....:
DataFrames с иерархическими столбцами будут сглажены для имен XML элементов
с уровнями, разделенными подчеркиваниями:In [415]: ext_geom_df = pd.DataFrame(
.....: {
.....: "type": ["polygon", "other", "polygon"],
.....: "shape": ["square", "circle", "triangle"],
.....: "degrees": [360, 360, 180],
.....: "sides": [4, np.nan, 3],
.....: }
.....: )
.....:
In [416]: pvt_df = ext_geom_df.pivot_table(index='shape',
.....: columns='type',
.....: values=['degrees', 'sides'],
.....: aggfunc='sum')
.....:
In [417]: pvt_df
Out[417]:
degrees sides
type other polygon other polygon
shape
circle 360.0 NaN 0.0 NaN
square NaN 360.0 NaN 4.0
triangle NaN 180.0 NaN 3.0
In [418]: print(pvt_df.to_xml())
In [419]: print(geom_df.to_xml(namespaces={"": "https://example.com"}))
In [420]: print(
.....: geom_df.to_xml(namespaces={"doc": "https://example.com"},
.....: prefix="doc")
.....: )
.....:
In [421]: print(
.....: geom_df.to_xml(xml_declaration=False,
.....: pretty_print=False)
.....: )
.....:
In [422]: xsl = """
XML Заключительные замечания#
etree и lxml
парсеры не смогут разобрать любой разметочный документ, который не является корректно сформированным или
следует правилам синтаксиса XML. Учтите, что HTML не является XML-документом, если он
не соответствует спецификациям XHTML. Однако другие популярные типы разметки, включая KML, XAML,
RSS, MusicML, MathML, соответствуют требованиям XML схемы.etree и lxml для построения необходимого документа, а не путем конкатенации строк или корректировок регулярных выражений. Всегда помните, XML — это специальный текстовый файл с правилами разметки.read_xml и
to_xml за исключением сложных XPath и любых XSLT. Хотя ограниченный в возможностях,
etree всё ещё является надёжным и способным парсером и построителем деревьев. Его производительность может отставать lxml до определенной степени для больших файлов, но относительно незаметно для файлов малого и среднего размера.Файлы Excel#
read_excel() метод может читать Excel 2007+ (.xlsx) файлы
с использованием openpyxl Модуль Python. Excel 2003 (.xls) файлы
можно читать с помощью xlrd. Двоичный Excel (.xlsb)
файлы можно читать с помощью pyxlsbВсе форматы могут быть прочитаны с использованием calamine движок.
В to_excel() метод экземпляра используется для
сохранения DataFrame в Excel. Обычно семантика работы
похожа на работу с csv данные.
См. cookbook для некоторых продвинутых стратегий.engine=None, следующая логика будет использоваться для определения движка:
path_or_buffer является форматом OpenDocument (.odf, .ods, .odt), тогда odf будет использоваться.path_or_buffer является форматом xls, xlrd будет использоваться.path_or_buffer имеет формат xlsb, pyxlsb будет использоваться.openpyxl будет использоваться.Чтение файлов Excel#
read_excel принимает путь к файлу Excel, и sheet_name указывающий, какой лист разбирать.engine_kwargs параметр, pandas передаст эти аргументы в
движок. Для этого важно знать, какую функцию pandas
использует внутренне.
openpyxl.load_workbook() для чтения (.xlsx) и (.xlsm) файлы.xlrd.open_workbook() для чтения (.xls) файлы.pyxlsb.open_workbook() для чтения (.xlsb) файлы.odf.opendocument.load() для чтения (.ods) файлы.python_calamine.load_workbook()
для чтения (.xlsx), (.xlsm), (.xls), (.xlsb), (.ods) файлы.# Returns a DataFrame
pd.read_excel("path_to_file.xls", sheet_name="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"] = pd.read_excel(xls, "Sheet1", index_col=None, na_values=["NA"])
data["Sheet2"] = pd.read_excel(xls, "Sheet2", index_col=None, na_values=["NA"])
# equivalent using the read_excel function
data = pd.read_excel(
"path_to_file.xls", ["Sheet1", "Sheet2"], index_col=None, na_values=["NA"]
)
ExcelFile также может быть вызван с xlrd.book.Book объект как параметр. Это позволяет пользователю контролировать, как читается файл Excel. Например, листы могут загружаться по требованию путем вызова xlrd.open_workbook()
с on_demand=True.import xlrd
xlrd_book = xlrd.open_workbook("path_to_file.xls", on_demand=True)
with pd.ExcelFile(xlrd_book) as xls:
df1 = pd.read_excel(xls, "Sheet1")
df2 = pd.read_excel(xls, "Sheet2")
Указание листов#
sheet_name, не путать с ExcelFile.sheet_names.sheet_names предоставляет доступ к списку листов.
sheet_name позволяет указать лист или листы для чтения.sheet_name равна 0, что указывает на чтение первого листаNone для возврата словаря всех доступных листов.# Returns a DataFrame
pd.read_excel("path_to_file.xls", "Sheet1", index_col=None, na_values=["NA"])
# Returns a DataFrame
pd.read_excel("path_to_file.xls", 0, index_col=None, na_values=["NA"])
# Returns a DataFrame
pd.read_excel("path_to_file.xls")
# Returns a dictionary of DataFrames
pd.read_excel("path_to_file.xls", sheet_name=None)
# Returns the 1st and 4th sheet, as a dictionary of DataFrames.
pd.read_excel("path_to_file.xls", sheet_name=["Sheet1", 3])
read_excel может читать более одного листа, установив sheet_name либо в список имён листов, список позиций листов, либо None чтобы прочитать все листы.
Листы могут быть указаны по индексу или имени листа, используя целое число или строку,
соответственно.Чтение
MultiIndex#read_excel может прочитать MultiIndex индекса, передавая список столбцов в index_col
и MultiIndex столбец, передавая список строк в header. Если любой из index
или columns если сериализованы имена уровней, они также будут прочитаны путем указания строк/столбцов, составляющих уровни.MultiIndex индекс без имён:In [424]: df = pd.DataFrame(
.....: {"a": [1, 2, 3, 4], "b": [5, 6, 7, 8]},
.....: index=pd.MultiIndex.from_product([["a", "b"], ["c", "d"]]),
.....: )
.....:
In [425]: df.to_excel("path_to_file.xlsx")
In [426]: df = pd.read_excel("path_to_file.xlsx", index_col=[0, 1])
In [427]: df
Out[427]:
a b
a c 1 5
d 2 6
b c 3 7
d 4 8
In [428]: df.index = df.index.set_names(["lvl1", "lvl2"])
In [429]: df.to_excel("path_to_file.xlsx")
In [430]: df = pd.read_excel("path_to_file.xlsx", index_col=[0, 1])
In [431]: df
Out[431]:
a b
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
MultiIndex индекс и столбцы, списки, указывающие каждый
должны быть переданы в index_col и header:In [432]: df.columns = pd.MultiIndex.from_product([["a"], ["b", "d"]], names=["c1", "c2"])
In [433]: df.to_excel("path_to_file.xlsx")
In [434]: df = pd.read_excel("path_to_file.xlsx", index_col=[0, 1], header=[0, 1])
In [435]: df
Out[435]:
c1 a
c2 b d
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
index_col будет заполнено вперёд
для обеспечения кругового преобразования с to_excel для merged_cells=True. Чтобы избежать заполнения пропущенных значений вперед, используйте set_index после чтения данных вместо
index_col.Парсинг определенных столбцов#
read_excel takes
a usecols ключевое слово, позволяющее указать подмножество столбцов для разбора.pd.read_excel("path_to_file.xls", "Sheet1", usecols="A,C:E")
usecols если это список целых чисел, то предполагается, что это индексы столбцов файла для парсинга.pd.read_excel("path_to_file.xls", "Sheet1", usecols=[0, 2, 3])
usecols=[0, 1] то же самое, что [1, 0].usecols является списком строк, предполагается, что каждая строка соответствует имени столбца, предоставленному либо пользователем в names или выводится из
заголовочной строки(строк) документа. Эти строки определяют, какие столбцы будут разобраны:pd.read_excel("path_to_file.xls", "Sheet1", usecols=["foo", "bar"])
usecols=['baz', 'joe'] то же самое, что ['joe', 'baz'].usecols является вызываемым, вызываемая функция будет оценена по именам столбцов, возвращая имена, где вызываемая функция оценивается как True.pd.read_excel("path_to_file.xls", "Sheet1", usecols=lambda x: x.isalpha())
Разбор дат#
parse_dates ключевое слово для преобразования этих строк в даты и время:pd.read_excel("path_to_file.xls", "Sheet1", parse_dates=["date_strings"])
Конвертеры ячеек#
converters
опция. Например, чтобы преобразовать столбец в логический тип:pd.read_excel("path_to_file.xls", "Sheet1", converters={"MyBools": bool})
def cfun(x):
return int(x) if x else -1
pd.read_excel("path_to_file.xls", "Sheet1", converters={"MyInts": cfun})
Спецификации типов данных#
dtype ключевое слово, которое принимает словарь
сопоставления имен столбцов с типами. Чтобы интерпретировать данные без
вывода типа, используйте тип str или object.pd.read_excel("path_to_file.xls", dtype={"MyInts": "int64", "MyText": str})
Запись файлов Excel#
Запись файлов Excel на диск#
DataFrame объект на лист файла Excel, вы можете использовать
to_excel метод экземпляра. Аргументы в основном такие же, как to_csv
описанному выше, первый аргумент — имя файла Excel, а
необязательный второй аргумент — имя листа, в который DataFrame должно быть
написано. Например:df.to_excel("path_to_file.xlsx", sheet_name="Sheet1")
.xlsx расширение будет записано с использованием xlsxwriter (если доступно) или
openpyxl.DataFrame будет записан таким образом, чтобы попытаться имитировать вывод REPL. index_label будет помещён во вторую
строку вместо первой. Вы можете поместить его в первую строку, установив
merge_cells опция в to_excel() to False:df.to_excel("path_to_file.xlsx", index_label="label", merge_cells=False)
DataFrames для разделения листов в одном файле Excel, можно передать ExcelWriter.with pd.ExcelWriter("path_to_file.xlsx") as writer:
df1.to_excel(writer, sheet_name="Sheet1")
df2.to_excel(writer, sheet_name="Sheet2")
engine_kwargs параметр, pandas передаст эти аргументы в
движок. Для этого важно знать, какую функцию pandas использует внутри.
openpyxl.Workbook() для создания нового листа и openpyxl.load_workbook() для добавления данных в существующий лист. Движок openpyxl записывает в (.xlsx) и (.xlsm) файлы.xlsxwriter.Workbook() для записи в (.xlsx) файлы.odf.opendocument.OpenDocumentSpreadsheet() для записи в (.ods) файлы.Запись файлов Excel в память#
StringIO или
BytesIO используя ExcelWriter.from io import BytesIO
bio = BytesIO()
# By setting the 'engine' in the ExcelWriter constructor.
writer = pd.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#
engine аргумент ключевого слова.xlsx, openpyxl
для .xlsm. Если у вас установлено несколько
движков, вы можете установить движок по умолчанию через установка
параметров конфигурации io.excel.xlsx.writer и
io.excel.xls.writer. pandas вернется к openpyxl для .xlsx
файлы, если Xlsxwriter недоступно.to_excel и для ExcelWriter. Встроенные движки:
openpyxl: требуется версия 2.4 или вышеxlsxwriter# By setting the 'engine' in the DataFrame 'to_excel()' methods.
df.to_excel("path_to_file.xlsx", sheet_name="Sheet1", engine="xlsxwriter")
# By setting the 'engine' in the ExcelWriter constructor.
writer = pd.ExcelWriter("path_to_file.xlsx", engine="xlsxwriter")
# Or via pandas configuration.
from pandas import options # noqa: E402
options.io.excel.xlsx.writer = "xlsxwriter"
df.to_excel("path_to_file.xlsx", sheet_name="Sheet1")
Стиль и форматирование#
DataFrame’s to_excel метод.
float_format : Строка формата для чисел с плавающей точкой (по умолчанию None).freeze_panes : Кортеж из двух целых чисел, представляющих самую нижнюю строку и самый правый столбец для закрепления. Каждый из этих параметров начинается с единицы, поэтому (1, 1) закрепит первую строку и первый столбец (по умолчанию None).to_excel метод. Отличные примеры можно найти в
Xlsxwriter документация здесь: https://xlsxwriter.readthedocs.io/working_with_pandas.htmlOpenDocument Spreadsheets#
engine='odf'. Необходимо установить опциональную зависимость 'odfpy'.read_excel() метод может читать электронные таблицы OpenDocument# Returns a DataFrame
pd.read_excel("path_to_file.ods", engine="odf")
to_excel() метод может записывать электронные таблицы OpenDocument# Writes DataFrame to a .ods file
df.to_excel("path_to_file.ods", engine="odf")
Бинарные файлы Excel (.xlsb)#
read_excel() метод также может читать двоичные файлы Excel
с помощью pyxlsb модуль. Семантика и возможности для чтения
двоичных файлов Excel в основном соответствуют тому, что можно сделать для Файлы Excel используя
engine='pyxlsb'. pyxlsb не распознает типы datetime
в файлах и будет возвращать числа с плавающей точкой вместо них (можно использовать calamine
если вам нужно распознавать типы datetime).# Returns a DataFrame
pd.read_excel("path_to_file.xlsb", engine="pyxlsb")
Calamine (файлы Excel и ODS)#
read_excel() метод может читать файл Excel (.xlsx, .xlsm, .xls, .xlsb)
и электронные таблицы OpenDocument (.ods) с использованием python-calamine xlsm calamine
и работает быстрее других движков в большинстве случаев. Необходимо установить опциональную зависимость 'python-calamine'.# Returns a DataFrame
pd.read_excel("path_to_file.xlsb", engine="calamine")
Буфер обмена#
read_clipboard() метод, который принимает содержимое буфера обмена и передает его
read_csv метод. Например, вы можете скопировать следующий текст в
буфер обмена (CTRL-C во многих операционных системах): A B C
x 1 4 p
y 2 5 q
z 3 6 r
DataFrame вызывая:>>> clipdf = pd.read_clipboard()
>>> clipdf
A B C
x 1 4 p
y 2 5 q
z 3 6 r
to_clipboard метод может использоваться для записи содержимого DataFrame в буфер обмена. После этого вы можете вставить содержимое буфера обмена в другие приложения (CTRL-V во многих операционных системах). Здесь мы показываем запись
DataFrame в буфер обмена и чтение обратно.>>> df = pd.DataFrame(
... {"A": [1, 2, 3], "B": [4, 5, 6], "C": ["p", "q", "r"]}, index=["x", "y", "z"]
... )
>>> df
A B C
x 1 4 p
y 2 5 q
z 3 6 r
>>> df.to_clipboard()
>>> pd.read_clipboard()
A B C
x 1 4 p
y 2 5 q
z 3 6 r
Сериализация (Pickling)#
to_pickle методы, использующие Python
cPickle модуль для сохранения структур данных на диск с использованием формата pickle.In [436]: df
Out[436]:
c1 a
c2 b d
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
In [437]: df.to_pickle("foo.pkl")
read_pickle функция в pandas пространство имен может использоваться для загрузки любого сохраненного объекта pandas (или любого другого сохраненного объекта) из файла:In [438]: pd.read_pickle("foo.pkl")
Out[438]:
c1 a
c2 b d
lvl1 lvl2
a c 1 5
d 2 6
b c 3 7
d 4 8
read_pickle() гарантируется обратная совместимость только на несколько минорных релизов назад.Сжатые файлы pickle#
read_pickle(), DataFrame.to_pickle() и Series.to_pickle() может читать и записывать сжатые pickle-файлы. Типы сжатия gzip, bz2, xz, zstd поддерживаются для чтения и записи.
zip формат файла поддерживает только чтение и должен содержать только один файл данных
для чтения.gzip, bz2, zip, xz, zstd если имя файла заканчивается на '.gz', '.bz2', '.zip',
'.xz', или '.zst', соответственно.dict чтобы передать параметры в
протокол сжатия. Он должен иметь 'method' ключ установлен в имя
протокола сжатия, который должен быть одним из
{'zip', 'gzip', 'bz2', 'xz', 'zstd'}. Все остальные пары ключ-значение передаются в базовую библиотеку сжатия.In [439]: df = pd.DataFrame(
.....: {
.....: "A": np.random.randn(1000),
.....: "B": "foo",
.....: "C": pd.date_range("20130101", periods=1000, freq="s"),
.....: }
.....: )
.....:
In [440]: df
Out[440]:
A B C
0 -0.317441 foo 2013-01-01 00:00:00
1 -1.236269 foo 2013-01-01 00:00:01
2 0.896171 foo 2013-01-01 00:00:02
3 -0.487602 foo 2013-01-01 00:00:03
4 -0.082240 foo 2013-01-01 00:00:04
.. ... ... ...
995 -0.171092 foo 2013-01-01 00:16:35
996 1.786173 foo 2013-01-01 00:16:36
997 -0.575189 foo 2013-01-01 00:16:37
998 0.820750 foo 2013-01-01 00:16:38
999 -1.256530 foo 2013-01-01 00:16:39
[1000 rows x 3 columns]
In [441]: df.to_pickle("data.pkl.compress", compression="gzip")
In [442]: rt = pd.read_pickle("data.pkl.compress", compression="gzip")
In [443]: rt
Out[443]:
A B C
0 -0.317441 foo 2013-01-01 00:00:00
1 -1.236269 foo 2013-01-01 00:00:01
2 0.896171 foo 2013-01-01 00:00:02
3 -0.487602 foo 2013-01-01 00:00:03
4 -0.082240 foo 2013-01-01 00:00:04
.. ... ... ...
995 -0.171092 foo 2013-01-01 00:16:35
996 1.786173 foo 2013-01-01 00:16:36
997 -0.575189 foo 2013-01-01 00:16:37
998 0.820750 foo 2013-01-01 00:16:38
999 -1.256530 foo 2013-01-01 00:16:39
[1000 rows x 3 columns]
In [444]: df.to_pickle("data.pkl.xz", compression="infer")
In [445]: rt = pd.read_pickle("data.pkl.xz", compression="infer")
In [446]: rt
Out[446]:
A B C
0 -0.317441 foo 2013-01-01 00:00:00
1 -1.236269 foo 2013-01-01 00:00:01
2 0.896171 foo 2013-01-01 00:00:02
3 -0.487602 foo 2013-01-01 00:00:03
4 -0.082240 foo 2013-01-01 00:00:04
.. ... ... ...
995 -0.171092 foo 2013-01-01 00:16:35
996 1.786173 foo 2013-01-01 00:16:36
997 -0.575189 foo 2013-01-01 00:16:37
998 0.820750 foo 2013-01-01 00:16:38
999 -1.256530 foo 2013-01-01 00:16:39
[1000 rows x 3 columns]
In [447]: df.to_pickle("data.pkl.gz")
In [448]: rt = pd.read_pickle("data.pkl.gz")
In [449]: rt
Out[449]:
A B C
0 -0.317441 foo 2013-01-01 00:00:00
1 -1.236269 foo 2013-01-01 00:00:01
2 0.896171 foo 2013-01-01 00:00:02
3 -0.487602 foo 2013-01-01 00:00:03
4 -0.082240 foo 2013-01-01 00:00:04
.. ... ... ...
995 -0.171092 foo 2013-01-01 00:16:35
996 1.786173 foo 2013-01-01 00:16:36
997 -0.575189 foo 2013-01-01 00:16:37
998 0.820750 foo 2013-01-01 00:16:38
999 -1.256530 foo 2013-01-01 00:16:39
[1000 rows x 3 columns]
In [450]: df["A"].to_pickle("s1.pkl.bz2")
In [451]: rt = pd.read_pickle("s1.pkl.bz2")
In [452]: rt
Out[452]:
0 -0.317441
1 -1.236269
2 0.896171
3 -0.487602
4 -0.082240
...
995 -0.171092
996 1.786173
997 -0.575189
998 0.820750
999 -1.256530
Name: A, Length: 1000, dtype: float64
In [453]: df.to_pickle("data.pkl.gz", compression={"method": "gzip", "compresslevel": 1})
msgpack#
msgpack был удален в версии 1.0.0. Рекомендуется использовать pickle вместо этого.HDF5 (PyTables)#
HDFStore является объектом, похожим на словарь, который читает и записывает pandas с использованием
высокопроизводительного формата HDF5 с помощью отличного PyTables библиотеки. См. cookbook
для некоторых продвинутых стратегийIn [454]: store = pd.HDFStore("store.h5")
In [455]: print(store)
In [456]: index = pd.date_range("1/1/2000", periods=8)
In [457]: s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"])
In [458]: df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=["A", "B", "C"])
# store.put('s', s) is an equivalent method
In [459]: store["s"] = s
In [460]: store["df"] = df
In [461]: store
Out[461]:
# store.get('df') is an equivalent method
In [462]: store["df"]
Out[462]:
A B C
2000-01-01 0.858644 -0.851236 1.058006
2000-01-02 -0.080372 -1.268121 1.561967
2000-01-03 0.816983 1.965656 -1.169408
2000-01-04 0.712795 -0.062433 0.736755
2000-01-05 -0.298721 -1.988045 1.475308
2000-01-06 1.103675 1.382242 -0.650762
2000-01-07 -0.729161 -0.142928 -1.063038
2000-01-08 -1.005977 0.465222 -0.094517
# dotted (attribute) access provides get as well
In [463]: store.df
Out[463]:
A B C
2000-01-01 0.858644 -0.851236 1.058006
2000-01-02 -0.080372 -1.268121 1.561967
2000-01-03 0.816983 1.965656 -1.169408
2000-01-04 0.712795 -0.062433 0.736755
2000-01-05 -0.298721 -1.988045 1.475308
2000-01-06 1.103675 1.382242 -0.650762
2000-01-07 -0.729161 -0.142928 -1.063038
2000-01-08 -1.005977 0.465222 -0.094517
# store.remove('df') is an equivalent method
In [464]: del store["df"]
In [465]: store
Out[465]:
In [466]: store.close()
In [467]: store
Out[467]:
API чтения/записи#
HDFStore поддерживает API верхнего уровня с использованием read_hdf для чтения и to_hdf для записи, аналогично тому, как read_csv и to_csv работа.In [470]: df_tl = pd.DataFrame({"A": list(range(5)), "B": list(range(5))})
In [471]: df_tl.to_hdf("store_tl.h5", key="table", append=True)
In [472]: pd.read_hdf("store_tl.h5", "table", where=["index>2"])
Out[472]:
A B
3 3 3
4 4 4
dropna=True.In [473]: df_with_missing = pd.DataFrame(
.....: {
.....: "col1": [0, np.nan, 2],
.....: "col2": [1, np.nan, np.nan],
.....: }
.....: )
.....:
In [474]: df_with_missing
Out[474]:
col1 col2
0 0.0 1.0
1 NaN NaN
2 2.0 NaN
In [475]: df_with_missing.to_hdf("file.h5", key="df_with_missing", format="table", mode="w")
In [476]: pd.read_hdf("file.h5", "df_with_missing")
Out[476]:
col1 col2
0 0.0 1.0
1 NaN NaN
2 2.0 NaN
In [477]: df_with_missing.to_hdf(
.....: "file.h5", key="df_with_missing", format="table", mode="w", dropna=True
.....: )
.....:
In [478]: pd.read_hdf("file.h5", "df_with_missing")
Out[478]:
col1 col2
0 0.0 1.0
2 2.0 NaN
Фиксированный формат#
put, который записывает HDF5 в PyTables в фиксированном формате массива, называемом fixed формат. Эти типы хранилищ не дополняемыми после записи (хотя вы можете просто
удалить их и перезаписать). Также они не являются queryable; они должны быть
извлечены полностью. Они также не поддерживают датафреймы с неуникальными именами столбцов.
fixed форматы хранилищ обеспечивают очень быструю запись и немного более быстрое чтение, чем table хранит.
Этот формат задается по умолчанию при использовании put или to_hdf или с помощью format='fixed' или format='f'.fixed формат вызовет TypeError если вы попытаетесь извлечь с помощью where:In [479]: pd.DataFrame(np.random.randn(10, 2)).to_hdf("test_fixed.h5", key="df")
In [480]: pd.read_hdf("test_fixed.h5", "df", where="index>5")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[480], line 1
----> 1 pd.read_hdf("test_fixed.h5", "df", where="index>5")
File ~/work/pandas/pandas/pandas/io/pytables.py:465, in read_hdf(path_or_buf, key, mode, errors, where, start, stop, columns, iterator, chunksize, **kwargs)
460 raise ValueError(
461 "key must be provided when HDF5 "
462 "file contains multiple datasets."
463 )
464 key = candidate_only_group._v_pathname
--> 465 return store.select(
466 key,
467 where=where,
468 start=start,
469 stop=stop,
470 columns=columns,
471 iterator=iterator,
472 chunksize=chunksize,
473 auto_close=auto_close,
474 )
475 except (ValueError, TypeError, LookupError):
476 if not isinstance(path_or_buf, HDFStore):
477 # if there is an error, close the store if we opened it.
File ~/work/pandas/pandas/pandas/io/pytables.py:919, in HDFStore.select(self, key, where, start, stop, columns, iterator, chunksize, auto_close)
905 # create the iterator
906 it = TableIterator(
907 self,
908 s,
(...)
916 auto_close=auto_close,
917 )
--> 919 return it.get_result()
File ~/work/pandas/pandas/pandas/io/pytables.py:2042, in TableIterator.get_result(self, coordinates)
2039 where = self.where
2041 # directly return the result
-> 2042 results = self.func(self.start, self.stop, where)
2043 self.close()
2044 return results
File ~/work/pandas/pandas/pandas/io/pytables.py:903, in HDFStore.select.
Формат таблицы#
HDFStore поддерживает другой PyTables формат на диске, table
формат. Концептуально table имеет структуру, очень похожую на DataFrame,
с строками и столбцами. A table может быть дополнен в той же или
других сессиях. Кроме того, поддерживаются операции удаления и запросов.
Этот формат задается format='table' или format='t'
to append или put или to_hdf.pd.set_option('io.hdf.default_format','table') для включения put/append/to_hdf по умолчанию сохранять в table формат.In [481]: store = pd.HDFStore("store.h5")
In [482]: df1 = df[0:4]
In [483]: df2 = df[4:]
# append data (creates a table automatically)
In [484]: store.append("df", df1)
In [485]: store.append("df", df2)
In [486]: store
Out[486]:
table передавая format='table' или format='t' в put операция.Иерархические ключи#
foo/bar/bah), который будет
генерировать иерархию подхранилищ (или Groups в терминологии PyTables
). Ключи могут быть указаны без ведущего '/' и всегда
абсолютный (например, 'foo' ссылается на '/foo'). Операции удаления могут удалить
всё в подхранилище и ниже, поэтому будьте осторожно.In [489]: store.put("foo/bar/bah", df)
In [490]: store.append("food/orange", df)
In [491]: store.append("food/apple", df)
In [492]: store
Out[492]:
walk метод, который будет возвращать кортеж для каждого ключа группы вместе с относительными ключами его содержимого.In [496]: for (path, subgroups, subkeys) in store.walk():
.....: for subgroup in subgroups:
.....: print("GROUP: {}/{}".format(path, subgroup))
.....: for subkey in subkeys:
.....: key = "/".join([path, subkey])
.....: print("KEY: {}".format(key))
.....: print(store.get(key))
.....:
GROUP: /foo
KEY: /df
A B C
2000-01-01 0.858644 -0.851236 1.058006
2000-01-02 -0.080372 -1.268121 1.561967
2000-01-03 0.816983 1.965656 -1.169408
2000-01-04 0.712795 -0.062433 0.736755
2000-01-05 -0.298721 -1.988045 1.475308
2000-01-06 1.103675 1.382242 -0.650762
2000-01-07 -0.729161 -0.142928 -1.063038
2000-01-08 -1.005977 0.465222 -0.094517
GROUP: /foo/bar
KEY: /foo/bar/bah
A B C
2000-01-01 0.858644 -0.851236 1.058006
2000-01-02 -0.080372 -1.268121 1.561967
2000-01-03 0.816983 1.965656 -1.169408
2000-01-04 0.712795 -0.062433 0.736755
2000-01-05 -0.298721 -1.988045 1.475308
2000-01-06 1.103675 1.382242 -0.650762
2000-01-07 -0.729161 -0.142928 -1.063038
2000-01-08 -1.005977 0.465222 -0.094517
In [497]: store.foo.bar.bah
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[497], line 1
----> 1 store.foo.bar.bah
File ~/work/pandas/pandas/pandas/io/pytables.py:626, in HDFStore.__getattr__(self, name)
624 """allow attribute access to get stores"""
625 try:
--> 626 return self.get(name)
627 except (KeyError, ClosedFileError):
628 pass
File ~/work/pandas/pandas/pandas/io/pytables.py:826, in HDFStore.get(self, key)
824 if group is None:
825 raise KeyError(f"No object named {key} in the file")
--> 826 return self._read_group(group)
File ~/work/pandas/pandas/pandas/io/pytables.py:1891, in HDFStore._read_group(self, group)
1890 def _read_group(self, group: Node):
-> 1891 s = self._create_storer(group)
1892 s.infer_axes()
1893 return s.read()
File ~/work/pandas/pandas/pandas/io/pytables.py:1765, in HDFStore._create_storer(self, group, format, value, encoding, errors)
1763 tt = "generic_table"
1764 else:
-> 1765 raise TypeError(
1766 "cannot create a storer if the object is not existing "
1767 "nor a value are passed"
1768 )
1769 else:
1770 if isinstance(value, Series):
TypeError: cannot create a storer if the object is not existing nor a value are passed
# you can directly access the actual PyTables node but using the root node
In [498]: store.root.foo.bar.bah
Out[498]:
/foo/bar/bah (Group) ''
children := ['axis0' (Array), 'axis1' (Array), 'block0_items' (Array), 'block0_values' (Array)]
In [499]: store["foo/bar/bah"]
Out[499]:
A B C
2000-01-01 0.858644 -0.851236 1.058006
2000-01-02 -0.080372 -1.268121 1.561967
2000-01-03 0.816983 1.965656 -1.169408
2000-01-04 0.712795 -0.062433 0.736755
2000-01-05 -0.298721 -1.988045 1.475308
2000-01-06 1.103675 1.382242 -0.650762
2000-01-07 -0.729161 -0.142928 -1.063038
2000-01-08 -1.005977 0.465222 -0.094517
Хранение типов#
Хранение смешанных типов в таблице#
ValueError.min_itemsize={`values`: size} в качестве параметра для append
установит большее минимальное значение для строковых столбцов. Хранение floats,
strings, ints, bools, datetime64 в настоящее время поддерживаются. Для строковых
столбцов, передача nan_rep = 'nan' для добавления изменит представление nan по умолчанию на диске (которое преобразуется в/из np.nan), по умолчанию
устанавливается в nan.In [500]: df_mixed = pd.DataFrame(
.....: {
.....: "A": np.random.randn(8),
.....: "B": np.random.randn(8),
.....: "C": np.array(np.random.randn(8), dtype="float32"),
.....: "string": "string",
.....: "int": 1,
.....: "bool": True,
.....: "datetime64": pd.Timestamp("20010102"),
.....: },
.....: index=list(range(8)),
.....: )
.....:
In [501]: df_mixed.loc[df_mixed.index[3:5], ["A", "B", "string", "datetime64"]] = np.nan
In [502]: store.append("df_mixed", df_mixed, min_itemsize={"values": 50})
In [503]: df_mixed1 = store.select("df_mixed")
In [504]: df_mixed1
Out[504]:
A B C ... int bool datetime64
0 0.013747 -1.166078 -1.292080 ... 1 True 1970-01-01 00:00:00.978393600
1 -0.712009 0.247572 1.526911 ... 1 True 1970-01-01 00:00:00.978393600
2 -0.645096 1.687406 0.288504 ... 1 True 1970-01-01 00:00:00.978393600
3 NaN NaN 0.097771 ... 1 True NaT
4 NaN NaN 1.536408 ... 1 True NaT
5 -0.023202 0.043702 0.926790 ... 1 True 1970-01-01 00:00:00.978393600
6 2.359782 0.088224 -0.676448 ... 1 True 1970-01-01 00:00:00.978393600
7 -0.143428 -0.813360 -0.179724 ... 1 True 1970-01-01 00:00:00.978393600
[8 rows x 7 columns]
In [505]: df_mixed1.dtypes.value_counts()
Out[505]:
float64 2
float32 1
object 1
int64 1
bool 1
datetime64[ns] 1
Name: count, dtype: int64
# we have provided a minimum string column size
In [506]: store.root.df_mixed.table
Out[506]:
/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": StringCol(itemsize=50, shape=(1,), dflt=b'', 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": Int64Col(shape=(1,), dflt=0, pos=6)}
byteorder := 'little'
chunkshape := (689,)
autoindex := True
colindexes := {
"index": Index(6, mediumshuffle, zlib(1)).is_csi=False}
Хранение DataFrame с MultiIndex#
DataFrames хранение/выборка из таблиц очень похожа на
хранение/выборку из однородного индекса DataFrames.In [507]: index = pd.MultiIndex(
.....: levels=[["foo", "bar", "baz", "qux"], ["one", "two", "three"]],
.....: codes=[[0, 0, 0, 1, 1, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 1, 2, 0, 1, 2]],
.....: names=["foo", "bar"],
.....: )
.....:
In [508]: df_mi = pd.DataFrame(np.random.randn(10, 3), index=index, columns=["A", "B", "C"])
In [509]: df_mi
Out[509]:
A B C
foo bar
foo one -1.303456 -0.642994 -0.649456
two 1.012694 0.414147 1.950460
three 1.094544 -0.802899 -0.583343
bar one 0.410395 0.618321 0.560398
two 1.434027 -0.033270 0.343197
baz two -1.646063 -0.695847 -0.429156
three -0.244688 -1.428229 -0.138691
qux one 1.866184 -1.446617 0.036660
two -1.660522 0.929553 -1.298649
three 3.565769 0.682402 1.041927
In [510]: store.append("df_mi", df_mi)
In [511]: store.select("df_mi")
Out[511]:
A B C
foo bar
foo one -1.303456 -0.642994 -0.649456
two 1.012694 0.414147 1.950460
three 1.094544 -0.802899 -0.583343
bar one 0.410395 0.618321 0.560398
two 1.434027 -0.033270 0.343197
baz two -1.646063 -0.695847 -0.429156
three -0.244688 -1.428229 -0.138691
qux one 1.866184 -1.446617 0.036660
two -1.660522 0.929553 -1.298649
three 3.565769 0.682402 1.041927
# the levels are automatically included as data columns
In [512]: store.select("df_mi", "foo=bar")
Out[512]:
A B C
foo bar
bar one 0.410395 0.618321 0.560398
two 1.434027 -0.033270 0.343197
index ключевое слово зарезервировано и не может использоваться как имя уровня.Запросы#
Запрос к таблице#
select и delete операции имеют необязательный критерий, который можно
указать для выбора/удаления только части данных. Это позволяет
иметь очень большую таблицу на диске и извлекать только часть данных.Term класс под капотом, как логическое выражение.
index и columns являются поддерживаемыми индексаторами для DataFrames.data_columns указаны, они могут использоваться как дополнительные индексаторы.level_0, level_1, … если не предоставлено.=, ==, !=, >, >=, <, <=
| : или& : и( и ) : для группировки
= будет автоматически расширен до оператора сравнения ==~ — это оператор not, но может использоваться только в очень ограниченных обстоятельствах.&
'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']"datestring = "HolyMoly'"
store.select("df", "index == string")
string = "HolyMoly'"
store.select('df', f'index == {string}')
SyntaxError. Обратите внимание, что здесь есть одинарная кавычка, за которой следует двойная кавычка в string
переменная.'%r' спецификатор форматаstore.select("df", "index == %r" % string)
string.In [513]: dfq = pd.DataFrame(
.....: np.random.randn(10, 4),
.....: columns=list("ABCD"),
.....: index=pd.date_range("20130101", periods=10),
.....: )
.....:
In [514]: store.append("dfq", dfq, format="table", data_columns=True)
In [515]: store.select("dfq", "index>pd.Timestamp('20130104') & columns=['A', 'B']")
Out[515]:
A B
2013-01-05 -0.830545 -0.457071
2013-01-06 0.431186 1.049421
2013-01-07 0.617509 -0.811230
2013-01-08 0.947422 -0.671233
2013-01-09 -0.183798 -1.211230
2013-01-10 0.361428 0.887304
In [516]: store.select("dfq", where="A>0 or C>0")
Out[516]:
A B C D
2013-01-02 0.658179 0.362814 -0.917897 0.010165
2013-01-03 0.905122 1.848731 -1.184241 0.932053
2013-01-05 -0.830545 -0.457071 1.565581 1.148032
2013-01-06 0.431186 1.049421 0.383309 0.595013
2013-01-07 0.617509 -0.811230 -2.088563 -1.393500
2013-01-08 0.947422 -0.671233 -0.847097 -1.187785
2013-01-10 0.361428 0.887304 0.266457 -0.399641
columns ключевое слово может быть предоставлено для выбора списка столбцов, которые будут возвращены, это эквивалентно передаче
'columns=list_of_columns_to_filter':In [517]: store.select("df", "columns=['A', 'B']")
Out[517]:
A B
2000-01-01 0.858644 -0.851236
2000-01-02 -0.080372 -1.268121
2000-01-03 0.816983 1.965656
2000-01-04 0.712795 -0.062433
2000-01-05 -0.298721 -1.988045
2000-01-06 1.103675 1.382242
2000-01-07 -0.729161 -0.142928
2000-01-08 -1.005977 0.465222
start и stop параметры могут быть указаны для ограничения общего пространства поиска. Они задаются в терминах общего количества строк в таблице.select вызовет ValueError если выражение запроса содержит неизвестную ссылку на переменную. Обычно это означает, что вы пытаетесь выбрать столбец, который не столбец данных.select вызовет SyntaxError если выражение запроса недействительно.Запрос timedelta64[нс]#
timedelta64[ns] тип. Условия могут быть указаны в формате: , где float может быть знаковым (и дробным), а unit может быть
D,s,ms,us,ns для timedelta. Вот пример:In [518]: from datetime import timedelta
In [519]: dftd = pd.DataFrame(
.....: {
.....: "A": pd.Timestamp("20130101"),
.....: "B": [
.....: pd.Timestamp("20130101") + timedelta(days=i, seconds=10)
.....: for i in range(10)
.....: ],
.....: }
.....: )
.....:
In [520]: dftd["C"] = dftd["A"] - dftd["B"]
In [521]: dftd
Out[521]:
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 [522]: store.append("dftd", dftd, data_columns=True)
In [523]: store.select("dftd", "C<'-3.5D'")
Out[523]:
A B C
4 1970-01-01 00:00:01.356998400 2013-01-05 00:00:10 -5 days +23:59:50
5 1970-01-01 00:00:01.356998400 2013-01-06 00:00:10 -6 days +23:59:50
6 1970-01-01 00:00:01.356998400 2013-01-07 00:00:10 -7 days +23:59:50
7 1970-01-01 00:00:01.356998400 2013-01-08 00:00:10 -8 days +23:59:50
8 1970-01-01 00:00:01.356998400 2013-01-09 00:00:10 -9 days +23:59:50
9 1970-01-01 00:00:01.356998400 2013-01-10 00:00:10 -10 days +23:59:50
Запрос MultiIndex#
MultiIndex может быть достигнуто с использованием имени уровня.In [524]: df_mi.index.names
Out[524]: FrozenList(['foo', 'bar'])
In [525]: store.select("df_mi", "foo=baz and bar=two")
Out[525]:
A B C
foo bar
baz two -1.646063 -0.695847 -0.429156
MultiIndex имена уровней None, уровни автоматически становятся доступными через level_n ключевое слово с n уровень MultiIndex из которых вы хотите выбрать.In [526]: index = pd.MultiIndex(
.....: levels=[["foo", "bar", "baz", "qux"], ["one", "two", "three"]],
.....: codes=[[0, 0, 0, 1, 1, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 1, 2, 0, 1, 2]],
.....: )
.....:
In [527]: df_mi_2 = pd.DataFrame(np.random.randn(10, 3), index=index, columns=["A", "B", "C"])
In [528]: df_mi_2
Out[528]:
A B C
foo one -0.219582 1.186860 -1.437189
two 0.053768 1.872644 -1.469813
three -0.564201 0.876341 0.407749
bar one -0.232583 0.179812 0.922152
two -1.820952 -0.641360 2.133239
baz two -0.941248 -0.136307 -1.271305
three -0.099774 -0.061438 -0.845172
qux one 0.465793 0.756995 -0.541690
two -0.802241 0.877657 -2.553831
three 0.094899 -2.319519 0.293601
In [529]: store.append("df_mi_2", df_mi_2)
# the levels are automatically included as data columns with keyword level_n
In [530]: store.select("df_mi_2", "level_0=foo and level_1=two")
Out[530]:
A B C
foo two 0.053768 1.872644 -1.469813
Индексирование#
create_table_index
после того, как данные уже в таблице (после и append/put
операцию). Создание индекса таблицы — это высоко рекомендуется. Это
значительно ускорит ваши запросы при использовании select с индексированным измерением в качестве where.index=False to append.# we have automagically already created an index (in the first section)
In [531]: i = store.root.df.table.cols.index.index
In [532]: i.optlevel, i.kind
Out[532]: (6, 'medium')
# change an index by passing new parameters
In [533]: store.create_table_index("df", optlevel=9, kind="full")
In [534]: i = store.root.df.table.cols.index.index
In [535]: i.optlevel, i.kind
Out[535]: (9, 'full')
In [536]: df_1 = pd.DataFrame(np.random.randn(10, 2), columns=list("AB"))
In [537]: df_2 = pd.DataFrame(np.random.randn(10, 2), columns=list("AB"))
In [538]: st = pd.HDFStore("appends.h5", mode="w")
In [539]: st.append("df", df_1, data_columns=["B"], index=False)
In [540]: st.append("df", df_2, data_columns=["B"], index=False)
In [541]: st.get_storer("df").table
Out[541]:
/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 [542]: st.create_table_index("df", columns=["B"], optlevel=9, kind="full")
In [543]: st.get_storer("df").table
Out[543]:
/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, fullshuffle, zlib(1)).is_csi=True}
In [544]: st.close()
Запрос через столбцы данных#
indexable столбцы, которые вы всегда можете
запросить). Например, предположим, вы хотите выполнить эту распространённую
операцию на диске и вернуть только фрейм, соответствующий этому
запросу. Вы можете указать data_columns = True чтобы принудительно сделать все столбцы data_columns.In [545]: df_dc = df.copy()
In [546]: df_dc["string"] = "foo"
In [547]: df_dc.loc[df_dc.index[4:6], "string"] = np.nan
In [548]: df_dc.loc[df_dc.index[7:9], "string"] = "bar"
In [549]: df_dc["string2"] = "cool"
In [550]: df_dc.loc[df_dc.index[1:3], ["B", "C"]] = 1.0
In [551]: df_dc
Out[551]:
A B C string string2
2000-01-01 0.858644 -0.851236 1.058006 foo cool
2000-01-02 -0.080372 1.000000 1.000000 foo cool
2000-01-03 0.816983 1.000000 1.000000 foo cool
2000-01-04 0.712795 -0.062433 0.736755 foo cool
2000-01-05 -0.298721 -1.988045 1.475308 NaN cool
2000-01-06 1.103675 1.382242 -0.650762 NaN cool
2000-01-07 -0.729161 -0.142928 -1.063038 foo cool
2000-01-08 -1.005977 0.465222 -0.094517 bar cool
# on-disk operations
In [552]: store.append("df_dc", df_dc, data_columns=["B", "C", "string", "string2"])
In [553]: store.select("df_dc", where="B > 0")
Out[553]:
A B C string string2
2000-01-02 -0.080372 1.000000 1.000000 foo cool
2000-01-03 0.816983 1.000000 1.000000 foo cool
2000-01-06 1.103675 1.382242 -0.650762 NaN cool
2000-01-08 -1.005977 0.465222 -0.094517 bar cool
# getting creative
In [554]: store.select("df_dc", "B > 0 & C > 0 & string == foo")
Out[554]:
A B C string string2
2000-01-02 -0.080372 1.0 1.0 foo cool
2000-01-03 0.816983 1.0 1.0 foo cool
# this is in-memory version of this type of selection
In [555]: df_dc[(df_dc.B > 0) & (df_dc.C > 0) & (df_dc.string == "foo")]
Out[555]:
A B C string string2
2000-01-02 -0.080372 1.0 1.0 foo cool
2000-01-03 0.816983 1.0 1.0 foo cool
# we have automagically created this index and the B/C/string/string2
# columns are stored separately as ``PyTables`` columns
In [556]: store.root.df_dc.table
Out[556]:
/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=b'', pos=4),
"string2": StringCol(itemsize=4, shape=(), dflt=b'', pos=5)}
byteorder := 'little'
chunkshape := (1680,)
autoindex := True
colindexes := {
"index": Index(6, mediumshuffle, zlib(1)).is_csi=False,
"B": Index(6, mediumshuffle, zlib(1)).is_csi=False,
"C": Index(6, mediumshuffle, zlib(1)).is_csi=False,
"string": Index(6, mediumshuffle, zlib(1)).is_csi=False,
"string2": Index(6, mediumshuffle, zlib(1)).is_csi=False}
data columns, поэтому пользователь должен их обозначить. Кроме того,
вы не можете изменять столбцы данных (ни индексируемые) после первой
операции добавления/помещения (Конечно, вы можете просто прочитать данные и
создать новую таблицу!).Итератор#
iterator=True или chunksize=number_in_a_chunk
to select и select_as_multiple чтобы возвращать итератор по результатам.
По умолчанию возвращается 50 000 строк в чанке.In [557]: for df in store.select("df", chunksize=3):
.....: print(df)
.....:
A B C
2000-01-01 0.858644 -0.851236 1.058006
2000-01-02 -0.080372 -1.268121 1.561967
2000-01-03 0.816983 1.965656 -1.169408
A B C
2000-01-04 0.712795 -0.062433 0.736755
2000-01-05 -0.298721 -1.988045 1.475308
2000-01-06 1.103675 1.382242 -0.650762
A B C
2000-01-07 -0.729161 -0.142928 -1.063038
2000-01-08 -1.005977 0.465222 -0.094517
read_hdf который откроет, а затем автоматически закроет хранилище после завершения итерации.for df in pd.read_hdf("store.h5", "df", chunksize=3):
print(df)
In [558]: dfeq = pd.DataFrame({"number": np.arange(1, 11)})
In [559]: dfeq
Out[559]:
number
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
In [560]: store.append("dfeq", dfeq, data_columns=["number"])
In [561]: def chunks(l, n):
.....: return [l[i: i + n] for i in range(0, len(l), n)]
.....:
In [562]: evens = [2, 4, 6, 8, 10]
In [563]: coordinates = store.select_as_coordinates("dfeq", "number=evens")
In [564]: 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 [565]: store.select_column("df_dc", "index")
Out[565]:
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 [566]: store.select_column("df_dc", "string")
Out[566]:
0 foo
1 foo
2 foo
3 foo
4 NaN
5 NaN
6 foo
7 bar
Name: string, dtype: object
Выбор координат#
Index результирующих позиций. Эти координаты также можно передать в последующие
where операции.In [567]: df_coord = pd.DataFrame(
.....: np.random.randn(1000, 2), index=pd.date_range("20000101", periods=1000)
.....: )
.....:
In [568]: store.append("df_coord", df_coord)
In [569]: c = store.select_as_coordinates("df_coord", "index > 20020101")
In [570]: c
Out[570]:
Index([732, 733, 734, 735, 736, 737, 738, 739, 740, 741,
...
990, 991, 992, 993, 994, 995, 996, 997, 998, 999],
dtype='int64', length=268)
In [571]: store.select("df_coord", where=c)
Out[571]:
0 1
2002-01-02 0.007717 1.168386
2002-01-03 0.759328 -0.638934
2002-01-04 -1.154018 -0.324071
2002-01-05 -0.804551 -1.280593
2002-01-06 -0.047208 1.260503
... ... ...
2002-09-22 -1.139583 0.344316
2002-09-23 -0.760643 -1.306704
2002-09-24 0.059018 1.775482
2002-09-25 1.242255 -0.055457
2002-09-26 0.410317 2.194489
[268 rows x 2 columns]
Выбор с использованием маски where#
mask будет
результирующим index из операции индексирования. Этот пример выбирает месяцы datetimeindex, которые равны 5.In [572]: df_mask = pd.DataFrame(
.....: np.random.randn(1000, 2), index=pd.date_range("20000101", periods=1000)
.....: )
.....:
In [573]: store.append("df_mask", df_mask)
In [574]: c = store.select_column("df_mask", "index")
In [575]: where = c[pd.DatetimeIndex(c).month == 5].index
In [576]: store.select("df_mask", where=where)
Out[576]:
0 1
2000-05-01 1.479511 0.516433
2000-05-02 -0.334984 -1.493537
2000-05-03 0.900321 0.049695
2000-05-04 0.614266 -1.077151
2000-05-05 0.233881 0.493246
... ... ...
2002-05-27 0.294122 0.457407
2002-05-28 -1.102535 1.215650
2002-05-29 -0.432911 0.753606
2002-05-30 -1.105212 2.311877
2002-05-31 2.567296 2.610691
[93 rows x 2 columns]
Объект Storer#
get_storer. Вы можете использовать это программно, чтобы, например, получить количество
строк в объекте.In [577]: store.get_storer("df_dc").nrows
Out[577]: 8
Запросы к нескольким таблицам#
append_to_multiple и
select_as_multiple может выполнять добавление/выборку из
нескольких таблиц одновременно. Идея состоит в том, чтобы иметь одну таблицу (назовем ее
таблицей-селектором), в которой индексируется большинство/все столбцы, и выполнять запросы
по ней. Другие таблицы — это таблицы данных с индексом, соответствующим
индексу таблицы-селектора. Затем можно выполнить очень быстрый запрос
к таблице-селектору, но получить много данных. Этот метод похож на
использование очень широкой таблицы, но позволяет выполнять более эффективные запросы.append_to_multiple метод разделяет заданный DataFrame
на несколько таблиц в соответствии с d, словарь, который сопоставляет
имена таблиц со списком 'столбцов', которые вы хотите в этой таблице. Если None
используется вместо списка, эта таблица будет содержать оставшиеся
неуказанные столбцы данного DataFrame. Аргумент selector
определяет, какая таблица является таблицей-селектором (из которой можно делать запросы).
Аргумент dropna будет удалять строки из входных данных DataFrame чтобы обеспечить синхронизацию таблиц. Это означает, что если строка для одной из записываемых таблиц полностью np.nan, эта строка будет удалена из всех таблиц.dropna равно False, ПОЛЬЗОВАТЕЛЬ ОТВЕЧАЕТ ЗА СИНХРОНИЗАЦИЮ ТАБЛИЦ.
Помните, что полностью np.Nan строки не записываются в HDFStore, поэтому если
вы решите вызвать dropna=False, некоторые таблицы могут иметь больше строк, чем другие,
и поэтому select_as_multiple может не работать или возвращать неожиданные результаты.In [578]: df_mt = pd.DataFrame(
.....: np.random.randn(8, 6),
.....: index=pd.date_range("1/1/2000", periods=8),
.....: columns=["A", "B", "C", "D", "E", "F"],
.....: )
.....:
In [579]: df_mt["foo"] = "bar"
In [580]: df_mt.loc[df_mt.index[1], ("A", "B")] = np.nan
# you can also create the tables individually
In [581]: store.append_to_multiple(
.....: {"df1_mt": ["A", "B"], "df2_mt": None}, df_mt, selector="df1_mt"
.....: )
.....:
In [582]: store
Out[582]:
Удалить из таблицы#
where. При
удалении строк важно понимать PyTables удаляет
строки, стирая строки, затем перемещение следующие данные. Таким образом, удаление потенциально может быть очень затратной операцией в зависимости от ориентации ваших данных. Для оптимальной производительности стоит сделать измерение, которое вы удаляете, первым из
indexables.indexables. Вот простой пример использования. Вы храните данные панельного типа с датами в
major_axis и идентификаторы в minor_axis. Затем данные
перемежаются следующим образом:
major_axis будет довольно быстрым, так как один фрагмент удаляется, а затем следующие данные перемещаются. С другой стороны, операция удаления на minor_axis будет очень затратно. В этом случае почти наверняка будет быстрее переписать таблицу, используя where который выбирает все, кроме пропущенных данных.Примечания и ограничения#
Сжатие#
PyTables позволяет сжимать хранимые данные. Это относится ко
всем видам хранилищ, а не только к таблицам. Для управления сжатием
используются два параметра: complevel и complib.
complevel определяет, нужно ли и насколько сильно сжимать данные.
complevel=0 и complevel=None отключает сжатие и
0 включает сжатие.complib указывает, какую библиотеку сжатия использовать.
Если ничего не указано, используется библиотека по умолчанию zlib используется. Библиотека сжатия обычно оптимизируется либо для хороших коэффициентов сжатия, либо для скорости, и результаты будут зависеть от типа данных. Какой тип сжатия выбрать, зависит от ваших конкретных потребностей и данных. Список поддерживаемых библиотек сжатия:
blosccomplib определяется как что-то иное, чем перечисленные библиотеки,
ValueError выдается исключение.complib опция отсутствует на вашей платформе,
сжатие по умолчанию устанавливается в zlib без дальнейших церемоний.store_compressed = pd.HDFStore(
"store_compressed.h5", complevel=9, complib="blosc:blosclz"
)
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 поддерживает только параллельное чтение (через потоки или
процессы). Если требуется чтение и запись одновременно, вам
нужно сериализовать эти операции в одном потоке в одном
процессе. В противном случае вы повредите свои данные. Смотрите (GH 2397) для получения дополнительной информации.
fsync() перед снятием блокировок записи. Для
удобства вы можете использовать store.flush(fsync=True) сделать это за вас.table создаются столбцы (DataFrame) фиксированными; можно добавлять только точно такие же столбцыpytz.timezone('US/Eastern'))
не обязательно равны между версиями часовых поясов. Поэтому если данные
локализованы в определенный часовой пояс в HDFStore с использованием одной версии
библиотеки часовых поясов, и эти данные обновляются другой версией, данные
будут преобразованы в UTC, поскольку эти часовые пояса не считаются
равными. Используйте либо ту же версию библиотеки часовых поясов, либо используйте tz_convert с обновленным определением часового пояса.PyTables покажет NaturalNameWarning если имя столбца
не может быть использовано как селектор атрибутов.
Естественный идентификаторы содержат только буквы, цифры и подчёркивания и не могут начинаться с цифры. Другие идентификаторы не могут использоваться в where предложением
и обычно являются плохой идеей.Типы данных#
HDFStore будет сопоставлять тип данных object с PyTables базовый
dtype. Это означает, что следующие типы известны как работающие:
float64, float32, float16np.nanint64, int32, int8, uint64,uint32, uint8
datetime64[ns]NaTtimedelta64[ns]NaT
stringsnp.nanunicode столбцы не поддерживаются, и НЕ СРАБОТАЕТ.Категориальные данные#
category типы данных в HDFStore.
Запросы работают так же, как если бы это был массив объектов. Однако category данные с типом dtype хранятся более эффективным способом.In [586]: dfcat = pd.DataFrame(
.....: {"A": pd.Series(list("aabbcdba")).astype("category"), "B": np.random.randn(8)}
.....: )
.....:
In [587]: dfcat
Out[587]:
A B
0 a -1.520478
1 a -1.069391
2 b -0.551981
3 b 0.452407
4 c 0.409257
5 d 0.301911
6 b -0.640843
7 a -2.253022
In [588]: dfcat.dtypes
Out[588]:
A category
B float64
dtype: object
In [589]: cstore = pd.HDFStore("cats.h5", mode="w")
In [590]: cstore.append("dfcat", dfcat, format="table", data_columns=["A"])
In [591]: result = cstore.select("dfcat", where="A in ['b', 'c']")
In [592]: result
Out[592]:
A B
2 b -0.551981
3 b 0.452407
4 c 0.409257
6 b -0.640843
In [593]: result.dtypes
Out[593]:
A category
B float64
dtype: object
Строковые столбцы#
HDFStore использует фиксированную ширину столбца (размер элемента) для строковых столбцов.
Размер элемента строкового столбца вычисляется как максимум
длины данных (для этого столбца), которые передаются в HDFStore, в первом добавлении. Последующие добавления
могут ввести строку для столбца больше чем может вместить столбец, будет вызвано исключение (в противном случае вы
можете получить тихое усечение этих столбцов, приводящее к потере информации). В будущем мы можем ослабить это и
разрешить пользовательское усечение.min_itemsize при первом создании таблицы, чтобы заранее указать минимальную длину конкретного строкового столбца.
min_itemsize может быть целым числом или словарём, сопоставляющим имя столбца с целым числом. Вы можете передать values в качестве ключа для
разрешения всех индексируемые объекты или data_columns для установки этого min_itemsize.min_itemsize dict приведет к созданию всех переданных столбцов как data_columns автоматически.data_columns, тогда min_itemsize будет максимальной длиной любой переданной строкиIn [594]: dfs = pd.DataFrame({"A": "foo", "B": "bar"}, index=list(range(5)))
In [595]: dfs
Out[595]:
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 [596]: store.append("dfs", dfs, min_itemsize=30)
In [597]: store.get_storer("dfs").table
Out[597]:
/dfs/table (Table(5,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": StringCol(itemsize=30, shape=(2,), dflt=b'', pos=1)}
byteorder := 'little'
chunkshape := (963,)
autoindex := True
colindexes := {
"index": Index(6, mediumshuffle, zlib(1)).is_csi=False}
# A is created as a data_column with a size of 30
# B is size is calculated
In [598]: store.append("dfs2", dfs, min_itemsize={"A": 30})
In [599]: store.get_storer("dfs2").table
Out[599]:
/dfs2/table (Table(5,)) ''
description := {
"index": Int64Col(shape=(), dflt=0, pos=0),
"values_block_0": StringCol(itemsize=3, shape=(1,), dflt=b'', pos=1),
"A": StringCol(itemsize=30, shape=(), dflt=b'', pos=2)}
byteorder := 'little'
chunkshape := (1598,)
autoindex := True
colindexes := {
"index": Index(6, mediumshuffle, zlib(1)).is_csi=False,
"A": Index(6, mediumshuffle, zlib(1)).is_csi=False}
np.nan (пропущенное значение) с nan_rep строковое представление. По умолчанию используется строковое значение nan.
Вы могли случайно превратить фактический nan значение в пропущенное значение.In [600]: dfss = pd.DataFrame({"A": ["foo", "bar", "nan"]})
In [601]: dfss
Out[601]:
A
0 foo
1 bar
2 nan
In [602]: store.append("dfss", dfss)
In [603]: store.select("dfss")
Out[603]:
A
0 foo
1 bar
2 NaN
# here you need to specify a different nan rep
In [604]: store.append("dfss2", dfss, nan_rep="_nan_")
In [605]: store.select("dfss2")
Out[605]:
A
0 foo
1 bar
2 nan
Производительность#
tables формат имеет штраф производительности при записи по сравнению с
fixed хранилища. Преимущество - возможность добавления/удаления и
запроса (потенциально очень больших объемов данных). Время записи
обычно больше по сравнению с обычными хранилищами. Время запроса может
быть довольно быстрым, особенно по индексированной оси.chunksize= to append, указание размера чанков для записи (по умолчанию 50000). Это значительно снизит использование памяти при записи.expectedrows= к первому append,
чтобы установить ОБЩЕЕ количество строк, которые PyTables будет ожидать.
Это оптимизирует производительность чтения/записи.PerformanceWarning будет вызвано, если вы пытаетесь
сохранить типы, которые будут сериализованы PyTables (а не сохранены как
встроенные типы). См.
Здесь
для получения дополнительной информации и некоторых решений.Feather#
Index, или MultiIndex для
DataFrame и вызовет ошибку, если предоставлен нестандартный. Вы
можете .reset_index() для хранения индекса или .reset_index(drop=True) чтобы игнорировать это.In [606]: df = pd.DataFrame(
.....: {
.....: "a": list("abc"),
.....: "b": list(range(1, 4)),
.....: "c": np.arange(3, 6).astype("u1"),
.....: "d": np.arange(4.0, 7.0, dtype="float64"),
.....: "e": [True, False, True],
.....: "f": pd.Categorical(list("abc")),
.....: "g": pd.date_range("20130101", periods=3),
.....: "h": pd.date_range("20130101", periods=3, tz="US/Eastern"),
.....: "i": pd.date_range("20130101", periods=3, freq="ns"),
.....: }
.....: )
.....:
In [607]: df
Out[607]:
a b c ... g h i
0 a 1 3 ... 2013-01-01 2013-01-01 00:00:00-05:00 2013-01-01 00:00:00.000000000
1 b 2 4 ... 2013-01-02 2013-01-02 00:00:00-05:00 2013-01-01 00:00:00.000000001
2 c 3 5 ... 2013-01-03 2013-01-03 00:00:00-05:00 2013-01-01 00:00:00.000000002
[3 rows x 9 columns]
In [608]: df.dtypes
Out[608]:
a object
b int64
c uint8
d float64
e bool
f category
g datetime64[ns]
h datetime64[ns, US/Eastern]
i datetime64[ns]
dtype: object
In [609]: df.to_feather("example.feather")
In [610]: result = pd.read_feather("example.feather")
In [611]: result
Out[611]:
a b c ... g h i
0 a 1 3 ... 2013-01-01 2013-01-01 00:00:00-05:00 2013-01-01 00:00:00.000000000
1 b 2 4 ... 2013-01-02 2013-01-02 00:00:00-05:00 2013-01-01 00:00:00.000000001
2 c 3 5 ... 2013-01-03 2013-01-03 00:00:00-05:00 2013-01-01 00:00:00.000000002
[3 rows x 9 columns]
# we preserve dtypes
In [612]: result.dtypes
Out[612]:
a object
b int64
c uint8
d float64
e bool
f category
g datetime64[ns]
h datetime64[ns, US/Eastern]
i datetime64[ns]
dtype: object
Parquet#
DataFrame s, поддерживающий все типы данных pandas, включая расширенные типы, такие как datetime с часовым поясом.
pyarrow движок всегда записывает индекс в вывод, но fastparquet записывает только нестандартные индексы. Этот дополнительный столбец может вызывать проблемы для потребителей, не использующих pandas, которые его не ожидают. Вы можете принудительно включать или исключать индексы с помощью index аргумент, независимо от базового движка.pyarrow движок, категориальные типы данных для нестроковых типов могут быть сериализованы в parquet, но будут десериализованы как их примитивный тип данных.pyarrow движок сохраняет ordered флаг категориальных dtypes со строковыми типами. fastparquet не сохраняет ordered флаг.Interval и фактические типы объектов Python. Они вызовут полезное сообщение об ошибке при попытке сериализации. Period тип поддерживается с pyarrow >= 0.16.0.pyarrow движок сохраняет расширенные типы данных, такие как nullable integer и string data type (требуется pyarrow >= 0.16.0 и чтобы расширенный тип реализовывал необходимые протоколы, см. документация по типам расширений).engine для управления сериализацией. Это может быть один из pyarrow, или fastparquet, или auto.
Если движок НЕ указан, то pd.options.io.parquet.engine опция проверяется; если это также auto,
затем pyarrow пробуется, и откат к fastparquet.pyarrow>=8.0.0 поддерживает данные типа timedelta, fastparquet>=0.1.4 поддерживает даты с учетом часового пояса.
Эти библиотеки отличаются наличием различных базовых зависимостей (fastparquet используя numba, в то время как pyarrow использует c-библиотеку).In [613]: df = pd.DataFrame(
.....: {
.....: "a": list("abc"),
.....: "b": list(range(1, 4)),
.....: "c": np.arange(3, 6).astype("u1"),
.....: "d": np.arange(4.0, 7.0, dtype="float64"),
.....: "e": [True, False, True],
.....: "f": pd.date_range("20130101", periods=3),
.....: "g": pd.date_range("20130101", periods=3, tz="US/Eastern"),
.....: "h": pd.Categorical(list("abc")),
.....: "i": pd.Categorical(list("abc"), ordered=True),
.....: }
.....: )
.....:
In [614]: df
Out[614]:
a b c d e f g h i
0 a 1 3 4.0 True 2013-01-01 2013-01-01 00:00:00-05:00 a a
1 b 2 4 5.0 False 2013-01-02 2013-01-02 00:00:00-05:00 b b
2 c 3 5 6.0 True 2013-01-03 2013-01-03 00:00:00-05:00 c c
In [615]: df.dtypes
Out[615]:
a object
b int64
c uint8
d float64
e bool
f datetime64[ns]
g datetime64[ns, US/Eastern]
h category
i category
dtype: object
In [616]: df.to_parquet("example_pa.parquet", engine="pyarrow")
In [617]: df.to_parquet("example_fp.parquet", engine="fastparquet")
In [618]: result = pd.read_parquet("example_fp.parquet", engine="fastparquet")
In [619]: result = pd.read_parquet("example_pa.parquet", engine="pyarrow")
In [620]: result.dtypes
Out[620]:
a object
b int64
c uint8
d float64
e bool
f datetime64[ns]
g datetime64[ns, US/Eastern]
h category
i category
dtype: object
dtype_backend аргумент позволяет управлять типами данных по умолчанию для результирующего DataFrame.In [621]: result = pd.read_parquet("example_pa.parquet", engine="pyarrow", dtype_backend="pyarrow")
In [622]: result.dtypes
Out[622]:
a string[pyarrow]
b int64[pyarrow]
c uint8[pyarrow]
d double[pyarrow]
e bool[pyarrow]
f timestamp[ns][pyarrow]
g timestamp[ns, tz=US/Eastern][pyarrow]
h dictionary
fastparquet.In [623]: result = pd.read_parquet(
.....: "example_fp.parquet",
.....: engine="fastparquet",
.....: columns=["a", "b"],
.....: )
.....:
In [624]: result = pd.read_parquet(
.....: "example_pa.parquet",
.....: engine="pyarrow",
.....: columns=["a", "b"],
.....: )
.....:
In [625]: result.dtypes
Out[625]:
a object
b int64
dtype: object
Обработка индексов#
DataFrame При сохранении в формат parquet неявный индекс может быть включен как одна или несколько колонок в выходном файле. Таким образом, этот код:In [626]: df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
In [627]: df.to_parquet("test.parquet", engine="pyarrow")
pyarrow для сериализации:
a, b, и __index_level_0__. Если вы используете fastparquet, индекс может или не может
будет записано в файл.index=False to
to_parquet():In [628]: df.to_parquet("test.parquet", index=False)
a и b.
Если ваш DataFrame имеет пользовательский индекс, вы не получите его обратно при загрузке этого файла в DataFrame.index=True будет всегда записывать индекс, даже если это не
поведение по умолчанию базового движка.Разделение файлов Parquet#
In [629]: df = pd.DataFrame({"a": [0, 0, 1, 1], "b": [0, 1, 0, 1]})
In [630]: df.to_parquet(path="test", engine="pyarrow", partition_cols=["a"], compression=None)
path указывает родительский каталог, в который будут сохранены данные.
partition_cols являются именами столбцов, по которым набор данных будет разделён. Столбцы разделяются в порядке их указания. Разделы разделов определяются уникальными значениями в столбцах разделов. Приведённый выше пример создаёт разделённый набор данных, который может выглядеть так:test
├── a=0
│ ├── 0bac803e32dc42ae83fddfd029cbdebc.parquet
│ └── ...
└── a=1
├── e6ab24a4f45147b49b54a662f0c412a3.parquet
└── ...
ORC#
read_orc() и to_orc(). Это требует pyarrow библиотека.
to_orc() требует pyarrow>=7.0.0.read_orc() и to_orc() не поддерживаются в Windows пока, вы можете найти подходящие среды на установить дополнительные зависимости.In [631]: df = pd.DataFrame(
.....: {
.....: "a": list("abc"),
.....: "b": list(range(1, 4)),
.....: "c": np.arange(4.0, 7.0, dtype="float64"),
.....: "d": [True, False, True],
.....: "e": pd.date_range("20130101", periods=3),
.....: }
.....: )
.....:
In [632]: df
Out[632]:
a b c d e
0 a 1 4.0 True 2013-01-01
1 b 2 5.0 False 2013-01-02
2 c 3 6.0 True 2013-01-03
In [633]: df.dtypes
Out[633]:
a object
b int64
c float64
d bool
e datetime64[ns]
dtype: object
In [634]: df.to_orc("example_pa.orc", engine="pyarrow")
In [635]: result = pd.read_orc("example_pa.orc")
In [636]: result.dtypes
Out[636]:
a object
b int64
c float64
d bool
e datetime64[ns]
dtype: object
In [637]: result = pd.read_orc(
.....: "example_pa.orc",
.....: columns=["a", "b"],
.....: )
.....:
In [638]: result.dtypes
Out[638]:
a object
b int64
dtype: object
SQL-запросы#
pandas.io.sql модуль предоставляет набор обёрток запросов для облегчения извлечения данных и уменьшения зависимости от API конкретной базы данных.
sqlite3.Connection вместо движка, соединения или строки URI SQLAlchemy.
read_sql_table(table_name, con[, schema, ...])read_sql_query(sql, con[, index_col, ...])read_sql(sql, con[, index_col, ...])DataFrame.to_sql(name, con, *[, schema, ...])read_sql() является удобной оберткой вокруг
read_sql_table() и read_sql_query() (и для
обратной совместимости) и будет делегировать конкретной функции в зависимости от
предоставленного ввода (имя таблицы базы данных или SQL-запрос).
Имена таблиц не нужно заключать в кавычки, если они содержат специальные символы.adbc_driver_sqlite используя ваш менеджер пакетов. После установки вы можете использовать интерфейс DBAPI, предоставляемый драйвером ADBC, для подключения к вашей базе данных.import adbc_driver_sqlite.dbapi as sqlite_dbapi
# Create the connection
with sqlite_dbapi.connect("sqlite:///:memory:") as conn:
df = pd.read_sql_table("data", conn)
create_engine() функция для создания объекта движка
из URI базы данных. Вам нужно создать движок только один раз для каждой базы данных, к которой вы
подключаетесь.
Для получения дополнительной информации о create_engine() и форматирование URI, см. примеры
ниже и SQLAlchemy документацияIn [639]: from sqlalchemy import create_engine
# Create your engine.
In [640]: engine = create_engine("sqlite:///:memory:")
with engine.connect() as conn, conn.begin():
data = pd.read_sql_table("data", conn)
Запись DataFrames#
DataFrame data, мы можем вставить его
в базу данных, используя to_sql().
In [641]: import datetime
In [642]: c = ["id", "Date", "Col_1", "Col_2", "Col_3"]
In [643]: d = [
.....: (26, datetime.datetime(2010, 10, 18), "X", 27.5, True),
.....: (42, datetime.datetime(2010, 10, 19), "Y", -12.5, False),
.....: (63, datetime.datetime(2010, 10, 20), "Z", 5.73, True),
.....: ]
.....:
In [644]: data = pd.DataFrame(d, columns=c)
In [645]: data
Out[645]:
id Date Col_1 Col_2 Col_3
0 26 2010-10-18 X 27.50 True
1 42 2010-10-19 Y -12.50 False
2 63 2010-10-20 Z 5.73 True
In [646]: data.to_sql("data", con=engine)
Out[646]: 3
chunksize параметр при вызове to_sql. Например, следующее
записывает data в базу данных партиями по 1000 строк за раз:In [647]: data.to_sql("data_chunked", con=engine, chunksize=1000)
Out[647]: 3
Типы данных SQL#
bool_
dtype_backend="pyarrow" аргумент read_sql()# for roundtripping
with pg_dbapi.connect(uri) as conn:
df2 = pd.read_sql("pandas_table", conn, dtype_backend="pyarrow")
to_sql()
попытается сопоставить ваши данные с подходящим типом данных SQL на основе dtype данных. Когда у вас есть столбцы с dtype object, pandas попытается вывести
тип данных.dtype аргумент. Этот аргумент требует
словарь, сопоставляющий имена столбцов с типами SQLAlchemy (или строками для режима отката sqlite3).
Например, указание использовать sqlalchemy String тип вместо
стандартного Text тип для строковых столбцов:In [648]: from sqlalchemy.types import String
In [649]: data.to_sql("data_dtype", con=engine, dtype={"Col_1": String})
Out[649]: 3
timedelta64 будет записано как целочисленные
значения в наносекундах в базу данных, и будет выдано предупреждение. Единственное
исключение — при использовании драйвера ADBC PostgreSQL, в этом случае
интервал времени будет записан в базу данных как INTERVALcategory тип данных будет преобразован в плотное представление,
как вы получили бы с np.asarray(categorical) (например, для строковых категорий
это даёт массив строк).
Из-за этого чтение таблицы базы данных обратно не создать категориальный тип.Типы данных даты и времени#
to_sql() способен записывать данные datetime, которые не учитывают часовой пояс или учитывают его. Однако итоговые данные, хранящиеся в базе данных, в конечном счете зависят от поддерживаемого типа данных для данных datetime в используемой системе баз данных.
TEXTTIMESTAMP или DATETIMETIMESTAMP или TIMESTAMP WITH TIME ZONEread_sql_table() также способен читать данные даты и времени, которые
учитывают часовой пояс или не учитывают. При чтении TIMESTAMP WITH TIME ZONE типы, pandas
будет преобразовывать данные в UTC.Метод вставки#
method управляет предложением вставки SQL, которое используется. Возможные значения:
None: Использует стандартный SQL INSERT условие (по одному на строку).'multi': Передать несколько значений в одном INSERT предложение.
Использует специальный Синтаксис SQL не поддерживается всеми бэкендами.
Обычно это обеспечивает лучшую производительность для аналитических баз данных,
таких как Presto и Redshift, но имеет худшую производительность для
традиционных SQL-бэкендов, если таблица содержит много столбцов.
Для получения дополнительной информации проверьте SQLAlchemy документация.(pd_table, conn, keys, data_iter):
Это можно использовать для реализации более производительного метода вставки на основе
особенностей конкретного диалекта бэкенда.# Alternative to_sql() *method* for DBs that support COPY FROM
import csv
from io import StringIO
def psql_insert_copy(table, conn, keys, data_iter):
"""
Execute SQL statement inserting data
Parameters
----------
table : pandas.io.sql.SQLTable
conn : sqlalchemy.engine.Engine or sqlalchemy.engine.Connection
keys : list of str
Column names
data_iter : Iterable that iterates the values to be inserted
"""
# gets a DBAPI connection that can provide a cursor
dbapi_conn = conn.connection
with dbapi_conn.cursor() as cur:
s_buf = StringIO()
writer = csv.writer(s_buf)
writer.writerows(data_iter)
s_buf.seek(0)
columns = ', '.join(['"{}"'.format(k) for k in keys])
if table.schema:
table_name = '{}.{}'.format(table.schema, table.name)
else:
table_name = table.name
sql = 'COPY {} ({}) FROM STDIN WITH CSV'.format(
table_name, columns)
cur.copy_expert(sql=sql, file=s_buf)
Чтение таблиц#
read_sql_table() будет читать таблицу базы данных по заданному имени таблицы и, опционально, подмножеству столбцов для чтения.read_sql_table(), вы должен иметь драйвер ADBC или установленную опциональную зависимость SQLAlchemy.In [650]: pd.read_sql_table("data", engine)
Out[650]:
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
userid
является целочисленным столбцом в таблице. Тогда, интуитивно, select userid ... будет возвращать Series с целочисленными значениями, в то время как select cast(userid as text) ... будет
возвращать Series со значениями типа object (str). Соответственно, если результат запроса пуст,
то все результирующие столбцы будут возвращены как object-valued (поскольку они являются
наиболее общими). Если вы предполагаете, что ваш запрос иногда будет генерировать пустой
результат, вы можете явно привести типы после этого, чтобы обеспечить целостность dtype.DataFrame индекс,
и укажите подмножество столбцов для чтения.In [651]: pd.read_sql_table("data", engine, index_col="id")
Out[651]:
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 [652]: pd.read_sql_table("data", engine, columns=["Col_1", "Col_2"])
Out[652]:
Col_1 Col_2
0 X 27.50
1 Y -12.50
2 Z 5.73
In [653]: pd.read_sql_table("data", engine, parse_dates=["Date"])
Out[653]:
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()Поддержка схемы#
schema
ключевое слово в read_sql_table() и to_sql()
функций. Однако обратите внимание, что это зависит от типа базы данных (sqlite не
имеет схем). Например:df.to_sql(name="table", con=engine, schema="other_schema")
pd.read_sql_table("table", engine, schema="other_schema")
Запросы#
read_sql_query() функция.
В этом случае необходимо использовать вариант SQL, подходящий для вашей базы данных.
При использовании SQLAlchemy можно также передавать конструкции языка выражений SQLAlchemy,
которые не зависят от базы данных.In [654]: pd.read_sql_query("SELECT * FROM data", engine)
Out[654]:
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 [655]: pd.read_sql_query("SELECT id, Col_1, Col_2 FROM data WHERE id = 42;", engine)
Out[655]:
id Col_1 Col_2
0 42 Y -12.5
read_sql_query() функция поддерживает chunksize аргумент.
Указание этого вернет итератор по частям результата запроса:In [656]: df = pd.DataFrame(np.random.randn(20, 3), columns=list("abc"))
In [657]: df.to_sql(name="data_chunks", con=engine, index=False)
Out[657]: 20
In [658]: for chunk in pd.read_sql_query("SELECT * FROM data_chunks", engine, chunksize=5):
.....: print(chunk)
.....:
a b c
0 -0.395347 -0.822726 -0.363777
1 1.676124 -0.908102 -1.391346
2 -1.094269 0.278380 1.205899
3 1.503443 0.932171 -0.709459
4 -0.645944 -1.351389 0.132023
a b c
0 0.210427 0.192202 0.661949
1 1.690629 -1.046044 0.618697
2 -0.013863 1.314289 1.951611
3 -1.485026 0.304662 1.194757
4 -0.446717 0.528496 -0.657575
a b c
0 -0.876654 0.336252 0.172668
1 0.337684 -0.411202 -0.828394
2 -0.244413 1.094948 0.087183
3 1.125934 -1.480095 1.205944
4 -0.451849 0.452214 -2.208192
a b c
0 -2.061019 0.044184 -0.017118
1 1.248959 -0.675595 -1.908296
2 -0.125934 1.491974 0.648726
3 0.391214 0.438609 1.634248
4 1.208707 -1.535740 1.620399
Примеры подключения движка#
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://
Расширенные запросы SQLAlchemy#
sqlalchemy.text() для указания параметров запроса независимо от бэкендаIn [659]: import sqlalchemy as sa
In [660]: pd.read_sql(
.....: sa.text("SELECT * FROM data where Col_1=:col1"), engine, params={"col1": "X"}
.....: )
.....:
Out[660]:
index id Date Col_1 Col_2 Col_3
0 0 26 2010-10-18 00:00:00.000000 X 27.5 1
In [661]: metadata = sa.MetaData()
In [662]: 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 [663]: pd.read_sql(sa.select(data_table).where(data_table.c.Col_3 is True), engine)
Out[663]:
Empty DataFrame
Columns: [index, Date, Col_1, Col_2, Col_3]
Index: []
read_sql() используя sqlalchemy.bindparam()In [664]: import datetime as dt
In [665]: expr = sa.select(data_table).where(data_table.c.Date > sa.bindparam("date"))
In [666]: pd.read_sql(expr, engine, params={"date": dt.datetime(2010, 10, 18)})
Out[666]:
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#
import sqlite3
con = sqlite3.connect(":memory:")
data.to_sql("data", con)
pd.read_sql_query("SELECT * FROM data", con)
Google BigQuery#
pandas-gbq пакет предоставляет функциональность для чтения/записи из Google BigQuery.pandas-gbq установлен, вы можете
использовать методы pandas pd.read_gbq и DataFrame.to_gbq, который вызовет
соответствующие функции из pandas-gbq.Формат Stata#
Запись в формат stata#
DataFrame.to_stata() запишет DataFrame в файл .dta. Версия формата этого файла всегда 115 (Stata 12).In [667]: df = pd.DataFrame(np.random.randn(10, 2), columns=list("AB"))
In [668]: df.to_stata("stata.dta")
int8, int16, int32, float32
и float64 может храниться в .dta файлы. Кроме того,
Stata резервирует определенные значения для представления отсутствующих данных. Экспорт
неотсутствующего значения, которое находится вне допустимого диапазона в Stata для
определенного типа данных, изменит тип переменной на следующий больший
размер. Например, int8 значения ограничены диапазоном от -127 до 100 в Stata, поэтому переменные со значениями выше 100 вызовут преобразование в int16. nan значения в типах данных с плавающей точкой хранятся как базовый тип отсутствующих данных (. в Stata).int64,
bool, uint8, uint16, uint32 путем приведения к
наименьшему поддерживаемому типу, который может представлять данные. Например, данные
с типом uint8 будет приведено к int8 если все значения меньше
100 (верхняя граница для не-пропущенных int8 данные в Stata), или, если значения
выходят за пределы этого диапазона, переменная приводится к int16.int64 to float64 может привести к потере точности
если int64 значения больше 2**53.StataWriter и
DataFrame.to_stata() поддерживают только строки фиксированной ширины длиной до 244 символов, ограничение, наложенное форматом файла dta версии 115. Попытка записать Stata файлы dta со строками
длиной более 244 символов вызывают ValueError.Чтение из формата Stata#
read_stata будет читать файл dta и возвращать
либо DataFrame или pandas.api.typing.StataReader который можно использовать для инкрементального чтения файла.In [669]: pd.read_stata("stata.dta")
Out[669]:
index A B
0 0 -0.165614 0.490482
1 1 -0.637829 0.067091
2 2 -0.242577 1.348038
3 3 0.647699 -0.644937
4 4 0.625771 0.918376
5 5 0.401781 -1.488919
6 6 -0.981845 -0.046882
7 7 -0.306796 0.877025
8 8 -0.336606 0.624747
9 9 -1.582600 0.806340
chunksize возвращает
pandas.api.typing.StataReader экземпляр, который можно использовать для
чтения chunksize строк из файла за раз. StataReader
объект может использоваться как итератор.In [670]: with pd.read_stata("stata.dta", chunksize=3) as reader:
.....: for df in reader:
.....: print(df.shape)
.....:
(3, 3)
(3, 3)
(3, 3)
(1, 3)
iterator=True и укажите
chunksize с каждым вызовом
read().In [671]: with pd.read_stata("stata.dta", iterator=True) as reader:
.....: chunk1 = reader.read(5)
.....: 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 сохраняются при импорте.StataReader объекты, созданные ли read_stata()
(при использовании iterator=True или chunksize) или созданный вручную, должен использоваться как контекстный
менеджер (например, the with оператор).
В то время как close() метод доступен, его использование не поддерживается.
Он не является частью публичного API и будет удален в будущем без предупреждения.Категориальные данные#
Categorical данные могут быть экспортированы в Stata файлы данных как данные с метками значений.
Экспортированные данные состоят из базовых кодов категорий как целочисленных значений данных
и категорий как меток значений. Stata не имеет явного эквивалента для Categorical и информацию о ли информация о том, что переменная упорядочена
теряется при экспорте.str вызывается на
категориях при экспорте данных. Экспорт Categorical переменные с
нестроковыми категориями вызывают предупреждение и могут привести к потере
информации, если str представления категорий не уникальны.Categorical
переменные с использованием аргумента ключевого слова convert_categoricals (True по умолчанию).
Аргумент ключевого слова order_categoricals (True по умолчанию) определяет
будет ли импортировано Categorical переменные упорядочены.Categorical переменные всегда используют целочисленные типы данных между -1 и n-1 где n это количество
категорий. Если исходные значения в Stata файл данных требуется, их можно импортировать, установив convert_categoricals=False, который импортирует исходные данные (но не метки переменных). Исходные значения можно сопоставить с импортированными категориальными данными, поскольку существует простое отображение между исходными Stata значения данных и коды категорий импортированных
категориальных переменных: пропущенным значениям присваивается код -1, и наименьшее исходное значение присваивается 0, второму наименьшему присваивается
1 и так далее, пока наибольшему исходному значению не будет присвоен код n-1.Categorical со строковыми категориями для значений, которые помечены, и числовыми категориями для значений без метки.форматы SAS#
read_sas() может читать (но не записывать) файлы форматов SAS XPORT (.xpt) и SAS7BDAT (.sas7bdat).DataFrame.chunksize или используйте iterator=True для получения объектов чтения (XportReader или SAS7BDATReader) для инкрементального
чтения файла. Объекты чтения также имеют атрибуты,
содержащие дополнительную информацию о файле и его переменных.df = pd.read_sas("sas_data.sas7bdat")
def do_something(chunk):
pass
with pd.read_sas("sas_xport.xpt", chunk=100000) as rdr:
for chunk in rdr:
do_something(chunk)
Форматы SPSS#
read_spss() может читать (но не записывать) файлы форматов SPSS
SAV (.sav) и ZSAV (.zsav).pd.Categorical,
и DataFrame возвращается со всеми столбцами.usecols параметр для получения подмножества столбцов. Укажите convert_categoricals=False
чтобы избежать преобразования категориальных столбцов в pd.Categorical.df = pd.read_spss("spss_data.sav")
usecols из файла SPSS и
избежать преобразования категориальных столбцов в pd.Categorical:df = pd.read_spss(
"spss_data.sav",
usecols=["foo", "bar"],
convert_categoricals=False,
)
Другие форматы файлов#
netCDF#
DataFrame для работы с многомерными наборами данных, с акцентом на формат файлов netCDF и лёгкое преобразование в pandas и обратно.Соображения производительности#
In [1]: sz = 1000000
In [2]: df = pd.DataFrame({'A': np.random.randn(sz), 'B': [1] * sz})
In [3]: df.info()
import numpy as np
import os
sz = 1000000
df = pd.DataFrame({"A": np.random.randn(sz), "B": [1] * sz})
sz = 1000000
np.random.seed(42)
df = pd.DataFrame({"A": np.random.randn(sz), "B": [1] * sz})
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", key="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", key="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", key="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", key="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)
def test_feather_write(df):
df.to_feather("test.feather")
def test_feather_read():
pd.read_feather("test.feather")
def test_pickle_write(df):
df.to_pickle("test.pkl")
def test_pickle_read():
pd.read_pickle("test.pkl")
def test_pickle_write_compress(df):
df.to_pickle("test.pkl.compress", compression="xz")
def test_pickle_read_compress():
pd.read_pickle("test.pkl.compress", compression="xz")
def test_parquet_write(df):
df.to_parquet("test.parquet")
def test_parquet_read():
pd.read_parquet("test.parquet")
test_feather_write, test_hdf_fixed_write и test_hdf_fixed_write_compress.In [4]: %timeit test_sql_write(df)
3.29 s ± 43.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [5]: %timeit test_hdf_fixed_write(df)
19.4 ms ± 560 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [6]: %timeit test_hdf_fixed_write_compress(df)
19.6 ms ± 308 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [7]: %timeit test_hdf_table_write(df)
449 ms ± 5.61 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [8]: %timeit test_hdf_table_write_compress(df)
448 ms ± 11.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [9]: %timeit test_csv_write(df)
3.66 s ± 26.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [10]: %timeit test_feather_write(df)
9.75 ms ± 117 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [11]: %timeit test_pickle_write(df)
30.1 ms ± 229 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [12]: %timeit test_pickle_write_compress(df)
4.29 s ± 15.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [13]: %timeit test_parquet_write(df)
67.6 ms ± 706 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
test_feather_read, test_pickle_read и
test_hdf_fixed_read.In [14]: %timeit test_sql_read()
1.77 s ± 17.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [15]: %timeit test_hdf_fixed_read()
19.4 ms ± 436 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [16]: %timeit test_hdf_fixed_read_compress()
19.5 ms ± 222 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [17]: %timeit test_hdf_table_read()
38.6 ms ± 857 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [18]: %timeit test_hdf_table_read_compress()
38.8 ms ± 1.49 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [19]: %timeit test_csv_read()
452 ms ± 9.04 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [20]: %timeit test_feather_read()
12.4 ms ± 99.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [21]: %timeit test_pickle_read()
18.4 ms ± 191 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [22]: %timeit test_pickle_read_compress()
915 ms ± 7.48 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [23]: %timeit test_parquet_read()
24.4 ms ± 146 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
test.pkl.compress, test.parquet и test.feather занимал наименьшее место на диске (в байтах).29519500 Oct 10 06:45 test.csv
16000248 Oct 10 06:45 test.feather
8281983 Oct 10 06:49 test.parquet
16000857 Oct 10 06:47 test.pkl
7552144 Oct 10 06:48 test.pkl.compress
34816000 Oct 10 06:42 test.sql
24009288 Oct 10 06:43 test_fixed.hdf
24009288 Oct 10 06:43 test_fixed_compress.hdf
24458940 Oct 10 06:44 test_table.hdf
24458940 Oct 10 06:44 test_table_compress.hdf
Комментарии и пустые строки#
Игнорирование комментариев в строках и пустых строк#
Если
commentесли параметр указан, то полностью закомментированные строки будут игнорироваться. По умолчанию полностью пустые строки также будут игнорироваться.Если
skip_blank_lines=False, затемread_csvне будет игнорировать пустые строки:Предупреждение
Наличие игнорируемых строк может создавать неоднозначности с номерами строк; параметр
headerиспользует номера строк (игнорируя закомментированные/пустые строки), в то время какskiprowsиспользует номера строк (включая закомментированные/пустые строки):Если оба
headerиskiprowsуказаны,headerбудет относиться к концуskiprows. Например:Комментарии#
Иногда комментарии или метаданные могут быть включены в файл:
По умолчанию парсер включает комментарии в вывод:
Мы можем подавить комментарии с помощью
commentключевое слово: