Python 使用pd.read_CSV(不规则分隔符,自定义NA)读取borked CSV文件

Python 使用pd.read_CSV(不规则分隔符,自定义NA)读取borked CSV文件,python,pandas,csv,unicode,separator,Python,Pandas,Csv,Unicode,Separator,我正在读取CSV数据以用作熊猫数据帧,但CSV似乎没有遵循任何合理的约定(除了使用;作为分隔符外,每个人都应该……)。看起来,唯一的目标是让它们在文本编辑器中打开时看起来好看 以下是一些示例(设置为变量,以便读者可以使用这些示例): 好的,十进制逗号(easy)、分号分隔符(easy)、dayfirst(easy)和一组元数据(skiprows,也很容易) print(ts生成一个漂亮的数据帧 val date 1939-10-01 1.1 1939-12-01

我正在读取CSV数据以用作熊猫数据帧,但CSV似乎没有遵循任何合理的约定(除了使用
作为分隔符外,每个人都应该……)。看起来,唯一的目标是让它们在文本编辑器中打开时看起来好看

以下是一些示例(设置为变量,以便读者可以使用这些示例):

好的,十进制逗号(easy)、分号分隔符(easy)、dayfirst(easy)和一组元数据(skiprows,也很容易)

print(ts
生成一个漂亮的数据帧

             val
date
1939-10-01   1.1
1939-12-01   1.0
1940-01-01  10.0
ts.index
是一个很好的
DatetimeIndex
类型(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…
仍然可以正常工作,但是
会将
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Ä')
使用时,整个操作将失败。
print(ts)

它不仅不接受
作为
NaN
,还将所有
val
s转换为字符串,从而忽略小数点逗号并保留尾随空格。
ts.val[0]
现在是
'1,1'
,因此简单的
ts.val=ts.val.astype(float)
当然失败了

我在
na_values='NÄ'
方面做错了什么?

为什么它还会打断
decimal','
并添加空格?

似乎
skipinitialspace=True
应该会有所帮助,但当然
仍然会打断
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Ä')
提供了一个很好的
打印(ts)

(注意小数点!),但现在我遇到了一个奇怪的情况,它确实替换了逗号,但是
ts.val[0]
现在又是一个字符串,并且仍然有尾随空格(
'1.1'

那么我该如何读取这些文件呢?

我目前使用的解决方法是使用纯python读取CSV(我必须读取头文件(实际文件中有40行),然后将其写入正确的CSV,以便使用pandas读取:

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文件,大小高达1兆字节,这并不是一个真正的最佳解决方案,因此我想解决导入中的
问题。

您的
sep
指定错误(它以
s*
结尾,而不是
\s*
,这意味着它要查找0到无限个
s
字符)。这就是为什么您只捕获
后面的前导空格,而不捕获后面的空格;
。顺便说一句,这也干扰了(1),因为您试图替换
“NÄ”
,但值为
“NÄ”
。请改用
sep='\s*\\\s*'

将来可以做的一件事是自己打印出有问题的值,以确保它们包含它们认为您包含的内容,例如
ts.iloc[1].val

此外,如果unicode中的
NaN
值存在问题,则可以在解析之前将其剥离:

csv = io.StringIO(ex2.replace(u'N\xc4', '[MISSING]'))
ts = pd.read_csv(csv, 
    skiprows=4, decimal=',', index_col=0, usecols=[0,1], 
    dayfirst=True, parse_dates=True, names=['date', 'val'], 
    na_values='[MISSING]', sep='\s*\;\s*')
…这会给

             val
date
1939-10-01   1.1
1939-12-01   NaN
1940-01-01  10.0

我可能错过了一些东西,但是可以在调用
read_csv()
时指定数据类型,或者在解析文件后转换值吗?可以将值指定为列表:na_values=['-1.#IND',1.#INF'];还可以检查尾随空格(检查我的示例)。
dtype={'val':np.float64}
仅包含
ValueError的错误:无法将列val转换为type
,并且在列表中设置
naÄ值=['NÄ']]
)也不会改变结果。尾随(或前导)空格可能是一个问题。必须查看正则表达式的功能。将
设置为空格(
naÄ值=''\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']
uex.replace在我没有使用
StringIO
而是使用
pd.read_csv('file.csv,skiprows=…
)执行示例时如何工作?
csv=open('file.csv')。replace(u'N\xc4','missing]'
?结果是
属性错误:“\u io.TextIOWrapper”对象对我来说没有属性“replace”
。“使用
sep='\s*\\\s*'
而不是“该死,我可以发誓我总是在
s
之前拥有
\
。当然,搜索字母s没有意义。修复
sep
有效,没有
read().replace()。
               val
date
1939-10-01     1.1
1939-12-01      NÄ
1940-01-01      10
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 = io.StringIO(ex2.replace(u'N\xc4', '[MISSING]'))
ts = pd.read_csv(csv, 
    skiprows=4, decimal=',', index_col=0, usecols=[0,1], 
    dayfirst=True, parse_dates=True, names=['date', 'val'], 
    na_values='[MISSING]', sep='\s*\;\s*')
             val
date
1939-10-01   1.1
1939-12-01   NaN
1940-01-01  10.0