使用pd.read_csv读取无效的CSV文件不规则分隔符,自定义NA

问题描述

我正在读取CSV数据用作熊猫数据框,但是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(简单)和一堆元数据(skiprorow,也很简单)。

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...仍然可以正常工作,但是打破了val列并将其转换为字符串。但是当我将其更改为

ts = pd.read_csv(io.StringIO(ex2),'val'],na_values='NÄ')

使用na_values,整个操作失败。 print(ts)

                val
date
1939-10-01      1,1
1939-12-01     NÄ
1940-01-01    10

它不仅不接受作为NaN,还将所有val转换为字符串,因此忽略了小数逗号并保留了尾随空格。 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),sep='\s*[;]s*',na_values='NÄ')

给出了一个貌似不错的print(ts)

               val
date
1939-10-01     1.1
1939-12-01      NÄ
1940-01-01      10

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

那我该如何读取这些异常文件

我当前使用的解决方法是使用纯python读取CSV文件(无论如何,我必须读取标题(实际文件中为40行)),然后将其写到适当的CSV文件中,以便使用熊猫:

'   1.1'

但是对于数千个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',parse_dates=True) ts.val = ts.val.astype(float) 问题。

解决方法

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

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

此外,如果使用统一代码的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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...