如何处理CSV的不一致列



我的CSV数据是这样的:

ID;name;info
1;ABC;text1
2;DEF;text2;text3
3;GHI;text4;
4;JKL;text5;text6;text7

有3个命名列。附加的未命名列都与最后一个列(info)相关,并且这些附加列的数量是未知的。

使用df=pd.read_csv(filename, delimiter=";", dtype=object)返回一个不规则形状的"Error tokenizing data. C error..."

是否有可能将最后的列合并为一个包含列表的列,以实现下面的结果?

ID;name;info
1;ABC;[text1]
2;DEF;[text2, text3]
3;GHI;[text4]
4;JKL;[text5, text6, text7]

这是一种计算列中分隔符数量的一般方法,并以此为基础构造数据框架:

data = pd.read_csv("text.csv")
n_sep = data.columns[0].count(";")
headers = data.columns.str.split(";")[0]
data[headers] = data.iloc[:, 0].str.split(";", n=n_sep, expand=True)
data = data.iloc[:, 1:].assign(info=data['info'].str.split(";"))
ID name                   info
0  1  ABC                [text1]
1  2  DEF         [text2, text3]
2  3  GHI              [text4, ]
3  4  JKL  [text5, text6, text7]

您可以将整个文件作为一列读取,然后使用pd.Series.str.splitn(max_split)参数:

>>> df = pd.read_csv('sample.csv', header=None)
0
0             ID;name;info
1              1;ABC;text1
2        2;DEF;text2;text3
3             3;GHI;text4;
4  4;JKL;text5;text6;text7
>>> df = df[0].str.split(';', n=2, expand=True)
>>> df
0     1                  2
0  ID  name               info
1   1   ABC              text1
2   2   DEF        text2;text3
3   3   GHI             text4;
4   4   JKL  text5;text6;text7
>>> df.columns = df.loc[0].tolist()
>>> df = df.drop(0).reset_index(drop=True)
>>> df['info'] = df['info'].str.strip(';').str.split(';')
>> df
ID name                   info
0  1  ABC                [text1]
1  2  DEF         [text2, text3]
2  3  GHI                [text4]
3  4  JKL  [text5, text6, text7]

或者

>>> with open('sample.csv') as fh:
header = next(fh).strip().split(';')
df = pd.DataFrame([line.strip().split(';',2) for line in fh], columns=header)
>>> df['info'] = df['info'].str.strip(';').str.split(';')
>>> df
ID name                   info
0  1  ABC                [text1]
1  2  DEF         [text2, text3]
2  3  GHI                [text4]
3  4  JKL  [text5, text6, text7]

不幸的是,pd.read_csv期望文件中的字段数保持不变。但是标准的csv模块没有。所以你可以使用:

with open(filename) as fd:
rd = csv.reader(fd, delimiter=';')
fn = next(rd)  # extract the headers line
rd = csv.DictReader(fd, delimiter=';', fieldnames=fn[:-1], restkey=fn[-1])
df = pd.DataFrame((row for row in rd), columns = fn)

它给:

ID name                   info
0  1  ABC                [text1]
1  2  DEF         [text2, text3]
2  3  GHI              [text4, ]
3  4  JKL  [text5, text6, text7]

主要缺点是csv模块将所有内容保持为字符串,因此df.dtypes是:

ID      object
name    object
info    object
dtype: object

最新更新