使用 pd.read_csv(不规则分隔符,自定义 NA)读取 borked CSV 文件
reading borked CSV files with pd.read_csv (irregular delimiters, custom NA)
我正在读取 CSV 数据用作 pandas 数据框,但 CSV 似乎没有遵循任何理智的约定(除了使用 ;
作为分隔符,每个人都应该.. .).似乎唯一的目标是让它们在文本编辑器中打开时看起来 好
下面是一些示例(设置为变量,以便它们可用于 reader 示例):
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
,这还将所有 val
变成字符串,从而忽略小数点逗号并保留尾随空格。 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(无论如何我必须读取 header(实际文件中的 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 兆字节,这并不是一个真正的最佳解决方案,所以我想解决导入中的 NÄ
问题。
您的 sep
是 mis-specified(它以 s*
而不是 \s*
结尾,这意味着它正在寻找 0 到无限 s
个字符) .这就是为什么您只捕获 ;
之后的前导空格而不捕获尾随空格的原因。顺便说一下,这也干扰了 (1),因为您试图替换 'NÄ'
但值是 ' NÄ'
。请改用 sep='\s*\;\s*'
。
你将来可以做的一件事是自己打印出有问题的值,以确保它们包含他们认为你包含的内容,例如ts.iloc[1].val
.
此外,如果 NaN
值在 unicode 中是一个问题,您可以在解析之前将其删除:
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
我正在读取 CSV 数据用作 pandas 数据框,但 CSV 似乎没有遵循任何理智的约定(除了使用 ;
作为分隔符,每个人都应该.. .).似乎唯一的目标是让它们在文本编辑器中打开时看起来 好
下面是一些示例(设置为变量,以便它们可用于 reader 示例):
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
,这还将所有 val
变成字符串,从而忽略小数点逗号并保留尾随空格。 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(无论如何我必须读取 header(实际文件中的 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 兆字节,这并不是一个真正的最佳解决方案,所以我想解决导入中的 NÄ
问题。
您的 sep
是 mis-specified(它以 s*
而不是 \s*
结尾,这意味着它正在寻找 0 到无限 s
个字符) .这就是为什么您只捕获 ;
之后的前导空格而不捕获尾随空格的原因。顺便说一下,这也干扰了 (1),因为您试图替换 'NÄ'
但值是 ' NÄ'
。请改用 sep='\s*\;\s*'
。
你将来可以做的一件事是自己打印出有问题的值,以确保它们包含他们认为你包含的内容,例如ts.iloc[1].val
.
此外,如果 NaN
值在 unicode 中是一个问题,您可以在解析之前将其删除:
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