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

我正在读取 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

andts.index是一个很好的DatetimeIndexandtype(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Äas 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Ä')


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


那么我如何读取这些无聊的文件呢?


我当前使用的解决方法是使用纯Python读取CSV(无论如何我都必须读取标题(实际文件中的40行))并将其写入正确的CSV,以便用pandas读取:

但是对于几千个 CSV 文件,大小达到一兆字节,这并不是一个真正的最佳解决方案,所以我想NÄ在导入中解决这个问题。


拉莫斯之舞
浏览 192回答 1
1回答

狐的传说

您的sep指定错误(它s*以 而不是 结尾\s*,这意味着它正在寻找 0 到无限个s字符之间)。这就是为什么您只捕获前导空格而不捕获 后的尾随空格;。顺便说一句,这也干扰了 (1),因为您试图替换'NÄ'但值为'   NÄ'。sep='\s*\;\s*'代替使用。您将来可以做的一件事是自己打印出有问题的值,以确保它们包含他们认为您包含的内容,例如ts.iloc[1].val。另外,如果NaNunicode 中的值有问题,您可以在解析之前将其剥离: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*')...这会给...             valdate1939-10-01   1.11939-12-01   NaN1940-01-01  10.0
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python