[英]Pandas dataframe read_csv on bad data
我想阅读一个非常大的 csv(无法在 excel 中打开并轻松编辑),但在第 100,000 行左右,有一行有一个额外的列导致程序崩溃。 这一行是错误的,所以我需要一种方法来忽略它是一个额外的列的事实。 大约有 50 列,因此对标题进行硬编码并使用名称或 usecols 是不可取的。 我也可能会在其他 csv 中遇到这个问题并想要一个通用的解决方案。 不幸的是,我在 read_csv 中找不到任何东西。 代码很简单:
def loadCSV(filePath):
dataframe = pd.read_csv(filePath, index_col=False, encoding='iso-8859-1', nrows=1000)
datakeys = dataframe.keys();
return dataframe, datakeys
通过error_bad_lines=False
跳过错误的行:
error_bad_lines : 布尔值,默认情况下具有太多字段的 True 行(例如,带有太多逗号的 csv 行)将默认导致引发异常,并且不会返回任何 DataFrame。 如果为 False,那么这些“坏行”将从返回的 DataFrame 中删除。 (仅对 C 解析器有效)
要获取有关导致错误的行的信息,请尝试使用error_bad_lines=False
和warn_bad_lines=True
:
dataframe = pd.read_csv(filePath, index_col=False, encoding='iso-8859-1', nrows=1000,
warn_bad_lines=True, error_bad_lines=False)
error_bad_lines=False
跳过引起错误的行, warn_bad_lines=True
打印错误详细信息和行号,如下所示:
'Skipping line 3: expected 4 fields, saw 3401\nSkipping line 4: expected 4 fields, saw 30...'
如果您想保存警告消息(即用于进一步处理),那么您也可以将其保存到文件中(使用contextlib
):
import contextlib
with open(r'D:\Temp\log.txt', 'w') as log:
with contextlib.redirect_stderr(log):
dataframe = pd.read_csv(filePath, index_col=False, encoding='iso-8859-1',
warn_bad_lines=True, error_bad_lines=False)
1.4.0 的新功能
从pandas
1.4.0
开始, read_csv()
通过允许将可调用对象分配给on_bad_lines=
,提供允许您以更优雅和智能的方式处理这些情况的功能。
例如,假设CSV
可能导致错误数据错误: Expected 4 fields in line 3, saw 5
:
C1,C2,C3,C4
10,11,12,13
25,26,27,28,garbage
80,81,82,83
这个 function 只是忽略了坏行中的最后一列(正如上面原始问题陈述中所期望的那样):
df = pd.read_csv('your.csv', on_bad_lines=lambda x: x[:-1], engine='python')
df
C1 C2 C3 C4
0 10 11 12 13
1 25 26 27 28
2 80 81 82 83
on_bad_lines
可调用 function 在每个坏行上调用,并具有 function 签名(bad_line: list[str]) -> list[str] | None
(bad_line: list[str]) -> list[str] | None
。 如果 function 返回None
,坏行将被忽略。 如您所见, engine='python'
是必需的。
这样做的好处在于,它为您想要编写任何细粒度的逻辑来解决问题打开了大门。
例如,假设您想从行的开头或结尾删除错误数据,如果开头和结尾都有错误数据,则只需忽略该行,您可以:
CSV
C1,C2,C3,C4
10,11,12,13
20,21,22,23,garbage
60,61,62,63
trash,80,81,82,83
trash,90,91,82,garbage
Function 定义
def line_fixer(x):
if not x[0].isnumeric() and x[-1].isnumeric():
return x[1:]
if not x[-1].isnumeric() and x[0].isnumeric():
return x[:-1]
return None
结果
df = pd.read_csv('your.csv', on_bad_lines=line_fixer, engine='python')
df
C1 C2 C3 C4
0 10 11 12 13
1 20 21 22 23
2 60 61 62 63
3 80 81 82 83
对于像我这样在原版发布后几年遇到的人,其他答案建议使用error_bad_lines=False
和warn_bad_lines=True
,但两者都在熊猫中被弃用。 而是使用on_bad_lines = 'warn'
来实现相同的效果来跳过坏数据线。
on_bad_lines = 'warn'
遇到坏行时会发出警告并跳过该行。
on_bad_lines
的其他可接受的值是
这是我解决这些问题的方法,它很慢但效果很好,简单地说只需将 CSV 文件读取为 txt 文件,然后遍历每一行。 如果“,”逗号小于它应该只是跳过该行。 最终安全的正确线路。
def bad_lines(path):
import itertools
num_columns = []
lines = ""
for i in range(10,50,5):
content = open(path).readlines(i)[0]
if (content.count("'") == 0) and (content.count('"') == 0):
num_columns.append(content.count(","))
if len(set(num_columns)) == 1:
for line in itertools.islice(open(path), 0, None):
if line.count(",") >= num_columns[0]:
lines = lines + line
text_file = open("temp.txt", "w")
n = text_file.write(lines)
text_file.close()
return("temp.txt")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.