【发布时间】:2020-12-17 07:47:19
【问题描述】:
我正在读取 CSV 数据以用作 pandas 数据框,但 CSV 似乎没有遵循任何合理的约定(除了使用 ; 作为分隔符,每个人都应该......)。似乎唯一的目标是让它们在文本编辑器中打开时看起来不错
这里有一些示例(设置为变量,以便它们可以用于读者示例):
ex1="""
Type: Some Metadata
User: More Metadata
Data:
01.10.1939 00:00:00 ; 1,1 ;
01.12.1939 00:00:00 ; 1 ;
01.01.1940 00:00:00 ; 10 ;
"""
好的,十进制逗号(简单),分号分隔符(简单),dayfirst(简单)和一堆元数据(skiprows,也简单)。
ts = pd.read_csv(io.StringIO(ex1), skiprows=4, decimal=',', sep=';',
index_col=0, usecols=[0,1], dayfirst=True,
parse_dates=True, names=['date', 'val'])
print(ts 生成一个不错的数据框
val
date
1939-10-01 1.1
1939-12-01 1.0
1940-01-01 10.0
而ts.index 是一个不错的DatetimeIndex,而type(ts.val[0]) 是一个numpy.float64,应该是这样。但是让我们介绍一种创意的方式来标记NaN:
ex2="""
Type: Some Metadata
User: More Metadata
Data:
01.10.1939 00:00:00 ; 1,1;
01.12.1939 00:00:00 ; NÄ ;
01.01.1940 00:00:00 ; 10 ;
"""
上面的ts=read_csv... 仍然可以正常工作,但NÄ 打破了val 列并将其转换为字符串。但是当我把它改成
ts = pd.read_csv(io.StringIO(ex2), skiprows=4, decimal=',', sep=';',
index_col=0, usecols=[0,1], dayfirst=True,
parse_dates=True, names=['date', 'val'],
na_values='NÄ')
使用na_values,整个事情都失败了。 print(ts)
val
date
1939-10-01 1,1
1939-12-01 NÄ
1940-01-01 10
它不仅不接受NÄ 为NaN,这还将所有vals 转换为字符串,从而忽略小数逗号并保留尾随空格。 ts.val[0] 现在是 ' 1,1',所以一个简单的 ts.val = ts.val.astype(float) 当然会失败。
na_values='NÄ' 我做错了什么?
为什么还会破坏decimal','并添加空格?
似乎skipinitialspace=True 应该有所帮助,但当然NÄ 仍然会破坏val 列。
sep='\s*[;]s*' 看起来很有希望,而且
ts = pd.read_csv(io.StringIO(ex2), skiprows=4, decimal=',' ,sep='\s*[;]s*',
index_col=0, usecols=[0,1], dayfirst=True,
parse_dates=True, names=['date', 'val'],
na_values='NÄ')
给出了一个明显不错的print(ts)
val
date
1939-10-01 1.1
1939-12-01 NÄ
1940-01-01 10
(注意小数点!),但现在我遇到了一个奇怪的情况,它确实替换了逗号,但ts.val[0] 现在又是一个字符串,并且仍然有尾随空格(' 1.1')。
那么我该如何阅读那些无聊的文件呢?
我目前使用的解决方法是使用纯 python 读取 CSV(无论如何我必须读取标题(实际文件中的 40 行))并将其写入正确的 CSV,以便读取熊猫:
file = open(myfile, 'r', encoding='UTF-8')
table = file.readlines()
file.close()
for v1 in range(0, len(table)):
table[v1] = table[v1].replace("NÄ", "NaN")
table[v1] = table[v1].replace(",", ".")
dataoutput = ["date;val\r\n"]
for v1 in range(3, len(table)):
dataoutput.append(table[v1])
f2 = open(myfile.replace('.csv', 'good.csv'), 'w')
for v1 in range(0, len(dataoutput)):
f2.write(dataoutput[v1])
f2.close()
ts = pd.read_csv(myfile.replace('.csv', 'good.csv'),
sep=';', usecols=[0, 1], index_col=0,
dayfirst=True, parse_dates=True)
ts.val = ts.val.astype(float)
但是对于几千个 CSV 文件,大小达到一兆字节,这并不是真正的最佳解决方案,所以我想解决导入中的 NÄ 问题。
【问题讨论】:
-
我可能遗漏了一些东西,但可以在对
read_csv()的调用中指定 dtypes,做到这一点,或者在文件解析后转换值? -
您可以将值指定为列表:na_values=[ '-1.#IND ', '1.#INF ' ];还要检查尾随空格(查看我的示例)。
-
dtype={'val':np.float64}只是ValueError: Unable to convert column val to type <class 'numpy.float64'>的错误并在列表中设置NÄ(na_values=['NÄ']) 也不会改变结果。尾随(或前导)空格可能是一个问题。必须看看正则表达式的作用。 -
将
NÄ设置为空格 (na_values='\s*[NÄ]\s*') 似乎没有任何改变。 -
其他想法:检查编码。我对德语文件也有类似的问题。这是我完整的阅读行:
df = pd.read_csv( join( path, filename ), sep=';', encoding='iso-8859-1', engine='c', skiprows=[0], usecols=colstouse, na_values=[ '-1.#IND ', ' 1.#INF ' ] )
标签: python pandas csv unicode separator