用 pandas 打开德语 csv 文件的最佳方法是什么?
\n我有一个包含以下列的德语 csv 文件:
\n我的预期输出是:
\n Umlaute Zahlen\nDatum \n2020-01-01 R\xc3\xbcdiger 1000000.11\n2020-01-02 G\xc3\xbcnther 12.34\n2020-01-03 J\xc3\xbcrgen 567.89\n
Run Code Online (Sandbox Code Playgroud)\n下面提供了示例数据(参见文件)。
\n Umlaute Zahlen\nDatum \n2020-01-01 R\xc3\xbcdiger 1000000.11\n2020-01-02 G\xc3\xbcnther 12.34\n2020-01-03 J\xc3\xbcrgen 567.89\n
Run Code Online (Sandbox Code Playgroud)\n这会抛出一个UnicodeDecodeError
:
UnicodeDecodeError: \'utf-8\' codec can\'t decode byte 0xfc in position 12: invalid start byte\n
Run Code Online (Sandbox Code Playgroud)\n df = pd.read_csv(\'german_csv_test.csv\', sep=\';\', encoding=\'latin1\')\n
Run Code Online (Sandbox Code Playgroud)\n这不会引发错误,但它与我想要的输出相去甚远:
\n Datum Umlaute Zahlen\n0 01.01.2020 R\xc3\xbcdiger 1.000.000,11 \n1 02.01.2020 G\xc3\xbcnther 12,34 \n2 03.01.2020 J\xc3\xbcrgen 567,89 \n
Run Code Online (Sandbox Code Playgroud)\ndf = pd.read_csv(\'german_csv_test.csv\', sep=\';\', encoding=\'latin1\')\ndf[\'Datum\'] = pd.to_datetime(df[\'Datum\'])\ndf = df.set_index(\'Datum\')\ndf[\'Zahlen\'] = pd.to_numeric(df[\'Zahlen\'])\n
Run Code Online (Sandbox Code Playgroud)\n现在,我有四行代码,但它仍然不起作用。最后一行抛出错误ValueError: Unable to parse string " 1.000.000,11 " at position 0
。如果我注释掉最后一行,它就会起作用。但日期仍然是错误的,因为日期和月份互换了。
Umlaute Zahlen\nDatum \n2020-01-01 R\xc3\xbcdiger 1.000.000,11 \n2020-02-01 G\xc3\xbcnther 12,34 \n2020-03-01 J\xc3\xbcrgen 567,89 \n
Run Code Online (Sandbox Code Playgroud)\n我的文件german_csv_test.csv
如下所示:
Datum;Umlaute;Zahlen\n01.01.2020;R\xc3\xbcdiger; 1.000.000,11 \n02.01.2020;G\xc3\xbcnther; 12,34 \n03.01.2020;J\xc3\xbcrgen; 567,89 \n
Run Code Online (Sandbox Code Playgroud)\n它被编码为“cp1252”。我使用“CSV (MS-DOS)”选项将其保存在 Windows 上。
\n 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')
Run Code Online (Sandbox Code Playgroud)
德国 csv 文件很棘手,因为乍一看它们看起来不错,但数据类型都是错误的,而且月份和日期之间的切换可能会令人沮丧。上述参数适用于各种欧洲 csv 文件。下面我将解释每个参数。
sep=';'
几乎所有德语 csv 文件都使用分号“;” 作为分隔符。这适用于大多数欧洲国家。您可能会说这是错误的,因为 csv 意味着“逗号分隔值”。但这不是对错的问题,而是惯例的问题。您可以说 csv 代表“字符分隔值”。
thousands='.'
和decimal=','
此外,大多数欧洲国家使用点来对千位进行分组,并使用逗号来分隔小数。这篇很棒的文章解释了原因。
encoding='latin1'
如果您在Python 文档中查找德语编码,您将看到德语的编解码器“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,同样使用下划线而不是破折号。对这些编码使用替代别名可能会导致执行速度变慢。
如需进一步阅读,请查看这篇 SO 文章和Joel Spolsky 的博客。
converters=converters
大多数 pandas 用户都低估了转换器的重要性。它看起来像是一个简单问题的复杂解决方案。pd.to_datetime()
为什么读完文件后不使用呢?您希望将输入与数据处理分开(请参阅IPO 模型)。
我已经多次看到(并写过)这样的东西:
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')
Run Code Online (Sandbox Code Playgroud)
在下一次迭代中,你可能会晋升pd.to_datetime()
。但也许不是。这可能会导致一些意想不到的行为。编写此类代码两个月后,您只会看到一长串非结构化的 pandas 操作,并且您会认为“这真是一团糟。 ”
有多种方法可以清理数据框。但为什么不使用内置转换器呢?如果您为数据帧的每一列定义dtypes
和converters
,您就不必回头(愤怒地)。打电话后你就站稳了脚跟pd.read_csv()
。
请注意,转换器仅接受函数。这就是我在转换器中使用 lambda 函数的原因。否则我无法指定格式参数。
index_col='Datum'
这只是定义了索引列。它很方便,因为替代方案df = df.set_index('Datum')
并不那么漂亮。此外,它还有助于 - 像转换器一样 - 将输入块与数据处理分开。
归档时间: |
|
查看次数: |
2178 次 |
最近记录: |