如果每行包含不同数量的字段(数量很大),如何正确读取 csv 文件?

新手上路,请多包涵

我有一个来自亚马逊的文本文件,其中包含以下信息:

  #      user        item     time   rating     review text (the header is added by me for explanation, not in the text file
  disjiad123    TYh23hs9     13160032    5     I love this phone as it is easy to use
  hjf2329ccc    TGjsk123     14423321    3     Suck restaurant

如您所见,数据由空格分隔,每行中的列数不同。但是,文本内容也是如此。这是我试过的代码:

 pd.read_csv(filename, sep = " ", header = None, names = ["user","item","time","rating", "review"], usecols = ["user", "item", "rating"])#I'd like to skip the text review part

并出现这样的错误:

 ValueError: Passed header names mismatches usecols

当我试图阅读所有专栏时:

 pd.read_csv(filename, sep = " ", header = None)

这次的错误是:

 Error tokenizing data. C error: Expected 229 fields in line 3, saw 320

并且鉴于评论文本在很多行中都很长,因此在该 问题 中为每列添加标题名称的方法不起作用。

我想知道如果我想保留评论文本并分别跳过它们,如何读取 csv 文件。先感谢您!

编辑:

这个问题已经被 Martin Evans 完美解决了。但现在我正在玩另一个格式相似但不同的数据集。现在数据的顺序是相反的:

      # review text                          user        item     time   rating      (the header is added by me for explanation, not in the text file
   I love this phone as it is easy to used  isjiad123    TYh23hs9     13160032    5
  Suck restaurant                           hjf2329ccc    TGjsk123     14423321    3

你有什么想法正确阅读它吗?如有任何帮助,我们将不胜感激!

原文由 user5779223 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 743
2 个回答

正如建议的那样, DictReader 也可以按如下方式使用来创建行列表。然后可以将其作为框架导入熊猫:

 import pandas as pd
import csv

rows = []
csv_header = ['user', 'item', 'time', 'rating', 'review']
frame_header = ['user', 'item', 'rating', 'review']

with open('input.csv', 'rb') as f_input:
    for row in csv.DictReader(f_input, delimiter=' ', fieldnames=csv_header[:-1], restkey=csv_header[-1], skipinitialspace=True):
        try:
            rows.append([row['user'], row['item'], row['rating'], ' '.join(row['review'])])
        except KeyError, e:
            rows.append([row['user'], row['item'], row['rating'], ' '])

frame = pd.DataFrame(rows, columns=frame_header)
print frame

这将显示以下内容:

          user      item rating                                  review
0  disjiad123  TYh23hs9      5  I love this phone as it is easy to use
1  hjf2329ccc  TGjsk123      3                         Suck restaurant

如果评论出现在行的开头,那么一种方法是反向解析该行,如下所示:

 import pandas as pd
import csv

rows = []
frame_header = ['rating', 'time', 'item', 'user', 'review']

with open('input.csv', 'rb') as f_input:
    for row in f_input:
        cols = [col[::-1] for col in row[::-1][2:].split(' ') if len(col)]
        rows.append(cols[:4] + [' '.join(cols[4:][::-1])])

frame = pd.DataFrame(rows, columns=frame_header)
print frame

这将显示:

   rating      time      item        user  \
0      5  13160032  TYh23hs9   isjiad123
1      3  14423321  TGjsk123  hjf2329ccc

                                    review
0  I love this phone as it is easy to used
1                          Suck restaurant

row[::-1] 用于反转整行的文本, [2:] 跳过现在位于行首的行尾。每行然后按空格分开。列表理解然后重新反转每个拆分条目。最后 rows 通过采用固定的 5 列条目(现在在开头)附加到第一个。然后将剩余的条目用空格重新连接在一起并添加为最后一列。

这种方法的好处是它不依赖于您的输入数据是完全固定宽度的格式,而且您不必担心所使用的列宽是否会随时间变化。

原文由 Martin Evans 发布,翻译遵循 CC BY-SA 3.0 许可协议

看起来这是一个固定宽度的文件。 Pandas 供应 read_fwf 为了这个目的。以下代码为我正确读取文件。如果它不能完美工作,您可能想稍微调整一下宽度。

 pandas.read_fwf('test.fwf',
                 widths=[13, 12, 13, 5, 100],
                 names=['user', 'item', 'time', 'rating', 'review'])

如果列仍然与编辑后的版本一致(评分排在第一位),您只需添加正确的规范。像下面这样的指南有助于快速做到这一点:

 0        1         2         3         4         5         6         7         8
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
  I love this phone as it is easy to used  isjiad123    TYh23hs9     13160032    5
  Suck restaurant                          hjf2329ccc   TGjsk123     14423321    3

所以新命令变成:

 pandas.read_fwf('test.fwf',
                colspecs=[[0, 43], [44, 56], [57, 69], [70, 79], [80, 84]],
                names=['review', 'user', 'item', 'time', 'rating'])

原文由 chthonicdaemon 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题