使用 pandas 读取两个略有不同的 CSV 文件时,一个文件的处理方式与另一个文件不同。为什么?

When reading two slightly different CSV files with pandas, one gets handled differently from the other. Why?

我正在对数据集进行各种分析和绘图。

我从政府网站获取数据集作为 CSV 文件。根据数据类型,CSV 文件略有不同:

首先,我用 pythons standard CSV reader 读取了前 50 行,以搜索我稍后需要的各种字符串并找出需要多长时间header 实际上是。

下一步是用 sed 替换一些东西(更改列的名称,将 , 替换为 . 作为小数)。

然后我用

读了
Mydata=pd.read_csv(csv_list[counter],sep=';',skiprows=DataStart,index_col='Date',usecols=0,1],dayfirst=True,parse_dates=True,na_values='L\xfccke')

现在是我的问题 - 以下两个 CSV,第一个有效,第二个无效:

这个:

...20 more lines of header
Werteformat:               ;1 Nachkommast.
Date;level
01.01.1971 07:00:00   ;     0.0
02.01.1971 07:00:00   ;     0.0
03.01.1971 07:00:00   ;     0.0
...15000 lines of data
01.01.2012 07:00:00   ;Lücke

有效,而这个

...30 more lines of header
Werteformat:               ;2 Nachkommast.
Date;level;
01.01.1970 00:00:00   ;   427.27 ;     
01.02.1970 00:00:00   ;   427.80 ;     
...500 lines of data, with stuff like
01.03.1973 00:00:00   ;Lücke     ;     
in between

尝试使用

绘制直方图时出错
Traceback (most recent call last):
  File "plotter.py", line 179, in <module>
    plt.hist(Jan_RV)
  File "/usr/lib64/python2.7/site-packages/matplotlib/pyplot.py", line      2827, in hist
         stacked=stacked, **kwargs)
   File "/usr/lib64/python2.7/site-packages/matplotlib/axes.py", line 8326, in hist
     m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs)
   File "/usr/lib64/python2.7/site-packages/numpy/lib/function_base.py",      line 176, in histogram
     mn, mx = [mi+0.0 for mi in range]
 TypeError: cannot concatenate 'str' and 'float' objects

好的,所以看起来有些东西被读取为字符串,并且通过 运行 ipython 中的某些部分,我发现他们选择的是 Lücke 部分用作 NaNmissing data 代表。我以为我已经用 read_csv 中的 na_values='L\xfccke' 解决了这个问题,并且对于第一个数据集,它确实有效。如果我查看 ipython 中的 MyData,我会看到 NaN 而不是 Lücke,而对于第二个数据集,Lücke 会保留。

[编辑] 元音变音 ü 导致问题的怀疑可能是错误的?我手动将 Lücke 更改为 NaN,并去掉了 read_csv 中的 na_values='L\xfccke',它仍然将文本部分(现在是 NaN)保留为字符串。我也有

Rlength=len(MyData)   #counts everything, including NaN
Rcount=MyData.count() #counts only valid numbers
NaN_Number=Rlength-Rcount

在我的脚本中,对于第二个数据集,它总是导致 0 NaN_Numbers [/edit]

这可能是什么原因? na_values 是否只取第一个值,然后停止?我在第二个数据集中有一个空列是否会导致问题?但这无关紧要,因为我只拿前两个 usecols=[0,1].

另一个明显的区别是第一组是每日数据,第二组是每月数据,但这无关紧要。我还有其他一些月度数据,确实有效。

我的一个想法是,CSV 文件可能有不同的 行结尾 (这是正确的术语吗?Unix v. Windows,或回车 return v. line feed) 或编码,但在我的编辑器中查看它,它告诉我它们是相同的。 stat filename.csv 在终端中,也得到了非常相似的结果。

所以我完全迷路了。

编辑2:* 简短示例 CSV 文件:

Werteformat:               ;2 Nachkommast.
Date ;level ;
01.10.1982 00:00:00   ;   873.33 ;     
01.11.1982 00:00:00   ;   873.19 ;     
01.12.1982 00:00:00   ;Lücke     ;     
01.01.1983 00:00:00   ;Lücke     ;     
01.02.1983 00:00:00   ;   873.17 ;     

