我有一个csv文件有错误。有些行有4个分隔符(;(,而大多数行有5个分隔符。我有时有4个分隔符的原因是因为有时第二列缺失。
示例:
var1;var2;var3;var4;var5
1;10;john;40;56
2;mary;34;78
3;90.0;smith;52;45
如果我导入csv文件:
import pandas as pd
df=pd.read_csv('myfile.csv', sep=";")
我获得数据帧:
var1 var2 var3 var4 var5
1 10 john 40 56
2 mary 34 78
3 90.0 smith 52 45
我想要:
var1 var2 var3 var4 var5
1 10 john 40 56
2 NaN mary 34 78
3 90.0 smith 52 45
也许我可以把数据帧分成两部分(一部分是5";",另一部分是4";"(,并在最后附加。我从代码开始:
import csv
with open('myfile.csv',newline='') as fin, open('output.csv','w',newline='') as fout:
reader = csv.reader(fin)
writer = csv.writer(fout)
for row in reader:
if len(row) > 4:
writer.writerow(row)
但是我得到了错误:";行包含NUL";。
解决方法可以是shift
数据帧的一部分:
# read with shifted columns
df = pd.read_csv('myfile.csv', sep=';')
# identify rows with incorrect data
m = df['var5'].isna()
# define columns to correct (second to last)
cols = df.columns[1:]
# correct the invalid rows
df.loc[m, cols] = df.loc[m, cols].shift(axis=1)
输出:
var1 var2 var3 var4 var5
0 1 10 john 40 56.0
1 2 None mary 34 78.0
2 3 90.0 smith 52 45.0
如果需要,可以按照以下方式预处理file.csv
插入;
,让file.csv
内容为
var1;var2;var3;var4;var5
1;10;john;40;56
2;mary;34;78
3;90.0;smith;52;45
然后
with open("file.csv","r") as fin, open("file_fixed.csv","w") as fout:
for line in fin:
if line.count(';') == 3:
line = line.replace(';',';;',1)
fout.write(line)
确实创建了具有以下内容的file_fixed.csv
var1;var2;var3;var4;var5
1;10;john;40;56
2;;mary;34;78
3;90.0;smith;52;45
说明:如果线路有3个;
,则使用;;
替换;
一次(即使用;;
仅替换第一个;
(
另一种可能的解决方案,基于numpy.roll
和pandas.DataFrame.apply
:
df = pd.read_csv('myfile.csv', sep=';')
df.iloc[:, 1:] = df.iloc[:, 1:].apply(
lambda x: np.roll(x, 1) if np.isnan(x[3]) else x, axis=1)
输出:
var1 var2 var3 var4 var5
0 1 10 john 40 56.0
1 2 NaN mary 34 78.0
2 3 90.0 smith 52 45.0
关于您最终遇到的特定错误,通过打开"output.csv",您会发现它不包含任何内容,这就是为什么当您尝试打开它时会抛出错误(我想是通过使用pd.read_csv?(。
如果你在阅读循环中添加一行print
,你会注意到每一行都是一个字符串的1元素列表,你的值用分号分隔,而不是5元素的值列表。
这是因为你必须告诉你的阅读器方法你使用分号作为分隔符(而不是默认的,
(。因此,如果您为读取器和写入器指定分隔符;
,它将创建一个新的csv文件,其中只有没有缺失值的行:
import csv
with open('myfile.csv',newline='') as fin, open('output.csv','w',newline='') as fout:
reader = csv.reader(fin, delimiter = ';')
writer = csv.writer(fout, delimiter = ';')
for row in reader:
print(row)
if len(row) > 4:
writer.writerow(row)
希望这能帮助