在Python中使用scipy/numpy解析字母数字CSV的可靠方法

3 投票
4 回答
1829 浏览
提问于 2025-04-15 23:36

我一直在寻找一种好的、灵活的方法来解析Python中的CSV文件,但标准的选项似乎都不太合适。我有点想自己写一个,但我觉得结合numpy/scipy和csv模块的某些功能就能满足我的需求,所以我不想重复造轮子。

我希望能有一些标准功能,比如可以指定分隔符、是否有表头、跳过多少行、注释的分隔符、忽略哪些列等等。我最缺少的一个功能是能够以一种优雅的方式解析CSV文件,同时处理字符串数据和数字数据。我的很多CSV文件中有些列包含字符串(长度不一定相同)和数字数据。我希望能对这些数字数据使用numpy数组的功能,同时也能访问字符串。例如,假设我的文件看起来是这样的(想象一下列是用制表符分隔的):

# my file
name  favorite_integer  favorite_float1  favorite_float2  short_description
johnny  5  60.2  0.52  johnny likes fruitflies
bob 1  17.52  0.001  bob, bobby, robert

data = loadcsv('myfile.csv', delimiter='\t', parse_header=True, comment='#')

我希望能以两种方式访问数据:

  1. 作为一个值的矩阵:对我来说,获取一个numpy.array很重要,这样我可以轻松地转置并访问数字列。在这种情况下,我想做类似这样的事情:

    floats_and_ints = data.matrix

    floats_and_ints[:, 0] # 访问整数

    floats_and_ints[:, 1:3] # 访问一些浮点数 transpose(floats_and_ints) # 等等..

  2. 作为一个类似字典的对象,我不需要知道表头的顺序:我也希望能按表头的顺序访问数据。例如,我想这样做:

    data['favorite_float1'] # 获取表头为"favorite_float1"的列的所有值

    data['name'] # 获取所有行的名字

我不想知道favorite_float1是表格中的第二列,因为这可能会改变。

对我来说,能够遍历行并按名称访问字段也很重要。例如:

for row in data:
  # print names and favorite integers of all 
  print "Name: ", row["name"], row["favorite_int"]

(1)中的表示方式暗示了numpy.array,但据我所知,这种方式对字符串处理得不好,需要我提前指定数据类型和表头标签。

(2)中的表示方式暗示了字典列表,这也是我一直在使用的。然而,这对于有两个字符串字段而其他列都是数字的CSV文件来说,真的很糟糕。对于数字值,你确实希望能够访问矩阵表示,并将其作为numpy.array进行操作。

有没有一种结合csv/numpy/scipy功能的方式,可以兼顾这两种灵活性?对此的任何建议都将非常感激。

总之,主要功能有:

  1. 标准的指定分隔符、跳过的行数、忽略的列等的能力。
  2. 能够获取数据的numpy.array/矩阵表示,以便可以操作数字值。
  3. 能够按表头名称提取列和行(如上例所示)。

4 个回答

0

numpy.genfromtxt() 是一个用来从文本文件中读取数据的函数。它可以处理各种格式的数据,比如数字、字符串等。这个函数特别适合处理那些有缺失值的数据,因为它可以自动识别并处理这些缺失的部分。

使用这个函数时,你只需要告诉它文件的路径,数据的分隔符(比如逗号、空格等),以及你想要读取的数据类型。这样,numpy就会把文件里的数据读进来,变成一个可以在程序中使用的数组。

总之,numpy.genfromtxt() 是一个非常方便的工具,可以帮助你轻松地从文本文件中获取数据,特别是当数据格式不太规则或者有缺失值的时候。

2

matplotlib.mlab.csv2rec 这个函数会返回一个 numpyrecarray,这意味着你可以对这个数据做很多 numpy 数组能做的事情。每一行数据都是 record 类型的实例,你可以像用元组一样来访问它们,但它们也有自动命名的属性,这些属性对应你数据中的列名:

rows = matplotlib.mlab.csv2rec('data.csv')
row = rows[0]

print row[0]
print row.name
print row['name']

csv2rec 还能够理解“带引号的字符串”,这点不同于 numpy.genfromtext

总的来说,我觉得 csv2rec 结合了 csv.readernumpy.genfromtext 的一些最佳功能。

4

看看这个pandas,它是建立在numpy之上的。这里有一个简单的例子:

In [7]: df = pd.read_csv('data.csv', sep='\t', index_col='name')
In [8]: df
Out[8]: 
        favorite_integer  favorite_float1  favorite_float2        short_description
name                                                                               
johnny                 5            60.20            0.520  johnny likes fruitflies
bob                    1            17.52            0.001       bob, bobby, robert
In [9]: df.describe()
Out[9]: 
       favorite_integer  favorite_float1  favorite_float2
count          2.000000         2.000000         2.000000
mean           3.000000        38.860000         0.260500
std            2.828427        30.179317         0.366988
min            1.000000        17.520000         0.001000
25%            2.000000        28.190000         0.130750
50%            3.000000        38.860000         0.260500
75%            4.000000        49.530000         0.390250
max            5.000000        60.200000         0.520000
In [13]: df.ix['johnny', 'favorite_integer']
Out[13]: 5
In [15]: df['favorite_float1'] # or attribute: df.favorite_float1
Out[15]: 
name
johnny    60.20
bob       17.52
Name: favorite_float1
In [16]: df['mean_favorite'] = df.mean(axis=1)
In [17]: df.ix[:, 3:]
Out[17]: 
              short_description  mean_favorite
name                                          
johnny  johnny likes fruitflies      21.906667
bob          bob, bobby, robert       6.173667

撰写回答