Как открыть немецкий CSV-файл с pandas? - PullRequest
1 голос
/ 13 июля 2020

Вопрос

Как лучше всего открыть немецкий CSV-файл с помощью pandas?

У меня есть немецкий CSV-файл со следующими столбцами:

  • Дата: Дата в формате «ДД.ММ.ГГГГ»
  • Umlaute: немецкие имена со специальными символами, c в немецком языке
  • Zahlen: Числа в формате '000.000 , 00 '

Мой ожидаемый результат:

            Umlaute      Zahlen
Datum                          
2020-01-01  Rüdiger  1000000.11
2020-01-02  Günther       12.34
2020-01-03   Jürgen      567.89

Примеры данных приведены ниже (см. Файл).

1-я попытка: использовать pd.read_csv () без параметров

    df = pd.read_csv('german_csv_test.csv')

Это вызывает UnicodeDecodeError:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 12: invalid start byte

2-я попытка: используйте pd.read_csv с указанием кодировки и разделение

  df = pd.read_csv('german_csv_test.csv', sep=';', encoding='latin1')

Это не вызывает ошибок, но это далеко от моего желаемого результата:

  • Даты являются строками, а не временем.
  • Числа не совпадают ' t float, но объекты.
  • Столбец «Datum» не является индексом.
        Datum  Umlaute          Zahlen
0  01.01.2020  Rüdiger   1.000.000,11 
1  02.01.2020  Günther          12,34 
2  03.01.2020   Jürgen         567,89 

3-я попытка: очистка

df = pd.read_csv('german_csv_test.csv', sep=';', encoding='latin1')
df['Datum'] = pd.to_datetime(df['Datum'])
df = df.set_index('Datum')
df['Zahlen'] = pd.to_numeric(df['Zahlen'])

Теперь, У меня четыре строчки кода, но он все еще не работает. Последняя строка выдает ошибку ValueError: Unable to parse string " 1.000.000,11 " at position 0. Если я прокомментирую последнюю строчку, она работает. Но даты все равно неправильные, потому что день и месяц поменялись местами.

            Umlaute          Zahlen
Datum                              
2020-01-01  Rüdiger   1.000.000,11 
2020-02-01  Günther          12,34 
2020-03-01   Jürgen         567,89 

Файл

Мой файл german_csv_test.csv выглядит так:

Datum;Umlaute;Zahlen
01.01.2020;Rüdiger; 1.000.000,11 
02.01.2020;Günther; 12,34 
03.01.2020;Jürgen; 567,89 

Он закодирован как 'cp1252'. Я сохранил его на Windows с опцией «CSV (MS-DOS)».

1 Ответ

4 голосов
/ 13 июля 2020

Решение

    converters = {'Datum': lambda x: pd.to_datetime(x, format='%d.%m.%Y')}
    df1 = pd.read_csv('german_csv_test.csv', sep=';', thousands='.', decimal=',', encoding='latin1',
                      converters=converters, index_col='Datum')

Немецкие CSV-файлы сложны, потому что на первый взгляд они выглядят нормально, но все типы данных неверны, и переключение между месяцем и днем ​​может расстраивать. Вышеуказанные параметры работают с широким спектром европейских файлов csv. Далее я объясню каждый параметр.

Параметр sep=';'

Почти во всех немецких CSV-файлах используется точка с запятой ';' как характер разделения. Это справедливо для большинства европейских стран. Вы можете возразить, что это неправильно, потому что csv означает «значения, разделенные запятыми». Но дело не в правильном или неправильном, а в условности. И вы могли бы сказать, что csv означает «значения, разделенные символами» .

Параметры thousands='.' и decimal=','

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

Параметр encoding='latin1'

Если вы посмотрите немецкую кодировку в Python документации , вы увидите код c 'cp273' для немецкого языка. Используется редко. Вам должно быть хорошо с "latin1" для Западной Европы. Использование этого кода c извлекает выгоду из внутренней оптимизации в CPython:

CPython детали реализации : Некоторые распространенные кодировки могут обходить кодеки поисковый механизм для повышения производительности. Эти возможности оптимизации распознаются CPython только для ограниченного набора псевдонимов (без учета регистра): utf-8, utf8, latin-1, latin1, iso-8859-1, iso8859-1, mbcs (Windows только), ascii, us-ascii, utf-16, utf16, utf-32, utf32 и то же самое с использованием подчеркивания вместо тире. Использование альтернативных псевдонимов для этих кодировок может привести к более медленному выполнению.

Для дальнейшего чтения посмотрите этот пост SO и блог Джоэла Спольски .

Параметр converters=converters

Конвертеры недооцениваются большинством pandas пользователей. Это похоже на сложное решение простой проблемы. Почему бы не использовать pd.to_datetime() после прочтения файла? Вы хотите отделить ввод от обработки данных (см. модель IPO ).

Я видел (и писал) что-то подобное много раз:

  df = pd.read_csv('test.csv')
  df['Revenue'] = df['Price'] * df['Quantity']  # I don't have to clean up all columns. I just need the revenue.
  (...)  # Some other code

  # Plotting revenue
  df['Revenue'] = df['Revenue'] / 1000
  df['Date'] = pd.to_datetime(df['Date'])  # Oh, the dates are still strings. I can fix this easily before plotting.

В следующей итерации вы можете переместить pd.to_datetime() вверх. А может и нет. И, вероятно, это приводит к какому-то неожиданному поведению. Через два месяца после того, как вы написали такой код, вы просто видите длинную последовательность неструктурированных pandas операций и думаете: « Это беспорядок. »

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

Имейте в виду, что конвертеры принимают только функции. Вот почему я использовал в конвертере лямбда-функцию. В противном случае я не смог бы указать параметр формата.

Подробнее о преобразователях см. В документации и в этом сообщении SO

Параметр index_col='Datum'

Это просто определяет столбец индекса. Это удобно, потому что альтернатива df = df.set_index('Datum') не так хороша. Кроме того, это помогает, как и конвертеры, отделять входной блок от обработки данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...