簡體   English   中英

如何使用 pandas 打開德國 csv 文件?

[英]How to open a German csv file with pandas?

問題

用 pandas 打開德國 csv 文件的最佳方法是什么?

我有一個德國 csv 文件,其中包含以下列:

  • 基准:日期格式為 'DD.MM.YYYY'
  • 變音符號:帶有特定於德語的特殊字符的德語名稱
  • Zahlen:格式為“000.000,00”的數字

我預期的 output 是:

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

下面提供了示例數據(見文件)。


第一次嘗試:使用不帶參數的 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

第二次嘗試:使用 pd.read_csv 指定編碼和分隔

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

這不會引發錯誤,但與我想要的 output 相差甚遠:

  • 日期是字符串而不是日期時間。
  • 數字不是浮動的,而是對象。
  • “基准”列不是索引。
        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 上。

解決方案

    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 文檔中查找德語編碼,您將看到德語的編解碼器“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 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()向上移動。 但也許不是。 這可能會導致一些意想不到的行為。 編寫此類代碼兩個月后,您只看到一長串非結構化的 pandas 操作,您會認為“這是一團糟。

有幾種方法可以清潔您的 dataframe。 但是為什么不使用內置轉換器呢? 如果您為 dataframe 的每一列定義dtypesconverters ,您不必回頭(憤怒地)。 調用pd.read_csv()后,您站在了堅實的基礎上。

請注意,轉換器僅接受函數。 這就是我在轉換器中使用 lambda function 的原因。 否則我無法指定格式參數。

文檔此 SO 帖子中了解有關轉換器的更多信息

參數index_col='Datum'

這只是定義了索引列。 這很方便,因為替代df = df.set_index('Datum')不是那么漂亮。 此外,它有助於 - 像轉換器一樣 - 將輸入塊與數據處理分開。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM