Сообщить об ошибке.

Функция read_csv() модуля pandas в Python

Читает CSV-файл с данными в DataFrame

Синтаксис pandas.read_csv():

import pandas

df = pandas.read_csv(filepath_or_buffer, *, sep=',', delimiter=None, header='infer', 
                     names=None, index_col=None, usecols=None, dtype=None, 
                     engine=None, converters=None, true_values=None, false_values=None, 
                     skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, 
                     na_values=None, keep_default_na=True, na_filter=True, verbose=False, 
                     skip_blank_lines=True, parse_dates=None, infer_datetime_format=False, 
                     keep_date_col=False, date_parser=no_default, date_format=None, 
                     dayfirst=False, cache_dates=True, iterator=False, chunksize=None, 
                     compression='infer', thousands=None, decimal='.', lineterminator=None, 
                     quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, 
                     encoding=None, encoding_errors='strict', dialect=None, on_bad_lines='error', 
                     delim_whitespace=False, low_memory=True, memory_map=False, 
                     float_precision=None, storage_options=None, dtype_backend='numpy_nullable')

Принимаемые аргументы pandas.read_csv():

  • filepath_or_buffer - любой допустимый путь в виде строки. Строка может быть URL. Допустимые схемы URL включают http(s), ftp(s), s3, gs и file. Для URL-адресов файлов ожидается host. Локальным файлом может быть: file://localhost/path/to/table.csv.

    Если необходимо передать объект pathlib, то этот аргумент принимает любой оs.PathLike.

    Аргумент также поддерживает объекты подобные открытому файлу, у которых есть метод file.read(), такие как дескриптор файла (например, открытый файл open()) или io.StringIO.

  • sep=‘,’ - Символ или шаблон регулярного выражения для использования в качестве разделителя. Если sep=None, то C-движок не может автоматически определить разделитель, но движок синтаксического анализа Python может. Это означает, что будет использоваться последний и автоматически обнаружит разделитель только из первой допустимой строки файла встроенным инструментом сниффера Python, csv.Sniffer. Кроме того, разделители длиной более 1 символа и отличные от '\s+' будут интерпретироваться как регулярные выражения, а также принудительно использовать механизм синтаксического анализа Python. Обратите внимание, что разделители регулярных выражений склонны игнорировать данные, заключенные в кавычки. Пример регулярного выражения: '\r\t'.

  • delimiter=None - псевдоним для аргумента sep.

  • header='infer' - номер(a) строки(строк), содержащие метки столбцов и отмечают начало данных (с нулевым индексом). Поведение по умолчанию заключается в выводе имен столбцов: если аргумент names не передается, то поведение идентично header=0, а имена столбцов выводятся из первой строки файла, если имена столбцов передаются явно в names, то поведение идентично header=None. Чтобы иметь возможность заменять существующие имена, нужно явно передать header=0. Аргумент header может представлять собой список целых чисел, которые определяют расположение строк для MultiIndex в столбцах, например [0, 1, 3]. Промежуточные строки, которые не указаны, будут пропущены (например, строка 2 в этом примере пропущена). Обратите внимание, что этот аргумент игнорирует пустые и закомментированные строки, если skip_blank_lines=True, поэтому header=0 обозначает первую строку данных, а не первую строку файла.

  • names=None - список меток столбцов (список имен столбцов). Если файл содержит строку заголовка, то следует явно передать header=0, чтобы переопределить имена столбцов. Дубликаты в этом списке не допускаются.

  • index_col=None - столбцы для использования в качестве меток строк DataFrame, заданные как имя или индекс столбца. Если передан список int/str, то будет создан MultiIndex.

    Примечание. index_col=False можно использовать, чтобы не использовать первый столбец в качестве индекса, например. когда есть некорректный файл с разделителями в конце каждой строки.

    Значение по умолчанию None определяет следующее поведение. Если количество полей в строке заголовка столбца равно количеству полей в теле файла данных, то используется индекс по умолчанию. Если он больше, то первые столбцы используются в качестве индекса, так что оставшееся количество полей в теле равно количеству полей в заголовке.

    Первая строка после заголовка используется для определения количества столбцов, которые войдут в индекс. Если последующие строки содержат меньше столбцов, чем первая строка, то они заполняются значением NaN.

    Этого можно избежать с помощью аргумента usecols. Он гарантирует, что столбцы принимаются как есть, а конечные данные игнорируются.

  • usecols=None - подмножество выбираемых столбцов, обозначаемых либо метками столбцов, либо индексами столбцов. Если это список, то все элементы должны быть либо позиционными (т. е. целочисленными индексами в столбцах с данными), либо строками, которые соответствуют именам столбцов, предоставленным либо пользователем в names, либо полученным из строк заголовка документа. Если указаны имена, то строки заголовка документа не принимаются во внимание. Например допустимым, что usecols, это список [0, 1, 2] или ['foo', 'bar', 'baz']. Порядок элементов игнорируется, поэтому usecols=[0, 1] совпадает с [1, 0]. Чтобы создать экземпляр DataFrame с сохранением порядка элементов ['foo', 'bar'], нужно использовать вызов pd.read_csv(data, usecols=['foo', 'bar'])[['foo', 'bar']] или pd.read_csv(data, usecols=['foo', 'bar'])[['bar', 'foo']] для порядка столбцов ['bar', 'foo'].

    Если значением аргумента является вызываемая функция, то она будет вычисляться по именам столбцов, возвращая имена, в которых вызываемая функция принимает значение True:

    >>> import pandas as pd
    >>> from io import StringIO
    >>> data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3"
    >>> pd.read_csv(StringIO(data))
    #   col1 col2  col3
    # 0    a    b     1
    # 1    a    b     2
    # 2    c    d     3
    
    >>> pd.read_csv(StringIO(data), usecols=lambda x: x.upper() in ["COL1", "COL3"])
    #   col1  col3
    # 0    a     1
    # 1    a     2
    # 2    c     3
    

    Использование этого аргумента приводит к гораздо более быстрому анализу и меньшему использованию памяти. Механизм Python сначала загружает данные, прежде чем решить, какие столбцы следует удалить.

  • dtype=None - тип данных, который применяется ко всему набору данных, либо в случае передачи словаря с типами данных - к отдельным столбцам. Например, {'a': np.float64, 'b': np.int32, 'c': 'Int64'}. Чтобы сохранить, а не интерпретировать dtype необходимо использовать типы str или object вместе с подходящими настройками na_values. Если указаны конвертеры converters, то они будут применены ВМЕСТО преобразования dtype.

  • engine=None - используемый парсер, принимает значения: 'c', 'pyarrow', 'python'. Движки C и Pyarrow работают быстрее, а движок Python в настоящее время более функционален. Многопоточность в настоящее время поддерживается только движком Pyarrow.

  • converters=None - словарь функции для преобразования значений в указанных столбцах (ключах). Ключами могут быть либо метки столбцов, либо индексы столбцов.

  • true_values=None - список строк, которые следует рассматривать как True в дополнение к варианту 'True' без учета регистра. Например, ['y', 'yes', 'ok']

  • false_values=None - список строк, которые следует рассматривать как False в дополнение к варианту 'False' без учета регистра. Например, ['n', 'no']

  • skipinitialspace=False - пропускать пробелы после разделителя или нет.

  • skiprows=None - список номеров строк для пропуска (с индексом 0) или количество строк для пропуска (int) в начале файла.

    Если это вызываемая функция, то она будет оцениваться по индексам строк, возвращая True, если строка должна быть пропущена, и False в противном случае.

    >>> data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3"
    >>> pd.read_csv(StringIO(data))
    #   col1 col2  col3
    # 0    a    b     1
    # 1    a    b     2
    # 2    c    d     3
    
    >>> pd.read_csv(StringIO(data), skiprows=lambda x: x % 2 != 0)
    col1 col2  col3
    # 0    a    b     2
    
  • skipfooter=0 - количество строк в нижней части файла, которые нужно пропустить (не поддерживается, если аргумент engine='c').

  • nrows=None - количество строк файла для чтения. Полезно для чтения фрагментов больших файлов.

  • na_values=None - список строк для распознавания значений NA/NaN. Если передан словарь, то в нем указываются конкретные значения NA для каждого столбца (ключи). По умолчанию следующие значения интерпретируются как NaN: ' ', '#N/A', '#N/A N/A”, '#NA', '-1.#IND', '-1.#QNAN', '-NaN', '-nan', '1.#IND', '1.#QNAN', '<NA>', 'N/A', 'NA', 'NULL', 'NaN', 'None', 'n/a', 'nan', 'null'.

  • keep_default_na=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, то для синтаксического анализа используются только значения NaN, указанные в na_values.
    • Если keep_default_na=False, а na_values не указаны, то никакие строки не будут проанализированы как NaN.

    Обратите внимание, что если na_filter передается как False, то аргументы keep_default_na и na_values будут проигнорированы.

  • na_filter=True - обнаружение маркеров отсутствующих значений (пустые строки и значения na_values). В данных, без каких-либо значений NA передача na_filter=False может повысить производительность чтения большого файла.

  • verbose=False - есть ли значений NA в нечисловых столбцах.

  • skip_blank_lines=True - значение True, пропускает пустые строки, а не интерпретирует их как значения NaN.

  • parse_dates=None - принимает bool, список, список списков или словарь списков.

    Поведение заключается в следующем:

    • если True - попробует проанализировать индекс. Примечание: автоматически устанавливается в True, если были переданы аргументы date_format или date_parser.
    • список целых чисел, например [1, 2, 3] - попробует разобрать столбцы 1, 2, 3 каждый как отдельный столбец даты.
    • список списков, например [[1, 3]] - объединит столбцы 1 и 3 и проанализировать как один столбец даты. (Устарело с версии pandas 2.2, объедините нужные столбцы с pandas.to_datetime() после синтаксического анализа).
    • словарь, например {'foo' : [1, 3]} - разбирает столбцы 1, 3 как дату и вызывает результат ‘foo’. Значения объединяются пробелом перед разбором.

    Если столбец или индекс не могут быть представлены в виде массива datetime, скажем, из-за неразличимого значения или сочетания часовых поясов, то столбец или индекс будут возвращены без изменений как объектный тип данных. Для нестандартного анализа даты/времени, после прочтения данных в DataFrame, необходимо использовать pandas.to_datetime().

    Примечание. Для дат в формате iso8601 существует быстрый путь.

  • infer_datetime_format=False - (Устарело с версии pandas 2.0, строгая версия этого аргумента теперь используется по умолчанию) если True и включен parse_dates, то pandas попытается определить формат строк даты и времени в столбцах, и если это возможно, переключится на более быстрый метод анализа. В некоторых случаях это может увеличить скорость парсинга в 5-10 раз.

  • keep_date_col=False - если True и parse_dates указывает объединение нескольких столбцов (устарело с версии pandas 2.2 и будет удалено в будущей версии), то сохраняет исходные столбцы.

  • date_parser=no_default - (Устарело с версии pandas 2.0, используйте pandas.to_datetime() после синтаксического анализа) функция, используемая для преобразования последовательности строковых столбцов в массив экземпляров даты/времени. По умолчанию для преобразования используется dateutil.parser.parser. Pandas попытается вызвать date_parser тремя разными способами, переходя к следующему в случае возникновения исключения:

    1. передать в качестве аргументов один или несколько массивов (как определено в parse_dates);
    2. объединить (по строкам) значения из столбцов, определенных parse_dates, в один массив и передать его;
    3. вызвать date_parser один раз для каждой строки, используя в качестве аргументов одну или несколько строк (соответствующих столбцам, определенным в parse_dates).
  • date_format=None - строка формата (например, '%d/%m/%Y'), используемая для анализа даты совместно с parse_dates. Информацию о вариантах строки формата смотрите в документации по strftime, но учтите, что '%f' будет анализировать вплоть до наносекунд. Также вы можно передать:

    • 'ISO8601', для анализа любого ISO8601. Cтрока времени (не обязательно в том же формате);
    • 'mixed' - определяет формат для каждого элемента индивидуально. Это рискованно, следует использовать его вместе с аргументом dayfirst.

  • dayfirst=False - используемый формат - международный (False - первый идет год) и европейский (True - первый идет день) формат.

  • cache_dates=True - если True, то используйте кэш уникальных преобразованных дат. Может значительно ускорить анализ повторяющихся строк даты, особенно со смещением часового пояса.

  • iterator=False - возвращает объект TextFileReader для итерации или получения фрагментов с помощью get_chunk().

  • chunksize=None - количество строк для чтения фрагмента из файла. Передача значения приведет к тому, что функция вернет объект TextFileReader для итерации.

  • compression='infer' - если имеет значение 'infer', а аргумент filepath_or_buffer является объектом оs.PathLike (например модуль pathlib), то самостоятельно обнаружит сжатие из следующих расширений: '.gz', '.bz2', '.zip', '.xz', '.zst', '.tar', '.tar.gz', '.tar.xz' или '.tar.bz2' (в противном случае сжатие отсутствует).

    При передачи значения ‘zip’ или ‘tar’ ZIP-файл должен содержать только один файл данных для чтения. Значение None говорит об отсутствии сжатия.

  • thousands=None - один символ, действующий как разделитель тысяч в числовых значениях .

  • decimal='.' - один символ, который нужно распознать как десятичную точку.

  • lineterminator=None - символ, используемый для обозначения разрыва строки. Действует только с аргументом engine='c'.

  • quotechar='"' - один символ, используемый для обозначения начала и конца элемента, заключенного в кавычки. Элементы, заключенные в кавычки, могут содержать разделитель, который определен аргументом delimiter, и он будет проигнорирован.

  • quoting=0 - управляет поведением при цитировании полей в формате csv.QUOTE_*. По умолчанию используется формат csv.QUOTE_MINIMAL (т.е. 0), это подразумевает, что в кавычки заключаются только поля, содержащие специальные символы (например, символы, определенные в аргументах quotechar, delimiter или lineterminator. Принимает значения 0 или csv.QUOTE_MINIMAL, 1 или csv.QUOTE_ALL, 2 или csv.QUOTE_NONNUMERIC, 3 или csv.QUOTE_NONE.

  • doublequote=True - если указан аргумент quotechar, а значение quoting не равно csv.QUOTE_NONE, указывает, следует ли интерпретировать два последовательных элемента quotechar ВНУТРИ поля как один элемент quotechar.

  • escapechar=None - символ, используемый для экранирования других символов.

  • comment=None - символ, указывающий, что остаток строки не следует анализировать. Если он находится в начале строки, то строка будет полностью проигнорирована. Этот аргумент должен состоять из одного символа. Как и пустые строки (при условии, что skip_blank_lines=True), полностью закомментированные строки игнорируются header, но не skiprows. Например, если comment='#', то синтаксический анализ строки #empty\na,b,c\n1,2,3 с header=0 приведет к тому, что 'a,b,c' будет рассматриваться как заголовок.

  • encoding=None - используемая кодировка при чтении/записи (например, 'utf-8')

  • encoding_errors='strict' - как обрабатывать ошибки кодирования. Список возможных значений.

  • dialect=None - если указан, то переопределяет значения для следующих аргументов: delimiter, doublequote, escapechar, skipinitialspace, quotechar и quoting. Для получения более подробной информации, смотрите csv.Dialect .

  • on_bad_lines='error' - указывает, что делать при обнаружении некорректной строки (строки со слишком большим количеством полей).

    Допустимые значения:

    • 'error', вызывает исключение при обнаружении некорректной строки.
    • 'warn', выводит предупреждение при обнаружении неправильной строки и пропускает эту строку.
    • 'skip', молча пропускает неправильные строки.
  • delim_whitespace=False - (Устарело с версии pandas 2.2, используйте sep='\s+') указывает, будет ли в качестве разделителя sep использоваться пробел (например, '' или \t) . Если эта опция установлена ​​на True, то ничего не должно быть передано для аргумента sep.

  • low_memory=True - внутренняя обработка файла по частям, что приводит к меньшему использованию памяти при синтаксическом анализе, но, возможно, к выводу смешанного типа. Чтобы гарантировать отсутствие смешанных типов, нужно установить значение False, либо указать тип в аргументе dtype. Обратите внимание, что независимо от того, что весь файл считывается в один фрейм данных, использует аргументы chunksize или iterator, для возврата данных порциями. (Допустимо только с аргументом engine='c').

  • memory_map=False - если для аргумента filepath_or_buffer указан путь к файлу, то сопоставляет файловый объект непосредственно с памятью и получает доступ к данным непосредственно оттуда. Использование этого аргумента может повысить производительность.

  • float_precision=None - указывает, какой механизм C должен использовать для преобразования значений с float. Возможные варианты: None или 'high' для обычного конвертера, 'legacy' для исходного конвертера pandas с более низкой точностью и 'round_trip' для двустороннего конвертера.

  • storage_options=None - дополнительные параметры, которые имеют смысл для конкретного подключения к хранилищу. Например, хост, порт, имя пользователя, пароль и т. д. Для URL-адресов HTTP(S) пары ключ-значение пересылаются в urllib.request.Request в качестве заголовков.

  • dtype_backend='numpy_nullable' - (экспериментальный) внутренний тип данных, применяемый к результирующему DataFrame.

    Поведение выглядит следующим образом:

    • 'numpy_nullable': возвращает фрейм с поддержкой null-dtype (по умолчанию).
    • 'pyarrow': возвращает фрейм данных ArrowDtype с нулевым значением, поддерживаемый pyarrow.

Возвращаемое значение pandas.read_csv():

  • DataFrame или TextFileReader в виде двумерной структуры данных с помеченными осями.

Описание pandas.read_csv()

Функция read_csv() модуля pandas читает файл с данными, разделенных запятыми (CSV), в DataFrame. Поддерживает опциональную итерацию или разбиение файла на куски.

Чтение файлов на удаленных источниках

Для чтения удаленных файлов можно передавать URL-адрес во многие функции ввода-вывода pandas. В следующем примере показано чтение CSV-файла по HTTPS протоколу:

pd.read_csv("https://download.bls.gov/pub/time.series/cu/cu.item", sep="\t")

Пользовательский заголовок можно отправить вместе с запросами 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
)

