【问题标题】:How to handle inconsistent columns of CSV如何处理不一致的 CSV 列
【发布时间】:2021-02-24 11:47:56
【问题描述】:

我的 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]

【问题讨论】:

  • 扫描文件,确定最大字段数(5,即您的示例中的2个),通过在最顶部的行中添加field4和field5来修改文件,然后导入。之后,您可以通过多种方式之一组合列stackoverflow.com/questions/52276658/…

标签: python pandas csv


【解决方案1】:

这是我们计算列中分隔符数量并基于此构造数据框的一般方法:

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]

【讨论】:

    【解决方案2】:

    您可以将整个文件读取为一列,然后使用 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]
    

    【讨论】:

      【解决方案3】:

      不幸的是,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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-09
        • 2020-08-26
        • 1970-01-01
        • 2020-04-30
        • 1970-01-01
        • 1970-01-01
        • 2012-05-12
        相关资源
        最近更新 更多