读入(@mhawke 的回答的一些变化已经包括在内):

Tester2=pd.read_csv('test2.csv',sep=r'\s*;',skiprows=1,index_col='Date',dayfirst=True,parse_dates=True,na_values='Lücke',usecols=[0,1])

结果

In [598]: Tester2
Out[598]: 
                level  Unnamed: 2
Date                             
1982-10-01     873.33         NaN
1982-11-01     873.19         NaN
1982-12-01        NaN         NaN
1983-01-01        NaN         NaN
1983-02-01     873.17         NaN

我也想了解这里的问题(我怀疑这与导致 Lücke 未被正确解释为 Nan 的 ¨ 编纂有关),但这里有一个解决方法。

这是我的 "test.csv" 文件:

A;B;C
1;2;;3
4;5;Lücke;6

这是我的代码:

def lucke_to_zero(val):
    if val == 'Lücke':
        return 0
    if not val:
        return 0
    return val 

mdict = {'B': lucke_to_zero}
frame = pd.read_csv("test.csv",sep=';',converters=mdict)
frame.head()

预期数据帧中的结果:

   A  B  C
1  2  0  3
4  5  0  6

第二个文件中 level 列的值包括尾随白色 space。这是因为第二个文件在 level 之后有一个附加列,由 header 和行中的尾随分隔符表示,因此白色 space 被视为该字段的一部分。考虑这个文件,它是第二个文件的最小示例(注意尾随分隔符 ;):

Date;level;
01.01.2012 07:00:00   ;Lücke ;

>>> import pandas as pd
>>> data = pd.read_csv('2.csv', sep=';')
>>> data['level'][0]
'L\xc3\xbccke '

值中包含结尾的 space,因此 na_values 必须包含 space(注意我的系统采用 UTF8 编码):

>>> data = pd.read_csv('2.csv', sep=';', na_values=['L\xc3\xbccke'])    # no space
>>> data['level'][0]
'L\xc3\xbccke '

>>> data = pd.read_csv('2.csv', sep=';', na_values=['L\xc3\xbccke '])    # with space
>>> data['level'][0]
nan

所以我认为这基本上就是您遇到问题的原因。您可以尝试将 sep 指定为正则表达式 r'\s*;' 以从所有列中删除尾随的白色 space,这应该适用于您的两个文件,以及其他可能的文件有不同数量的尾随白色space.

>>> data = pd.read_csv('2.csv', sep=r'\s*;', na_values=['L\xc3\xbccke'])    # no spaces required
>>> data['level'][0]
nan

但是:

  1. Whitespace 将从 all 列中删除,但这可能不会 对你来说是个问题。
  2. 将使用 Python 解析器引擎而不是 'c' 引擎 因为后者不支持正则表达式分隔符。警告是 发布大概是因为 Python 会比较慢。

如果上面的 2 是个问题,修复它会很困难,因为没有选项 read_csv() 来去除尾随 space。您可以在 converter 字典中提供 strip() 作为函数,但这不会影响匹配 na_values 的处理。也许您可以在使用 sed pre-process 文件时删除 whitespace。

此外,您可能需要确保在 na_values 中使用正确的字符串字符编码以匹配数据文件的字符编码。如果需要,您可以使用 encoding 参数。

@mhawke 的回答解决了我问题的第一部分。

以下问题,我的第三列充满空数据,导致我的代码 运行 失控,可能是 old pandas fedora 发布的版本。

根据 this Question usecols 曾经有一些错误,我还在 pandas 0.10,所以我可能受到了影响。在 usecols=[0,1] 中应该让我摆脱我的第三个,空列被忽略。

我的解决方法是 简单 del MyData['Unnamed: 2'] 如果我的 header 分析发现我有那些可怕的三列,它就会被触发。

到目前为止,使用 15 个 CSV 文件的测试数据集,它可以工作,但我有点担心将 'Unnamed: 2' 硬编码为列名。我还不明白该专栏为何以及如何获得该名称。

我不是专家(谁会猜到……)但不知何故感觉它并不是一个 好的 解决方案。