关于python:Pandas dataframe read_csv上的错误数据
- 2025-03-13 09:19:00
- admin 原创
- 86
问题描述:
我想读取一个非常大的 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
解决方案 1:
传递error_bad_lines=False
以跳过错误的行:
error_bad_lines:布尔值,默认为 True 行包含太多字段(例如 csv 行包含太多逗号)默认情况下会导致引发异常,并且不会返回任何 DataFrame。如果为 False,则这些“坏行”将从返回的 DataFrame 中删除。(仅适用于 C 解析器)
解决方案 2:
先前的答案建议使用error_bad_lines=False
和warn_bad_lines=True
,但现在两者在熊猫中都被弃用了。
相反,使用on_bad_lines='warn'
可以达到相同的效果,跳过坏的数据行。当遇到坏行时,它会发出警告并跳过该行。
dataframe = pd.read_csv(filePath, index_col=False, encoding='iso-8859-1', nrows=1000,
on_bad_lines='warn')
其他可接受的on_bad_lines
值包括
'error'
在错误的行上引发异常'skip'
它将跳过任何坏行
解决方案 3:
要获取有关导致错误的行的信息,请尝试使用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
Skipping line 4: expected 4 fields, saw 30...'
如果您想保存警告消息(即进行进一步处理),那么您也可以将其保存到文件中(使用contextlib
):
import contextlib
with open(r'D:Templog.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)
解决方案 4:
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
以下 lambda 函数只是忽略了错误行中的最后一列(正如上面原始问题陈述所期望的那样):
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
在每个坏行上被调用,并且具有函数签名(bad_line: list[str]) -> list[str] | None
。如果函数返回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
函数定义
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
解决方案 5:
这是我解决这些问题的方法,虽然很慢但效果很好,简单地说就是将 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")
扫码咨询,免费领取项目管理大礼包!