将 csv 文件加载到 numpy 并按名称访问列

Posted

技术标签:

【中文标题】将 csv 文件加载到 numpy 并按名称访问列【英文标题】:load csv file to numpy and access columns by name 【发布时间】:2014-07-31 09:10:24 【问题描述】:

我有一个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,并且我还想从给定的column name 访问column vectors。如果我使用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 列的数组,但无法使用 column 名称访问 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 中是否有任何方法可以同时满足这两个要求 (access columns by coluumn name like np.genfromtext and have a matrix like np.loadtxt)?

【问题讨论】:

【参考方案1】:

单独使用 numpy,您显示的选项是您唯一的选择。要么使用形状为 (3,7) 的同质 dtype 的 ndarray,要么使用(可能)异构 dtype 和形状 (3,) 的结构化数组。

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

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 替代方案是使用 dict 将列名映射到索引:

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 矩阵(将用于进一步的矩阵操作)而不是数组。 Numpy 矩阵没有标签可访问的列。 我想知道这种情况下的时间效率。起初,我想在 loadtxtgenfromtext 中加载 csv 文件并访问 numpy 数组和列名,但这需要太多时间。似乎这个解决方案也相似,只是将 genfromtext 替换为 csv.reader (具有更多代码行)。我的 csv 文件是 5MB,所以我想要一个可以同时做这两个的库。 无论文件多大,时间效率(使用 csv 模块)都不错,因为只读取第一行。不过,我认为Warren Weckesser's solution 更好。【参考方案2】:

因为您的数据是同质的——所有元素都是浮点值——你可以创建一个由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])

【讨论】:

以上是关于将 csv 文件加载到 numpy 并按名称访问列的主要内容,如果未能解决你的问题,请参考以下文章

Numpy - 将具有第一行的csv作为名称立即加载到结构化数组中?

如何将 CSV 文件中的数据加载到 numpy 数组中[重复]

将 CSV 文件加载到 NumPy memmap 数组使用太多内存

将熊猫数据框保存到csv时如何保留numpy数组

将熊猫数据框保存到csv时如何保留numpy数组

如何将csv文件转换为numpy数组格式?