Автоматическое обнаружение разделителя ячеек в "сырых данных"

Функция read_csv() способен выводить файлы с разделителями (не обязательно разделенными запятыми), т.к. pandas использует класс csv.Sniffer модуля csv. Для этого необходимо указать sep=None.

>>> df = pd.DataFrame(np.random.randn(10, 4))
>>> df.to_csv("tmp2.csv", sep=":", index=False)
>>> pd.read_csv("tmp2.csv", sep=None, engine="python")
#           0         1         2         3
# 0 -3.090337 -1.071775  0.094097 -0.193111
# 1  1.656500 -1.887067 -0.473435  0.164553
# 2  0.141371  0.343371 -0.382775 -1.184313
# 3 -0.856343  0.064099 -0.437490 -2.243752
# 4 -0.766447 -0.323522  1.168509  0.815811
# 5  0.442197  0.162073 -0.641610 -0.498648
# 6  0.506010 -1.483942 -0.659766  0.019671
# 7 -0.130446 -0.664035 -0.731641 -0.917420
# 8 -1.273134  1.280339 -0.864498  0.165605
# 9  0.396454  0.942713 -2.208943  1.915031

Указание типов данных столбца (аргумент dtype)

При чтении данных можно сразу указать тип данных для всего DataFrame или отдельных столбцов:

