使用 pandas 读取两个略有不同的 CSV 文件时,一个文件的处理方式与另一个文件不同。为什么?
When reading two slightly different CSV files with pandas, one gets handled differently from the other. Why?
我正在对数据集进行各种分析和绘图。
我从政府网站获取数据集作为 CSV 文件。根据数据类型,CSV 文件略有不同:
- 长度 header
- header
的内容
- 列数
- NaN 值的数量
- 每月或每日数据
- 值的大小
首先,我用 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
部分用作 NaN
或 missing 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
但是:
- Whitespace 将从 all 列中删除,但这可能不会
对你来说是个问题。
- 将使用 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'
硬编码为列名。我还不明白该专栏为何以及如何获得该名称。
我不是专家(谁会猜到……)但不知何故感觉它并不是一个 好的 解决方案。
我正在对数据集进行各种分析和绘图。
我从政府网站获取数据集作为 CSV 文件。根据数据类型,CSV 文件略有不同:
- 长度 header
- header 的内容
- 列数
- NaN 值的数量
- 每月或每日数据
- 值的大小
首先,我用 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
部分用作 NaN
或 missing 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
但是:
- Whitespace 将从 all 列中删除,但这可能不会 对你来说是个问题。
- 将使用 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'
硬编码为列名。我还不明白该专栏为何以及如何获得该名称。
我不是专家(谁会猜到……)但不知何故感觉它并不是一个 好的 解决方案。