将CSV文件加载到NumPy中,并按名称访问列

10

我有一个带有标题的csv文件,例如:

假设有这个test.csv文件:

"A","B","C","D","E","F","timestamp"
611.88243,9089.5601,5133.0,864.07514,1715.37476,765.22777,1.291111964948E12
611.88243,9089.5601,5133.0,864.07514,1715.37476,765.22777,1.291113113366E12
611.88243,9089.5601,5133.0,864.07514,1715.37476,765.22777,1.291120650486E12
我只想将它作为一个有3行7列的矩阵/ndarray加载,并且我还想从给定的列名访问列向量。如果我使用 genfromtxt(如下所示),我会得到一个有3行(每行一个)但没有列的 ndarray。
r = np.genfromtxt('test.csv',delimiter=',',dtype=None, names=True)
print r
print r.shape

[ (611.88243, 9089.5601000000006, 5133.0, 864.07514000000003, 1715.3747599999999, 765.22776999999996, 1291111964948.0)
 (611.88243, 9089.5601000000006, 5133.0, 864.07514000000003, 1715.3747599999999, 765.22776999999996, 1291113113366.0)
 (611.88243, 9089.5601000000006, 5133.0, 864.07514000000003, 1715.3747599999999, 765.22776999999996, 1291120650486.0)]
(3,)

我可以通过列名获取列向量,像这样:

print r['A']
  [ 611.88243  611.88243  611.88243]

如果我使用load.txt,那么我会得到一个有3行7列的数组,但是无法通过使用列名(如下所示)来访问columns

numpy.loadtxt(open("test.csv","rb"),delimiter=",",skiprows=1)

我理解

  [ [611.88243,9089.5601,5133.0,864.07514,1715.37476,765.22777,1.291111964948E12]
    [611.88243,9089.5601,5133.0,864.07514,1715.37476,765.22777,1.291113113366E12]
    [611.88243,9089.5601,5133.0,864.07514,1715.37476,765.22777,1.291120650486E12] ]

Python中,有没有一种方法可以同时实现这两个要求(像np.genfromtext一样按列名称访问列,并像np.loadtxt一样拥有矩阵)?

2个回答

10

只使用numpy,你所展示的选项是唯一的选择。要么使用形状为(3,7)的同种数据类型的ndarray,要么使用(可能)异种数据类型和形状为(3,)的结构化数组。

如果你真的想要一个带有标签列和形状为(3,7)的数据结构(以及许多其他好处),你可以使用pandas DataFrame:

In [67]: import pandas as pd
In [68]: df = pd.read_csv('data'); df
Out[68]: 
           A          B     C          D           E          F     timestamp
0  611.88243  9089.5601  5133  864.07514  1715.37476  765.22777  1.291112e+12
1  611.88243  9089.5601  5133  864.07514  1715.37476  765.22777  1.291113e+12
2  611.88243  9089.5601  5133  864.07514  1715.37476  765.22777  1.291121e+12    

In [70]: df['A']
Out[70]: 
0    611.88243
1    611.88243
2    611.88243
Name: A, dtype: float64

In [71]: df.shape
Out[71]: (3, 7)

一个纯粹的NumPy / Python替代方法是使用字典将列名映射到索引:

import numpy as np
import csv
with open(filename) as f:
    reader = csv.reader(f)
    columns = next(reader)
    colmap = dict(zip(columns, range(len(columns))))

arr = np.matrix(np.loadtxt(filename, delimiter=",", skiprows=1))
print(arr[:, colmap['A']])
产生收益
[[ 611.88243]
 [ 611.88243]
 [ 611.88243]]

这样,arr就是一个NumPy矩阵,可以使用语法按标签访问列。

arr[:, colmap[column_name]]

我想要一个numpy矩阵(将用于进一步的矩阵操作),而不是数组。 - user2481422
Numpy矩阵没有可通过标签访问的列。 - unutbu
我在想这种情况下的时间效率。起初,我考虑使用loadtxtgenfromtext同时加载csv文件并访问numpy数组和列名,但是这需要太多时间。看起来这个解决方案也类似,只是用csv.reader替换了genfromtext(代码行更多)。我的csv文件大小为5MB,所以我希望有一个库可以同时完成两者。 - user2481422
使用csv模块的时间效率不错,无论文件有多大,因为只读取第一行。然而,我认为Warren Weckesser的解决方案更好。 - unutbu

3

因为您的数据是同质的--所有元素都是浮点数值--所以您可以创建一个由 genfromtxt 返回的数据视图,该视图是一个二维数组。例如,

In [42]: r = np.genfromtxt("test.csv", delimiter=',', names=True)

创建一个 numpy 数组作为 r 的“视图”。这是一个常规的 numpy 数组,但是它使用 r 中的数据创建:
In [43]: a = r.view(np.float64).reshape(len(r), -1)

In [44]: a.shape
Out[44]: (3, 7)

In [45]: a[:, 0]
Out[45]: array([ 611.88243,  611.88243,  611.88243])

In [46]: r['A']
Out[46]: array([ 611.88243,  611.88243,  611.88243])

ra 指向同一块内存:

In [47]: a[0, 0] = -1

In [48]: r['A']
Out[48]: array([  -1.     ,  611.88243,  611.88243])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接