由于额外的列值,尝试使用 pandas Python 读取 csv 时出错
Posted
技术标签:
【中文标题】由于额外的列值,尝试使用 pandas Python 读取 csv 时出错【英文标题】:Getting error while trying to read csv using pandas Python due to extra column values 【发布时间】:2019-10-06 18:59:06 【问题描述】:这是我想要摆脱的场景: 我正在尝试阅读以下类型的 csv:
para1,para2,para3,para4
1,2,3,4,
1,2,3,4,5,
1,2,3,4,
2,3,4,5,6,7,8,9,0,
我正在使用以下命令并收到以下错误:
>>> import pandas as pd
>>> df =pd.read_csv("test.csv")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python35\lib\site-packages\pandas\io\parsers.py", line 702, in parser_f
return _read(filepath_or_buffer, kwds)
File "C:\Python35\lib\site-packages\pandas\io\parsers.py", line 435, in _read
data = parser.read(nrows)
File "C:\Python35\lib\site-packages\pandas\io\parsers.py", line 1139, in read
ret = self._engine.read(nrows)
File "C:\Python35\lib\site-packages\pandas\io\parsers.py", line 1995, in read
data = self._reader.read(nrows)
File "pandas\_libs\parsers.pyx", line 899, in pandas._libs.parsers.TextReader.read
File "pandas\_libs\parsers.pyx", line 914, in pandas._libs.parsers.TextReader._read_low_memory
File "pandas\_libs\parsers.pyx", line 968, in pandas._libs.parsers.TextReader._read_rows
File "pandas\_libs\parsers.pyx", line 955, in pandas._libs.parsers.TextReader._tokenize_rows
File "pandas\_libs\parsers.pyx", line 2172, in pandas._libs.parsers.raise_parser_error
pandas.errors.ParserError: Error tokenizing data. C error: Expected 4 fields in line 3, saw 5
我试图搜索问题并在 SO:Python Pandas Error tokenizing data 上找到了这个帖子
所以,我试过了。这不是我所期待的。它正在截断值。
>>> df =pd.read_csv("test.csv",error_bad_lines=False)
b'Skipping line 3: expected 4 fields, saw 5\nSkipping line 5: expected 4 fields, saw 9\n'
>>> df
para1 para2 para3 para4
0 1 2 3 4
1 1 2 3 4
我想要的是这样的: 如果有额外的值,则将列作为在额外中找到的最高列的整数值。然后将其余值设为零(0)直到最后一列并读取 csv。
我期待的输出是这样的:
>>> df =pd.read_csv("test.csv")
>>> df
para1 para2 para3 para4 0 1 2 3 4
0 1 2 3 4 NaN NaN NaN NaN NaN
1 1 2 3 4 5.0 NaN NaN NaN NaN
2 1 2 3 4 NaN NaN NaN NaN NaN
3 2 3 4 5 6.0 7.0 8.0 9.0 0.0
>>> df = df.fillna(0)
>>> df
para1 para2 para3 para4 0 1 2 3 4
0 1 2 3 4 0.0 0.0 0.0 0.0 0.0
1 1 2 3 4 5.0 0.0 0.0 0.0 0.0
2 1 2 3 4 0.0 0.0 0.0 0.0 0.0
3 2 3 4 5 6.0 7.0 8.0 9.0 0.0
但是请注意,我不想照顾专栏。相反,程序必须自动理解并制作上面给出的列标题。
其次,请尽量避免建议我写标题。因为可能有很多列我可能无法编写标题,而只是保持原样。所以缺少的列标题将是如上所述的数字整数。有人有任何查询的解决方案,请告诉我?
【问题讨论】:
不是有效的解决方案,但可以工作..您可以先读取没有标题的 csv 文件,然后第二次您可以只读取标题 @AkshayNevrekar 可能是,但没有可用的熊猫解决方案吗? 以上只是pandas解决方案......也许你的意思是问是否可以通过调整read_csv
中的一些参数来完成,至少我不知道。
@AkshayNevrekar 是的,类似
我已经编辑了示例,因为我忘了在那里添加额外的逗号
【参考方案1】:
我不确定是否有更简洁的方法来执行此操作,但我对其进行了测试,并且仅使用 pandas 即可:
df = pd.read_csv('test.csv', header=None, sep='\n')
df= df[0].str.split(',', expand=True)
new_header = df.iloc[0].fillna(df.columns.to_series())
df = df[1:]
df.columns = new_header
【讨论】:
假设1,"2,2,2",3
是 5 列,而不是像真正的 CSV 解析器那样的 3 列
我同意,如果您的数据结构需要更好的解决方案,它将无法工作,但它适用于他发布的 OP 的问题数据。【参考方案2】:
好的,这意味着您必须解析文件直到其结束才能获得实际的列数,因为pandas.read_csv
没有针对该要求的规定。
如果高性能不是问题 (*),一个简单的方法是依靠良好的旧 csv 模块并根据需要动态添加列:
with open('test.csv') as fd:
rd = csv.reader(fd)
header = next(rd) # initialize column names from first row
next_key = 0 # additional columns will start at '0'
data = k: list() for k in header # initialize data list per column
for row in rd:
while len(row) > len(header): # add eventual new columns
header.append(str(next_key))
data[header[-1]] = [np.nan] * len(data[header[0]])
next_key += 1 # increase next column name
# eventually extend the row up to the header size
row.extend([np.nan] * (len(header) - len(row)))
# and add data to the column lists
for i, k in enumerate(header): data[k].append(row[i])
# data is now in a dict format, suitable to feed DataFrame
df = pd.DataFrame(data)
(*) 上面的代码效率不是很高,因为它一次将元素添加到列表中。这对于 pandas DataFrame 来说是很糟糕的,即使对于 Python 列表也不是很好。可以通过在 numpy.ndarray
中分配束来改进它,但代价是增加了复杂性。
【讨论】:
这可能会有所帮助。但是If performance is not a concern (*)
是什么意思?显然,性能是一个值得考虑的问题。
@JafferWilson:我的意思是这段代码并不像read_csv
的C 解析器那样高效。在相当新的计算机上,它应该能够处理高达几兆字节的 csv 文件。如果您打算处理许多几 GB 的文件,则应该进行低级优化。
@JafferWilson: ...换一种说法,我的建议是你应该试一试,只有当性能不可接受时,才尝试使用 pre_allocation 来加快速度。
我一定会试一试的【参考方案3】:
尝试使用下面的代码,使用sep=' '
,然后使用iloc
获取第一列,然后简单地使用str.split
和expand=True
来创建一个新的数据框,然后使用fillna
替换NaN
s ,然后最后一行是用list
理解和list(range(...))
命名列。
所以你应该使用:
df = pd.read_csv("test.csv", sep=' ')
df2 = df.iloc[:, 0].str.replace(',$', '').str.split(',', expand=True).fillna(0)
dd = df.columns[0].split(',')
ff = [str(x) for x in range(len(df2.columns) - len(dd))]
df2.columns = dd + ff
print(df2)
【讨论】:
我如何确定是否添加list(range(5))
或list(range(10))
或其他任何内容?如果我有一个大数据集,我什至无法打开它并计算要添加多少。你能帮我解决这个问题吗?
@JafferWilson 再次编辑我的
@JafferWilson 很高兴再次提供帮助 :-)以上是关于由于额外的列值,尝试使用 pandas Python 读取 csv 时出错的主要内容,如果未能解决你的问题,请参考以下文章