>>> import numpy as np
>>> import pandas as pd
>>> from io import StringIO
>>> data = "a,b,c,d\n1,2,3,4\n5,6,7,8\n9,10,11"
>>> df = pd.read_csv(StringIO(data), dtype=object)
>>> df
#    a   b   c    d
# 0  1   2   3    4
# 1  5   6   7    8
# 2  9  10  11  NaN

>>> df["a"][0]
# '1'

# указываем желаемые типы для столбцов
>>> df = pd.read_csv(StringIO(data), dtype={"b": object, "c": np.float64, "d": "Int64"})
>>> df.dtypes
# a      int64
# b     object
# c    float64
# d      Int64
# dtype: object

Например, можно использовать аргумент converters функции read_csv():

>>> data = "col_1\n1\n2\n'A'\n4.22"
>>> df = pd.read_csv(StringIO(data), converters={"col_1": str})
>>> df
#   col_1
# 0     1
# 1     2
# 2   'A'
# 3  4.22

>>> df["col_1"].apply(type).value_counts()
# col_1
# <class 'str'>    4
# Name: count, dtype: int64

Или можно использовать функцию pandas.to_numeric() для принудительного преобразования типов после чтения данных:

>>> df2 = pd.read_csv(StringIO(data))
>>> df2["col_1"] = pd.to_numeric(df2["col_1"], errors="coerce")
>>> df2
#    col_1
# 0   1.00
# 1   2.00
# 2    NaN
# 3   4.22

