用熊猫打开德国csv文件的最佳方法是什么?
我有一个德国csv文件,其中包含以下列:
我的预期输出是:
Umlaute Zahlen
Datum
2020-01-01 Rüdiger 1000000.11
2020-01-02 Günther 12.34
2020-01-03 Jürgen 567.89
下面提供了示例数据(请参见文件)。
df = pd.read_csv('german_csv_test.csv')
这会引发UnicodeDecodeError
:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 12: invalid start byte
df = pd.read_csv('german_csv_test.csv', sep=';', encoding='latin1')
这不会引发任何错误,但与我期望的输出相距很远:
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
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”。我使用选项“ CSV(MS-DOS)”将其保存在Windows上。
答案 0 :(得分:4)
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代表"character separated values"。
thousands='.'
和decimal=','
此外,大多数欧洲国家/地区都使用点将千位和逗号分隔成小数。 This great article解释了原因。
encoding='latin1'
如果您在Python documentation中查找德语编码,则会看到德语的编解码器“ cp273”。很少使用。对于西欧,您最好使用“ latin1”。使用此编解码器可受益于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,并使用下划线代替破折号。对这些编码使用备用别名可能会导致执行速度变慢。
为了进一步阅读,请查找this SO post和Joel Spolsky's blog。
converters=converters
大多数熊猫用户对转换器的了解不足。它看起来像一个简单问题的复杂解决方案。为什么在读取文件后不使用pd.to_datetime()
?您要将输入与处理数据分开(请参见IPO model)。
我看过(写过)很多次了:
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()
。但也许不是。可能导致某些意外行为。编写此类代码两个月后,您只看到了一系列漫长的非结构化熊猫操作,并且认为“ 这是一团糟。”
有几种清除数据框的方法。但是为什么不使用内置转换器呢?如果您为数据框的每一列定义dtypes
和converters
,则不必回头(生气)。致电pd.read_csv()
后,您会站稳脚跟。
请注意,转换器仅接受功能。这就是为什么我在转换器中使用了lambda函数的原因。否则,我无法指定format参数。
在documentation和this SO post中了解有关转换器的更多信息
index_col='Datum'
这只是定义索引列。这很方便,因为替代项df = df.set_index('Datum')
并不那么漂亮。此外,它与转换器一样,有助于将输入块与数据处理分开。