Чтение и запись CSV-файлов в Python
Оглавление
- Что такое CSV-файл?
- Разбор CSV-файлов с помощью встроенной библиотеки CSV в Python
- Разбор CSV-файлов с помощью библиотеки pandas
- Заключение
Давайте посмотрим правде в глаза: вам нужно получать информацию в и из ваших программ не только с помощью клавиатуры и консоли. Обмен информацией через текстовые файлы - распространенный способ обмена информацией между программами. Одним из самых популярных форматов для обмена данными является формат CSV. Но как его использовать?
Давайте проясним одну вещь: вам не нужно (и вы не будете) создавать свой собственный парсер CSV с нуля. Есть несколько вполне приемлемых библиотек, которые вы можете использовать. Библиотека Python csv
подойдет для большинства случаев. Если ваша работа требует большого количества данных или численного анализа, библиотека pandas
также имеет возможности разбора CSV, что должно справиться с остальным.
В этой статье вы узнаете, как читать, обрабатывать и разбирать CSV из текстовых файлов с помощью Python. Вы увидите, как работают файлы CSV, познакомитесь с важной библиотекой csv
, встроенной в Python, и увидите, как работает разбор CSV с помощью библиотеки pandas
.
Итак, начнем!
Что такое CSV-файл?
Файл CSV (Comma Separated Values file) - это тип обычного текстового файла, в котором используется определенная структуризация для организации табличных данных. Поскольку это обычный текстовый файл, он может содержать только реальные текстовые данные - другими словами, печатаемые символы ASCII или Unicode.
О структуре файла CSV можно судить по его названию. Обычно в файлах CSV каждое конкретное значение данных отделяется запятой. Вот как выглядит эта структура:
column 1 name,column 2 name, column 3 name
first row data 1,first row data 2,first row data 3
second row data 1,second row data 2,second row data 3
...
Обратите внимание, что каждый фрагмент данных отделяется запятой. Обычно первая строка идентифицирует каждый фрагмент данных - другими словами, это имя столбца данных. Каждая последующая строка после этого является фактическими данными и ограничена только размером файла.
В общем случае символ-разделитель называется разделителем, и запятая - не единственный используемый символ. Другие популярные разделители включают символы табуляции (\t
), двоеточия (:
) и полуточия (;
). Для правильного разбора CSV-файла необходимо знать, какой разделитель используется.
Откуда берутся CSV-файлы?
CSV-файлы обычно создаются программами, которые обрабатывают большие объемы данных. Это удобный способ экспорта данных из электронных таблиц и баз данных, а также их импорта или использования в других программах. Например, вы можете экспортировать результаты работы программы поиска данных в CSV-файл, а затем импортировать его в электронную таблицу для анализа данных, создания графиков для презентации или подготовки отчета для публикации.
С файлами CSV очень легко работать программно. Любой язык, поддерживающий ввод текстовых файлов и работу со строками (например, Python), может работать с CSV-файлами напрямую.
Parsing CSV Files With Python's Built-in CSV Library
Библиотека csv
предоставляет функциональность для чтения из CSV-файлов и записи в них. Разработанная для работы с CSV-файлами, генерируемыми Excel, она легко адаптируется для работы с различными форматами CSV. Библиотека csv
содержит объекты и другой код для чтения, записи и обработки данных из CSV-файлов и в них.
Чтение CSV-файлов с помощью csv
Чтение из CSV-файла осуществляется с помощью объекта reader
. CSV-файл открывается как текстовый файл с помощью встроенной в Python функции open()
, которая возвращает объект file. Затем он передается объекту reader
, который выполняет всю работу.
Вот employee_birthday.txt
файл:
name,department,birthday month
John Smith,Accounting,November
Erica Meyers,IT,March
Вот код для его чтения:
import csv
with open('employee_birthday.txt') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
line_count = 0
for row in csv_reader:
if line_count == 0:
print(f'Column names are {", ".join(row)}')
line_count += 1
else:
print(f'\t{row[0]} works in the {row[1]} department, and was born in {row[2]}.')
line_count += 1
print(f'Processed {line_count} lines.')
Это приводит к следующему результату:
Column names are name, department, birthday month
John Smith works in the Accounting department, and was born in November.
Erica Meyers works in the IT department, and was born in March.
Processed 3 lines.
Каждая строка, возвращаемая reader
, представляет собой список элементов String
, содержащих данные, найденные путем удаления разделителей. Первая возвращаемая строка содержит имена столбцов, которые обрабатываются особым образом.
Чтение CSV-файлов в словарь с помощью csv
Вместо того чтобы работать со списком отдельных элементов String
, вы можете читать CSV-данные непосредственно в словарь (технически, Ordered Dictionary).
Опять же, наш входной файл employee_birthday.txt
выглядит следующим образом:
name,department,birthday month
John Smith,Accounting,November
Erica Meyers,IT,March
Вот код, чтобы прочитать его как словарь на этот раз:
import csv
with open('employee_birthday.txt', mode='r') as csv_file:
csv_reader = csv.DictReader(csv_file)
line_count = 0
for row in csv_reader:
if line_count == 0:
print(f'Column names are {", ".join(row)}')
line_count += 1
print(f'\t{row["name"]} works in the {row["department"]} department, and was born in {row["birthday month"]}.')
line_count += 1
print(f'Processed {line_count} lines.')
Это приводит к тому же результату, что и раньше:
Column names are name, department, birthday month
John Smith works in the Accounting department, and was born in November.
Erica Meyers works in the IT department, and was born in March.
Processed 3 lines.
Откуда взялись ключи словаря? Предполагается, что первая строка CSV-файла содержит ключи, которые используются для построения словаря. Если в вашем CSV-файле их нет, вы должны указать свои собственные ключи, задав необязательный параметр fieldnames
в виде списка, содержащего их.
Дополнительный Python CSV reader
Параметры
Объект reader
может обрабатывать различные стили CSV-файлов, задавая дополнительные параметры, некоторые из которых приведены ниже:
-
delimiter
задает символ, используемый для разделения каждого поля. По умолчанию используется запятая (','
). -
quotechar
задает символ, используемый для окружения полей, содержащих символ-разделитель. По умолчанию используется двойная кавычка (' " '
). -
escapechar
задает символ, используемый для экранирования символа-разделителя, в случае, если кавычки не используются. По умолчанию символ не используется.
Эти параметры заслуживают более подробного объяснения. Предположим, вы работаете со следующим employee_addresses.txt
файлом:
name,address,date joined
john smith,1132 Anywhere Lane Hoboken NJ, 07030,Jan 4
erica meyers,1234 Smith Lane Hoboken NJ, 07030,March 2
Этот CSV-файл содержит три поля: name
, address
и date joined
, которые разделены запятыми. Проблема заключается в том, что данные для поля address
также содержат запятую для обозначения почтового индекса.
Есть три разных способа справиться с этой ситуацией:
-
Используйте другой разделитель
Таким образом, запятую можно смело использовать в самих данных. Для указания нового разделителя используется необязательный параметрdelimiter
. -
Обернуть данные в кавычки
Специальный характер выбранного вами разделителя игнорируется в строках, заключенных в кавычки. Поэтому вы можете указать символ, используемый для кавычек, с помощью необязательного параметраquotechar
. Если этот символ также не встречается в данных, то все в порядке. -
Обратите символы-разделители в данных
Символы экранирования работают так же, как и в строках форматирования, обнуляя интерпретацию экранируемого символа (в данном случае разделителя). Если используется символ экранирования, он должен быть указан с помощью дополнительного параметраescapechar
.
Запись CSV-файлов с помощью csv
Вы также можете записывать в CSV-файл, используя объект writer
и метод .write_row()
:
import csv
with open('employee_file.csv', mode='w') as employee_file:
employee_writer = csv.writer(employee_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
employee_writer.writerow(['John Smith', 'Accounting', 'November'])
employee_writer.writerow(['Erica Meyers', 'IT', 'March'])
Необязательный параметр quotechar
указывает writer
, какой символ использовать для кавычек в полях при записи. Однако, будет ли использоваться кавычки или нет, определяется дополнительным параметром quoting
:
- Если для
quoting
установлено значениеcsv.QUOTE_MINIMAL
, то.writerow()
будет заключать поля в кавычки, только если они содержатdelimiter
илиquotechar
. Это случай по умолчанию. - Если для
quoting
установлено значениеcsv.QUOTE_ALL
, то.writerow()
будет заключать в кавычки все поля. - Если
quoting
установлено значениеcsv.QUOTE_NONNUMERIC
, то.writerow()
будет заключать в кавычки все поля, содержащие текстовые данные, и преобразовывать все числовые поля к типу данныхfloat
. - Если
quoting
имеет значениеcsv.QUOTE_NONE
, то.writerow()
будет экранировать разделители вместо того, чтобы заключать их в кавычки. В этом случае вы также должны указать значение необязательного параметраescapechar
.
Перечитывание файла в виде обычного текста показывает, что файл создается следующим образом:
John Smith,Accounting,November
Erica Meyers,IT,March
Запись CSV-файла из словаря с помощью csv
Раз уж вы можете читать наши данные в словарь, то будет справедливо, если вы сможете записывать их и из словаря:
import csv
with open('employee_file2.csv', mode='w') as csv_file:
fieldnames = ['emp_name', 'dept', 'birth_month']
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({'emp_name': 'John Smith', 'dept': 'Accounting', 'birth_month': 'November'})
writer.writerow({'emp_name': 'Erica Meyers', 'dept': 'IT', 'birth_month': 'March'})
В отличие от DictReader
, параметр fieldnames
необходим при записи словаря. Это имеет смысл, если подумать: без списка fieldnames
DictWriter
не может знать, какие ключи использовать для извлечения значений из ваших словарей. Он также использует ключи в fieldnames
для записи первой строки в виде имен столбцов.
Приведенный выше код генерирует следующий выходной файл:
emp_name,dept,birth_month
John Smith,Accounting,November
Erica Meyers,IT,March
Разбор CSV-файлов с помощью библиотеки pandas
Конечно, библиотека Python CSV - не единственная игра в городе. Чтение CSV-файлов возможно и в pandas
. Настоятельно рекомендуется, если вам нужно проанализировать большое количество данных.
pandas
- это библиотека Python с открытым исходным кодом, которая предоставляет высокопроизводительные инструменты для анализа данных и простые в использовании структуры данных. pandas
доступна для всех инсталляций Python, но является ключевой частью дистрибутива Anaconda и отлично работает в Jupyter notebook для обмена данными, кодом, результатами анализа, визуализациями и описательным текстом.
Установка pandas
и его зависимостей в Anaconda
легко выполняется:
$ conda install pandas
Как и использование pip
/pipenv
для других установок Python:
$ pip install pandas
Мы не будем вдаваться в подробности того, как работает pandas
и как его использовать. Для получения подробной информации об использовании pandas
для чтения и анализа больших массивов данных ознакомьтесь с превосходной статьей Шантну Тивари о работе с большими файлами Excel в pandas.
Чтение CSV-файлов с помощью pandas
Чтобы продемонстрировать возможности pandas
CSV, я создал немного более сложный файл для чтения, который называется hrdata.csv
. Он содержит данные о сотрудниках компании:
Name,Hire Date,Salary,Sick Days remaining
Graham Chapman,03/15/14,50000.00,10
John Cleese,06/01/15,65000.00,8
Eric Idle,05/12/14,45000.00,10
Terry Jones,11/01/13,70000.00,3
Terry Gilliam,08/12/14,48000.00,7
Michael Palin,05/23/13,66000.00,8
Чтение CSV в pandas
DataFrame
происходит быстро и просто:
import pandas
df = pandas.read_csv('hrdata.csv')
print(df)
Вот и все: три строки кода, и только одна из них выполняет реальную работу. pandas.read_csv()
открывает, анализирует и считывает предоставленный CSV-файл и сохраняет данные в DataFrame. Печать DataFrame
приводит к следующему результату:
Name Hire Date Salary Sick Days remaining
0 Graham Chapman 03/15/14 50000.0 10
1 John Cleese 06/01/15 65000.0 8
2 Eric Idle 05/12/14 45000.0 10
3 Terry Jones 11/01/13 70000.0 3
4 Terry Gilliam 08/12/14 48000.0 7
5 Michael Palin 05/23/13 66000.0 8
Вот несколько моментов, на которые стоит обратить внимание:
- Во-первых,
pandas
распознал, что первая строка CSV содержит имена столбцов, и использовал их автоматически. Я называю это добротой. - Однако
pandas
также использует нулевые целочисленные индексы вDataFrame
. Это потому, что мы не сказали ему, каким должен быть наш индекс. -
Далее, если вы посмотрите на типы данных наших столбцов, то увидите, что
pandas
правильно преобразовал столбцыSalary
иSick Days remaining
в числа, но столбецHire Date
по-прежнему являетсяString
. Это легко подтвердить в интерактивном режиме:>>> print(type(df['Hire Date'][0])) <class 'str'>
Давайте рассмотрим эти вопросы по очереди. Чтобы использовать другой столбец в качестве индекса DataFrame
, добавьте необязательный параметр index_col
:
import pandas
df = pandas.read_csv('hrdata.csv', index_col='Name')
print(df)
Теперь поле Name
является нашим DataFrame
индексом:
Hire Date Salary Sick Days remaining
Name
Graham Chapman 03/15/14 50000.0 10
John Cleese 06/01/15 65000.0 8
Eric Idle 05/12/14 45000.0 10
Terry Jones 11/01/13 70000.0 3
Terry Gilliam 08/12/14 48000.0 7
Michael Palin 05/23/13 66000.0 8
Далее давайте исправим тип данных поля Hire Date
. Вы можете заставить pandas
читать данные как дату с помощью необязательного параметра parse_dates
, который определяется как список имен столбцов, которые следует рассматривать как даты:
import pandas
df = pandas.read_csv('hrdata.csv', index_col='Name', parse_dates=['Hire Date'])
print(df)
Обратите внимание на разницу в выводе:
Hire Date Salary Sick Days remaining
Name
Graham Chapman 2014-03-15 50000.0 10
John Cleese 2015-06-01 65000.0 8
Eric Idle 2014-05-12 45000.0 10
Terry Jones 2013-11-01 70000.0 3
Terry Gilliam 2014-08-12 48000.0 7
Michael Palin 2013-05-23 66000.0 8
Теперь дата форматируется правильно, что легко подтвердить в интерактивном режиме:
>>> print(type(df['Hire Date'][0]))
<class 'pandas._libs.tslibs.timestamps.Timestamp'>
Если в ваших CSV-файлах нет имен колонок в первой строке, вы можете использовать дополнительный параметр names
, чтобы предоставить список имен колонок. Вы также можете использовать этот параметр, если хотите переопределить имена столбцов, указанные в первой строке. В этом случае вы также должны указать pandas.read_csv()
на игнорирование существующих имен столбцов с помощью необязательного параметра header=0
:
import pandas
df = pandas.read_csv('hrdata.csv',
index_col='Employee',
parse_dates=['Hired'],
header=0,
names=['Employee', 'Hired','Salary', 'Sick Days'])
print(df)
Обратите внимание, что, поскольку имена столбцов изменились, столбцы, указанные в дополнительных параметрах index_col
и parse_dates
, также должны быть изменены. Теперь мы получим следующий результат:
Hired Salary Sick Days
Employee
Graham Chapman 2014-03-15 50000.0 10
John Cleese 2015-06-01 65000.0 8
Eric Idle 2014-05-12 45000.0 10
Terry Jones 2013-11-01 70000.0 3
Terry Gilliam 2014-08-12 48000.0 7
Michael Palin 2013-05-23 66000.0 8
Запись CSV-файлов с помощью pandas
Конечно, если вы не можете снова извлечь данные из pandas
, это не принесет вам особой пользы. Записать DataFrame
в CSV-файл так же просто, как и прочитать его. Давайте запишем данные с новыми именами столбцов в новый CSV-файл:
import pandas
df = pandas.read_csv('hrdata.csv',
index_col='Employee',
parse_dates=['Hired'],
header=0,
names=['Employee', 'Hired', 'Salary', 'Sick Days'])
df.to_csv('hrdata_modified.csv')
Единственное отличие этого кода от приведенного выше кода чтения заключается в том, что вызов print(df)
был заменен на df.to_csv()
с указанием имени файла. Новый CSV-файл выглядит следующим образом:
Employee,Hired,Salary,Sick Days
Graham Chapman,2014-03-15,50000.0,10
John Cleese,2015-06-01,65000.0,8
Eric Idle,2014-05-12,45000.0,10
Terry Jones,2013-11-01,70000.0,3
Terry Gilliam,2014-08-12,48000.0,7
Michael Palin,2013-05-23,66000.0,8
Заключение
Если вы понимаете основы чтения CSV-файлов, то вы никогда не окажетесь в затруднительном положении, когда вам придется иметь дело с импортом данных. С большинством задач по чтению, обработке и записи CSV легко справится базовая библиотека csv
Python. Если вам нужно прочитать и обработать большое количество данных, библиотека pandas
также предоставляет возможности быстрой и простой работы с CSV.
Существуют ли другие способы разбора текстовых файлов? Конечно! Такие библиотеки, как ANTLR, PLY и PlyPlus, могут справиться с сильным разбором, а если простые String
манипуляции не помогают, всегда есть регулярные выражения.
Но это темы для других статей...
Вернуться на верх