>>> df2["col_1"].apply(type).value_counts()
# col_1
# <class 'float'>    4
# Name: count, dtype: int64

В конечном счете, чтением столбцов, содержащих смешанные типы данных, зависит от конкретных потребностей. В приведенном выше случае, если необходимо выявить аномалии данных с помощью NaN, то pandas.to_numeric(), вероятно, будет лучшим вариантом. Но если нужно, чтобы все данные были преобразованы независимо от их типа, то стоит использовать аргумент converters функции read_csv().

Примечание. В некоторых случаях чтение аномальных данных со столбцами, содержащими смешанные типы данных, приведет к несогласованному набору данных. Если возложить определение типов столбцов на pandas, то механизм синтаксического анализа будет выводить типы данных для разных фрагментов данных, а не для всего набора данных сразу. Следовательно, можно получить столбцы со смешанными типами данных. Например:

>>> col_1 = list(range(500000)) + ["a", "b"] + list(range(500000))
>>> df = pd.DataFrame({"col_1": col_1})
>>> df.to_csv("foo.csv")
>>> mixed_df = pd.read_csv("foo.csv")
>>> mixed_df["col_1"].apply(type).value_counts()
# col_1
# <class 'int'>    737858
# <class 'str'>    262144
# Name: count, dtype: int64

>>> mixed_df["col_1"].dtype
# dtype('O')

в результате mixed_df будет содержаnm тип int для определенных фрагментов столбца и str для других из-за смешанных типов dtype. Важно отметить, что весь столбец будет отмечен dtype: object, который используется для столбцов со смешанными типами данных.

Установка аргумента dtype_backend='numpy_nullable' приведет к созданию dtypes, допускающих значение NULL, для каждого столбца.

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,
"""
>>> df = pd.read_csv(StringIO(data), dtype_backend="numpy_nullable", parse_dates=["i"])
>>> df
#    a    b      c  d     e     f     g     h          i     j
# 0  1  2.5   True  a  <NA>  <NA>  <NA>  <NA> 2019-12-31  <NA>
# 1  3  4.5  False  b     6   7.5  True     a 2019-12-31  <NA>

>>> df.dtypes
# 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

Указание категориального типа dtype

Столбцы Categorical можно анализировать напрямую, указав аргумент dtype='category' или dtype=CategoricalDtype(categories,ordered).

>>> data = "col1,col2,col3\na,b,1\na,b,2\nc,d,3"
>>> pd.read_csv(StringIO(data))
#   col1 col2  col3
# 0    a    b     1
# 1    a    b     2
# 2    c    d     3

>>> pd.read_csv(StringIO(data)).dtypes
# col1    object
# col2    object
# col3     int64
# dtype: object

>>> pd.read_csv(StringIO(data), dtype="category").dtypes
# col1    category
# col2    category
# col3    category
# dtype: object

Используя словарь, можно анализировать отдельные столбцы как категориальные Categorical:

>>> pd.read_csv(StringIO(data), dtype={"col1": "category"}).dtypes
# col1    category
# col2      object
# col3       int64
# dtype: object

Указание dtype='category' приведет к созданию неупорядоченного значения Categorical, категории которого представляют собой уникальные значения, наблюдаемые в данных. Для бОльшего контроля над категориями и порядком нужно заранее создать CategoricalDtype и передать его для dtype этого столбца.

>>> from pandas.api.types import CategoricalDtype
>>> dtype = CategoricalDtype(["d", "c", "b", "a"], ordered=True)
>>> pd.read_csv(StringIO(data), dtype={"col1": dtype}).dtypes
# col1    category
# col2      object
# col3       int64
# dtype: object

При использовании dtype=CategoricalDtype, "неожиданные" значения за пределами dtype.categories рассматриваются как отсутствующие значения.

# значение 'c' - не указано
>>> dtype = CategoricalDtype(["a", "b", "d"]) 
>>> pd.read_csv(StringIO(data), dtype={"col1": dtype}).col1
# 0      a
# 1      a
# 2    NaN
# Name: col1, dtype: category
# Categories (3, object): ['a', 'b', 'd']

Примечание. При использовании dtype='category' результирующие категории всегда будут анализироваться как строки (dtype: object). Если категории являются числовыми, то их можно преобразовать с помощью функции pandas.to_numeric() или, при необходимости, другого преобразователя, например pandas.to_datetime().

Если dtype=CategoricalDtype(...) с однородными категориями (все числа, все даты/время и т.д.), то преобразование выполняется автоматически.

>>> df = pd.read_csv(StringIO(data), dtype="category")
>>> df.dtypes
# col1    category
# col2    category
# col3    category
# dtype: object

>>> df["col3"]
# 0    1
# 1    2
# 2    3
# Name: col3, dtype: category
# Categories (3, object): ['1', '2', '3']

>>> new_categories = pd.to_numeric(df["col3"].cat.categories)
>>> df["col3"] = df["col3"].cat.rename_categories(new_categories)
>>> df["col3"]
# 0    1
# 1    2
# 2    3
# Name: col3, dtype: category
# Categories (3, int64): [1, 2, 3]

Обработка имен столбцов (аргументы names и header)

Файл может иметь или не иметь строку заголовка. Библиотека pandas предполагает, что первая строка должна использоваться в качестве имен столбцов:

>>> data = "a,b,c\n1,2,3\n4,5,6\n7,8,9"
>>> print(data)
# a,b,c
# 1,2,3
# 4,5,6
# 7,8,9

>>> pd.read_csv(StringIO(data))
#    a  b  c
# 0  1  2  3
# 1  4  5  6
# 2  7  8  9

Указывая аргумент names вместе с header, можно указать другие имена, а также указать, следует ли "выбрасывать" строку заголовка (если таковая имеется):

>>> pd.read_csv(StringIO(data), names=["foo", "bar", "baz"], header=0)
#    foo  bar  baz
# 0    1    2    3
# 1    4    5    6
# 2    7    8    9

>>> pd.read_csv(StringIO(data), names=["foo", "bar", "baz"], header=None)
#   foo bar baz
# 0   a   b   c
# 1   1   2   3
# 2   4   5   6
# 3   7   8   9

Если заголовок находится НЕ в первой строке, то нужно передать номер этой строки в аргумент header. Это пропустит предыдущие строки:

>>> data = "skip this skip it\na,b,c\n1,2,3\n4,5,6\n7,8,9"
>>> print(data)
# skip this skip it
# a,b,c
# 1,2,3
# 4,5,6
# 7,8,9

>>> pd.read_csv(StringIO(data), header=1)
#    a  b  c
# 0  1  2  3
# 1  4  5  6
# 2  7  8  9

Примечание. Поведение по умолчанию заключается в выводе имен столбцов: если имена столбцов не передаются, то поведение идентично header=0, а имена столбцов выводятся из первой непустой строки файла. Если имена столбцов передаются явно, то поведение идентично header=None.

Синтаксический анализ повторяющихся имен

Если заголовок столбцов в файле содержат повторяющиеся имена, то pandas по умолчанию различит их, и предотвратит перезапись данных:

>>> data = "a,b,a\n0,1,2\n3,4,5"
>>> print(data)
# a,b,a
# 0,1,2
# 3,4,5

>>> pd.read_csv(StringIO(data))
#    a  b  a.1
# 0  0  1    2
# 1  3  4    5

Повторяющиеся столбцы ‘X’, ..., ‘X’ становятся ‘X’, ‘X.1’, ..., ‘X.N’.

Фильтрация столбцов при чтении данных (аргумент usecols)

Аргумент usecols позволяет выбрать любое подмножество столбцов в файле, используя имена столбцов или номера позиций, либо вызываемый объект:

>>> data = "a,b,c,d\n1,2,3,foo\n4,5,6,bar\n7,8,9,baz"
>>> print(data)
# a,b,c,d
# 1,2,3,foo
# 4,5,6,bar
# 7,8,9,baz

>>> pd.read_csv(StringIO(data))
#    a  b  c    d
# 0  1  2  3  foo
# 1  4  5  6  bar
# 2  7  8  9  baz

>>> pd.read_csv(StringIO(data), usecols=["b", "d"])
#    b    d
# 0  2  foo
# 1  5  bar
# 2  8  baz

>>> pd.read_csv(StringIO(data), usecols=[0, 2, 3])
#    a  c    d
# 0  1  3  foo
# 1  4  6  bar
# 2  7  9  baz

>>> pd.read_csv(StringIO(data), usecols=lambda x: x.upper() in ["A", "C"])
#    a  c
# 0  1  3
# 1  4  6
# 2  7  9

Аргумент usecols также можно использовать, чтобы указать, какие столбцы нужно исключить:

>>> pd.read_csv(StringIO(data), usecols=lambda x: x not in ["a", "c"])
#    b    d
# 0  2  foo
# 1  5  bar
# 2  8  baz

Комментарии (аргумент comment)

Если указан аргумент comment, то полностью закомментированные строки будут игнорироваться. По умолчанию полностью пустые строки также будут игнорироваться.

>>> data = "\na,b,c\n  \n# commented line\n1,2,3\n\n4,5,6"
>>> print(data)
# 
# a,b,c
#   
# # commented line
# 1,2,3
# 
# 4,5,6

>>> pd.read_csv(StringIO(data), comment="#")
#    a  b  c
# 0  1  2  3
# 1  4  5  6

Иногда комментарии или метаданные могут быть помещены в строку с данными:

data = (
    "ID,level,category\n"
    "Patient1,123000,x # really unpleasant\n"
    "Patient2,23000,y # wouldn't take his medicine\n"
    "Patient3,1234018,z # awesome"
)
with open("tmp.csv", "w") as fh:
    fh.write(data)

По умолчанию анализатор включает комментарии в выходные данные:

>>> df = pd.read_csv("tmp.csv")
>>> df
#          ID    level                        category
# 0  Patient1   123000           x # really unpleasant
# 1  Patient2    23000  y # wouldn't take his medicine
# 2  Patient3  1234018                     z # awesome

Можно подавить комментарии, используя аргумент comment:

>>> df = pd.read_csv("tmp.csv", comment="#")
>>> df
#          ID    level category
# 0  Patient1   123000       x 
# 1  Patient2    23000       y 
# 2  Patient3  1234018       z

Пустые строки (аргументы skiprows и skip_blank_lines)

Если аргумент skip_blank_lines=False, то read_csv() не будет игнорировать пустые строки:

>>> data = "a,b,c\n\n1,2,3\n\n\n4,5,6"
>>> print(data)
# a,b,c
# 
# 1,2,3
# 
# 
# 4,5,6

>>> pd.read_csv(StringIO(data), skip_blank_lines=False)
#      a    b    c
# 0  NaN  NaN  NaN
# 1  1.0  2.0  3.0
# 2  NaN  NaN  NaN
# 3  NaN  NaN  NaN
# 4  4.0  5.0  6.0

Предупреждение. Наличие игнорируемых строк может создавать неоднозначности, связанные с номерами строк. Аргумент header использует номера строк (игнорируя закомментированные/пустые строки), в то время как skiprows использует номера строк (включая закомментированные/пустые строки):

>>> data = "#comment\na,b,c\nA,B,C\n1,2,3"
>>> print(data)
# #comment
# a,b,c
# A,B,C
# 1,2,3

>>> pd.read_csv(StringIO(data), comment="#", header=1)
#    A  B  C
# 0  1  2  3

>>> data = "A,B,C\n#comment\na,b,c\n1,2,3"
>>> print(data)
# A,B,C
# #comment
# a,b,c
# 1,2,3

>>> pd.read_csv(StringIO(data), comment="#", skiprows=2)
#    a  b  c
# 0  1  2  3

Если указаны как header, так и skiprows, то header будет располагаться относительно конца skiprows. Например:

data = (
    "# empty\n"
    "# second empty line\n"
    "# third emptyline\n"
    "X,Y,Z\n"
    "1,2,3\n"
    "A,B,C\n"
    "1,2.,4.\n"
    "5.,NaN,10.0\n"
)

>>> pd.read_csv(StringIO(data), comment="#", skiprows=4, header=1)
#      A    B     C
# 0  1.0  2.0   4.0
# 1  5.0  NaN  10.0

Столбцы индексов и разделители ячеек в конце строк (аргумент index_col)

Если в файле на один столбец данных больше, чем количество имен столбцов, первый столбец будет использоваться в качестве индексных меток строк DataFrame:

>>> data = "a,b,c\n4,apple,bat,5.7\n8,orange,cow,10"
>>> pd.read_csv(StringIO(data))
#         a    b     c
# 4   apple  bat   5.7
# 8  orange  cow  10.0

Можно добиться такого поведения, используя аргумент index_col .

>>> data = "index,a,b,c\n4,apple,bat,5.7\n8,orange,cow,10"
>>> pd.read_csv(StringIO(data), index_col=0)
#             a    b     c
# index                   
# 4       apple  bat   5.7
# 8      orange  cow  10.0

Есть несколько исключительных случаев, когда файл был подготовлен с разделителями в конце каждой строки данных, что сбивает с толку анализатор. Чтобы явно отключить столбец индекса и отбросить последний столбец, нужно установить index_col=False:

>>> data = "a,b,c\n4,apple,bat,\n8,orange,cow,"
# обратите внимание на запятую 
# в конце каждой строки с данными
>>> print(data)
# a,b,c
# 4,apple,bat,
# 8,orange,cow,

>>> pd.read_csv(StringIO(data))
#         a    b   c
# 4   apple  bat NaN
# 8  orange  cow NaN

>>> pd.read_csv(StringIO(data), index_col=False)
#    a       b    c
# 0  4   apple  bat
# 1  8  orange  cow

Если подмножество данных анализируется с использованием аргумента usecols, то аргумент index_col основан на этом подмножестве, а не на исходных данных.

>>> pd.read_csv(StringIO(data), usecols=["b", "c"])
#      b   c
# 4  bat NaN
# 8  cow NaN

>>> pd.read_csv(StringIO(data), usecols=["b", "c"], index_col=0)
#      b   c
# 4  bat NaN
# 8  cow NaN

Так же смотрите далее подраздел "Чтение данных с MultiIndex"

Обработка даты/времени (аргументы parse_dates)

Для упрощения работы с данными datetime функция read_csv() использует аргументы parse_dates и date_format, позволяющие пользователям указывать различные столбцы и форматы даты/времени для преобразования входных текстовых данных в объекты datetime.

Самый простой случай - просто передать parse_dates=True:

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")
>>> df = pd.read_csv("foo.csv", index_col=0, parse_dates=True)
>>> df
#             A  B  C
# date               
# 2009-01-01  a  1  2
# 2009-01-02  b  3  4
# 2009-01-03  c  4  5

>>> df.index
# DatetimeIndex(['2009-01-01', '2009-01-02', '2009-01-03'], 
# dtype='datetime64[ns]', name='date', freq=None)

Бывает так, что сырые данные хранят различные компоненты даты/времени в различных столбцах. Аргумент parse_dates можно использовать для указания комбинации столбцов для анализа дат и/или времени.

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

# пишем данные во временный файл
with open("tmp.csv", "w") as fh:
    fh.write(data)

# читаем с указанием позиций столбцов, содержащих 
# дату и время как вложенные списки (устарело с версии 2.2)
>>> df = pd.read_csv("tmp.csv", header=None, parse_dates=[[1, 2], [1, 3]])
>>> df
#                   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

Предупреждение на будущее: поддержка вложенных последовательностей для аргумента 'parse_dates' будет считаться устаревшей с версии pandas 2.2. Теперь для объединения нужных столбцов необходимо использовать функцию pandas.to_datetime() после синтаксического анализа.

По умолчанию синтаксический анализатор удаляет столбцы даты компонента, но можно сохранить их с помощью ключевого аргумента keep_date_col (устарело с pandas 2.2 и будет удалено в будущей версии):

df = pd.read_csv(
    "tmp.csv", header=None, parse_dates=[[1, 2], [1, 3]], keep_date_col=True
)
>>> df
#                   1_2                 1_3     0         1          2          3     4
# 0 1999-01-27 19:00:00 1999-01-27 18:56:00  KORD  19990127   19:00:00   18:56:00  0.81
# 1 1999-01-27 20:00:00 1999-01-27 19:56:00  KORD  19990127   20:00:00   19:56:00  0.01
# 2 1999-01-27 21:00:00 1999-01-27 20:56:00  KORD  19990127   21:00:00   20:56:00 -0.59
# 3 1999-01-27 21:00:00 1999-01-27 21:18:00  KORD  19990127   21:00:00   21:18:00 -0.99
# 4 1999-01-27 22:00:00 1999-01-27 21:56:00  KORD  19990127   22:00:00   21:56:00 -0.59
# 5 1999-01-27 23:00:00 1999-01-27 22:56:00  KORD  19990127   23:00:00   22:56:00 -0.59

Обратите внимание: если нужно объединить несколько столбцов в один столбец даты, необходимо использовать вложенный список. Другими словами, parse_dates=[1, 2] указывает, что второй и третий столбцы должны анализироваться как отдельные столбцы даты, а parse_dates=[[1, 2]] означает, что два столбца должны быть проанализированы как один столбец.

Также можно использовать словарь для настройки имен столбцов с датами:

>>> date_spec = {"nominal": [1, 2], "actual": [1, 3]}
>>> df = pd.read_csv("tmp.csv", header=None, parse_dates=date_spec)
>>> df
#               nominal              actual     0     4
# 0 1999-01-27 19:00:00 1999-01-27 18:56:00  KORD  0.81
# 1 1999-01-27 20:00:00 1999-01-27 19:56:00  KORD  0.01
# 2 1999-01-27 21:00:00 1999-01-27 20:56:00  KORD -0.59
# 3 1999-01-27 21:00:00 1999-01-27 21:18:00  KORD -0.99
# 4 1999-01-27 22:00:00 1999-01-27 21:56:00  KORD -0.59
# 5 1999-01-27 23:00:00 1999-01-27 22:56:00  KORD -0.59

Примечание. Если столбец или индекс содержит неразбираемую дату, то весь столбец или индекс будет возвращен без изменений. Для нестандартного анализа даты и времени необходимо использовать функцию pandas.to_datetime() после pandas.read_csv().

Примечание. Функция pandas.read_csv() имеет сверхбыстрый метод анализа строк даты и времени в формате iso8601, например '2000-01-01T00:01:02+00:00' и подобных вариациях. Если есть возможность организовать хранение данных в этом формате, то время загрузки будет значительно быстрее, примерно в 20 раз!!!

Функции анализа даты (аргумент date_format)

Наконец, анализатор позволяет указать пользовательский формат date_format. С точки зрения производительности, следует попробовать эти методы анализа дат по порядку:

  • Если pandas формат неизвестен, то необходимо использовать аргумент date_format, например: date_format='%d/%m/%Y' или date_format={имя_столбца: '%d/%m/%Y'}.
  • Если данные содержат разные форматы для разных столбцов или нужно передать какие-либо дополнительные параметры (например, utc), то следует сначала прочитать данные как dtype: object, а затем, для преобразования использовать функцию pandas.to_datetime().

Определение формата даты и времени (аргумент dayfirst)

Несколько примеров строк с датой и времени, которые pandas автоматически распознает при чтении "сырых данных" (все они представляют 30 декабря 2023 г., 00:00:00):

  • '20231230';
  • '2023/12/30';
  • '20231230 00:00:00';
  • '30.12.2023 00:00:00';
  • '30/Dec/2023 00:00:00';
  • '30/December/2023 00:00:00';

Обратите внимание, что вывод формата чувствителен к значению аргумента dayfirst. Если dayfirst=True, то предполагается, что '12.01.2023' будет 1 декабря. Если dayfirst=False (по умолчанию), то предполагается, что '12.01.2023' будет 12 января. pandas попытается угадать формат по первому элементу, отличному от NaN, а затем проанализирует остальную часть столбца с этим форматом. Если pandas не угадает формат, то будет выдано предупреждение, и каждая строка будет анализироваться индивидуально с помощью dateutil.parser.parse. В общем, самый безопасный способ анализа - это явно указать формат даты/времени в аргументе format.

df = pd.read_csv(
    "foo.csv",
    index_col=0,
    parse_dates=True,
)

>>> df
#             A  B  C
# date               
# 2009-01-01  a  1  2
# 2009-01-02  b  3  4
# 2009-01-03  c  4  5

Если в одном столбце данные содержат смешанные форматы даты/времени, то можно попробовать передать format='mixed'

>>> from io import StringIO
>>> data = StringIO("date\n12 Jan 2000\n2000-01-13\n")
>>> df = pd.read_csv(data)
>>> df['date'] = pd.to_datetime(df['date'], format='mixed')
>>> df
#         date
# 0 2000-01-12
# 1 2000-01-13

или, если все форматы даты/времени соответствуют ISO8601, но не одинаково отформатированы:

>>> data = StringIO("date\n2020-01-01\n2020-01-01 03:00\n")
>>> df = pd.read_csv(data)
>>> df['date'] = pd.to_datetime(df['date'], format='ISO8601')
>>> df
#                  date
# 0 2020-01-01 00:00:00
# 1 2020-01-01 03:00:00

Метод преобразования данных float

Чтобы использовать определенный преобразователь значений float во время анализа можно указать аргумент float_precision. Возможные варианты: None, high и round_trip (который гарантированно возвращает значения туда и обратно после записи в файл). Например:

>>> val = "0.3066101993807095471566981359501369297504425048828125"
>>> data = "a,b,c\n1,2,{0}".format(val)
>>> df = pd.read_csv(StringIO(data), engine="c", float_precision=None)
>>> abs(df["c"][0] - float(val))
# 5.551115123125783e-17

>>> df = pd.read_csv(StringIO(data), engine="c", float_precision='high')
>>> abs(df["c"][0] - float(val))
# 5.551115123125783e-17

>>> df = pd.read_csv(StringIO(data), engine="c", float_precision='round_trip')
>>> abs(df["c"][0] - float(val))
# 0.0

Разделитель тысяч в больших числах (аргумент thousands)

Для больших чисел, записанных через разделитель тысяч, можно установить ключевой аргумент thousands в строку длиной 1, чтобы целые числа обрабатывались правильно:

По умолчанию числа с разделителем тысяч будут обрабатываться как строки:

data = (
    "ID|level|category\n"
    "Patient1|123,000|x\n"
    "Patient2|23,000|y\n"
    "Patient3|1,234,018|z"
)
with open("tmp.csv", "w") as fh:
    fh.write(data)

>>> df = pd.read_csv("tmp.csv", sep="|")
>>> df
#          ID      level category
# 0  Patient1    123,000        x
# 1  Patient2     23,000        y
# 2  Patient3  1,234,018        z

>>> df.level.dtype
# dtype('O')

Аргумент thousands позволяет корректно анализировать целые числа:

>>> df = pd.read_csv("tmp.csv", sep="|", thousands=",")
>>> df
#          ID    level category
# 0  Patient1   123000        x
# 1  Patient2    23000        y
# 2  Patient3  1234018        z

>>> df.level.dtype
# dtype('int64')

Анализ значений NA при чтении данных (аргумент na_values)

Чтобы контролировать, какие значения анализируются как пропущенные, необходимо указать строку в поле na_values. Если указать список строк, то все значения в нем считаются пропущенными значениями. Если указать число (float, например 5.0, или целое число, например 5), то соответствующие эквивалентные значения также будут подразумевать пропущенное значение (в этом случае эффективно [5.0, 5] распознаются как NaN).

Чтобы полностью переопределить значения по умолчанию, которые распознаются как отсутствующие, необходимо указать аргументу keep_default_na=False.

Несколько абстрактных примеров:

# числа 5 и 5.0 будут распознаны как `NaN`, 
# в дополнение к значениям по умолчанию.
pd.read_csv("path_to_file.csv", na_values=[5])

# ТОЛЬКО пустое поле будет распознано как `NaN`.
pd.read_csv("path_to_file.csv", keep_default_na=False, na_values=[""])

# ТОЛЬКО строки `NA`, и `0` будут распознаны как `NaN`.
pd.read_csv("path_to_file.csv", keep_default_na=False, na_values=["NA", "0"])

# строке 'Nope' в дополнение к значениям 
# по умолчанию распознаются как `NaN`.
pd.read_csv("path_to_file.csv", na_values=["Nope"])

Анализ логических значения при чтении данных (аргументы true_values и false_values)

Все обычные значения True, False, TRUE и FALSE распознаются как логические. Иногда может потребоваться распознать другие значения как логические. Для этого используйте параметры true_values и false_values следующим образом:

>>> data = "a,b,c\n1,Yes,2\n3,No,4"
>>> print(data)
# a,b,c
# 1,Yes,2
# 3,No,4

>>> pd.read_csv(StringIO(data))
#    a    b  c
# 0  1  Yes  2
# 1  3   No  4

>>> pd.read_csv(StringIO(data), true_values=["Yes"], false_values=["No"])
#    a      b  c
# 0  1   True  2
# 1  3  False  4

Обработка “плохих” строк (аргумент on_bad_lines)

Некоторые файлы могут содержать искаженные строки со слишком малым или слишком большим количеством полей с данными. Строки со слишком малым количеством полей будут иметь значения NA, заполненные в завершающих полях. Строки со слишком большим количеством полей по умолчанию выдадут сообщение об ошибке:

>>> data = "a,b,c\n1,2,3\n4,5,6,7\n8,9,10"
>>> pd.read_csv(StringIO(data))
# Traceback (most recent call last):
# ...
# pandas.errors.ParserError: Error tokenizing data. C error: Expected 3 fields in line 3, saw 4

В подобных случаях можно выбрать пропуск плохих строк:

>>> data = "a,b,c\n1,2,3\n4,5,6,7\n8,9,10"
>>> pd.read_csv(StringIO(data), on_bad_lines="skip")
#    a  b   c
# 0  1  2   3
# 1  8  9  10

Или передать вызываемую функцию для обработки ошибочной строки, если анализатор установлен как engine='python'.

# определим переменную и функцию обработки строк
external_list = []
def bad_lines_func(line):
    external_list.append(line)
    return line[-3:]

Вызываемая функция bad_lines_func() будет обрабатывать только строку со слишком большим количеством полей. Неправильные строки, вызванные другими ошибками, будут автоматически пропущены.

>>> bad_lines_func = lambda line: print(line)
>>> data = 'name,type\nname a,a is of type a\nname b,"b\" is of type b"'
>>> print(data)
# name,type
# name a,a is of type a
# name b,"b" is of type b"

>>> pd.read_csv(StringIO(data), on_bad_lines=bad_lines_func, engine="python")
#      name            type
# 0  name a  a is of type a

Можно использовать аргумент usecols для удаления посторонних данных, которые появляются в одних строках, но не появляются в других:

>>> pd.read_csv(StringIO(data), usecols=[0, 1, 2])
# Traceback (most recent call last):
# ...
# ValueError: Usecols do not match columns, columns expected but not found: [0, 1, 2]

Если необходимо сохранить все данные, включая строки со слишком большим количеством полей, то можно указать достаточное количество имен столбцов. Это гарантирует, что строки с недостаточным количеством столбцов будут заполнены символом NaN.

>>> pd.read_csv(StringIO(data), names=['a', 'b', 'c', 'd'])
#         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

Ключевой аргумент dialect

Ключевой аргумент dialect предоставляет большую гибкость при указании формата файла. По умолчанию используется диалект Excel, но можно указать либо название диалекта, либо экземпляр csv.Dialect.

Предположим, есть данные с незавершенными кавычками:

>>> data = "label1,label2,label3\n" 'index1,"a,c,e\n' "index2,b,d,f"
>>> print(data)
# label1,label2,label3
# index1,"a,c,e
# index2,b,d,f

По умолчанию используется диалект Excel и двойная кавычка обрабатывается как символ кавычки, что приводит к сбою при поиске новой строки до того, как будет найдена закрывающая двойная кавычка.

Такое поведение можно обойти, используя диалект:

>>> import csv
>>> dia = csv.excel()
>>> dia.quoting = csv.QUOTE_NONE
>>> pd.read_csv(StringIO(data), dialect=dia)
#        label1 label2 label3
# index1     "a      c      e
# index2      b      d      f

Все параметры диалекта могут быть указаны отдельно, с помощью дополнительных ключевых аргументов:

>>> data = "a,b,c~1,2,3~4,5,6"
>>> pd.read_csv(StringIO(data), lineterminator="~")
#    a  b  c
# 0  1  2  3
# 1  4  5  6

Кавычки и экранирующие символы (аргумент escapechar)

Кавычки (и другие управляющие символы) во встроенных полях могут обрабатываться любым количеством способов. Один из способов - использовать обратную косую черту. Чтобы правильно проанализировать такие данные, необходимо передать аргумент escapechar:

>>> data = 'a,b\n"hello, \\"Bob\\", nice to see you",5'
>>> print(data)
# a,b
# "hello, \"Bob\", nice to see you",5

>>> pd.read_csv(StringIO(data), escapechar="\\")
#                                a  b
# 0  hello, "Bob", nice to see you  5

Файлы с "неявным" индексным столбцом

Рассмотрим файл, в заголовке которого на один столбец меньше, чем количество столбцов с данными. В этом особом случае функция read_csv() предполагает, что первый столбец должен использоваться в качестве индекса:

>>> data = "A,B,C\n20090101,a,1,2\n20090102,b,3,4\n20090103,c,4,5"
>>> print(data)
# A,B,C
# 20090101,a,1,2
# 20090102,b,3,4
# 20090103,c,4,5

# запишем данные
with open("foo.csv", "w") as f:
    f.write(data)

# читаем
>>> pd.read_csv("foo.csv")
#           A  B  C
# 20090101  a  1  2
# 20090102  b  3  4
# 20090103  c  4  5

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

>>> df = pd.read_csv("foo.csv", parse_dates=True)
>>> df
#             A  B  C
# 2009-01-01  a  1  2
# 2009-01-02  b  3  4
# 2009-01-03  c  4  5

Чтение данных с MultiIndex

Предположим, есть данные, проиндексированные по двум столбцам:

>>> data = 'year,indiv,zit,xit\n1977,"A",1.2,.6\n1977,"B",1.5,.5'
>>> print(data)
# year,indiv,zit,xit
# 1977,"A",1.2,.6
# 1977,"B",1.5,.5

with open("mindex_ex.csv", mode="w") as f:
    f.write(data)

Аргумент index_col может принимать список номеров столбцов, чтобы создавать MultiIndex для индекса возвращаемого объекта:

>>> df = pd.read_csv("mindex_ex.csv", index_col=[0, 1])
>>> df
#             zit  xit
# year indiv          
# 1977 A      1.2  0.6
#      B      1.5  0.5

>>> df.loc[1977]
#        zit  xit
# indiv          
# A      1.2  0.6
# B      1.5  0.5

Указав список расположений строк для аргумента header, можно прочитать MultiIndex для столбцов. При указании непоследовательных строк промежуточные строки будут пропущены.

>>> mi_idx = pd.MultiIndex.from_arrays([[1, 2, 3, 4], list("abcd")], names=list("ab"))
>>> mi_col = pd.MultiIndex.from_arrays([[1, 2], list("ab")], names=list("cd"))
>>> df = pd.DataFrame(np.ones((4, 2)), index=mi_idx, columns=mi_col)
>>> import numpy as np
>>> df = pd.DataFrame(np.ones((4, 2)), index=mi_idx, columns=mi_col)
>>> df.to_csv("mi.csv")
>>> 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

>>> pd.read_csv("mi.csv", header=[0, 1, 2, 3], index_col=[0, 1])
# 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() также может интерпретировать более распространенный формат многостолбцовых индексов.

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

with open("mi2.csv", "w") as fh:
    fh.write(data)

>>> pd.read_csv("mi2.csv", header=[0, 1], index_col=0)
#      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), то все имена в индексе столбцов будут потеряны.

Перебор файлов по фрагментам (аргументы chunksize и iterator)

Предположим, что необходимо "лениво" перебирать файл (потенциально очень большой), а не считывать весь файл в память, например:

>>> df = pd.DataFrame(np.random.randn(10, 4))
>>> df.to_csv("tmp.csv", index=False)

Если указать размер фрагмента (аргумент chunksize), то возвращаемое значение будет итерируемым объектом типа TextFileReader:

with pd.read_csv("tmp.csv", chunksize=4) as reader:
    print(reader)
    for chunk in reader:
        print(chunk)

# <pandas.io.parsers.readers.TextFileReader object at 0x7f1e31b73670>
#           0         1         2         3
# 0  0.895552 -0.158974  0.107887 -0.621232
# 1  0.626029  1.758114  1.342532  0.146105
# 2  1.294353 -0.258822  0.547958 -1.357659
# 3 -0.128099 -0.510162  0.283735 -0.410268
#           0         1         2         3
# 4 -0.732997  0.411201 -1.570236 -2.267693
# 5  0.082201 -1.406110  0.265344  0.959789
# 6 -0.437544  1.769002 -0.813527 -1.738977
# 7 -0.680272 -0.729672  0.890892  1.218180
#           0         1         2         3
# 8  0.806144  0.434089  1.362968  0.634899
# 9  0.604131 -1.290217  0.673257 -1.376953

Передача аргумента iterator=True также вернет объект TextFileReader:

with pd.read_csv("tmp.csv", iterator=True) as reader:
    print(reader.get_chunk(5))

#           0         1         2         3
# 0  0.895552 -0.158974  0.107887 -0.621232
# 1  0.626029  1.758114  1.342532  0.146105
# 2  1.294353 -0.258822  0.547958 -1.357659
# 3 -0.128099 -0.510162  0.283735 -0.410268
# 4 -0.732997  0.411201 -1.570236 -2.267693