将制表符分隔的 csv 读入具有不同数据类型的 numpy 数组
Posted
技术标签:
【中文标题】将制表符分隔的 csv 读入具有不同数据类型的 numpy 数组【英文标题】:Reading tab delimited csv into numpy array with different data types 【发布时间】:2017-03-04 17:05:06 【问题描述】:我有一个制表符分隔的 csv 数据集,如下所示:
1 2 3 4 5 6 [0, 1, 2, 3, 4, 5]
3 1 2 6 4 5 [2, 0, 1, 5, 3, 4]
7 8 9 10 11 6 [0, 1, 2, 3, 4, 5]
10 11 9 8 7 6 [3, 4, 2, 1, 0, 5]
12 13 4 14 15 6 [0, 1, 2, 3, 4, 5]
13 4 14 12 15 6 [1, 2, 3, 0, 4, 5]
16 17 18 19 20 6 [0, 1, 2, 3, 4, 5]
6 18 20 17 16 19 [5, 2, 4, 1, 0, 3]
7 21 22 23 24 6 [0, 1, 2, 3, 4, 5]
23 6 21 7 22 24 [3, 5, 1, 0, 2, 4]
25 7 21 22 23 6 [0, 1, 2, 3, 4, 5]
6 21 7 22 25 23 [5, 2, 1, 3, 0, 4]
16 26 3 27 28 6 [0, 1, 2, 3, 4, 5]
26 6 27 3 28 16 [1, 5, 3, 2, 4, 0]
7 29 24 30 31 6 [0, 1, 2, 3, 4, 5]
30 24 6 7 29 31 [3, 2, 5, 0, 1, 4]
32 33 13 34 35 36 [0, 1, 2, 3, 4, 5]
34 32 36 35 13 33 [3, 0, 5, 4, 2, 1]
7 37 38 39 40 6 [0, 1, 2, 3, 4, 5]
39 38 40 6 37 7 [3, 2, 4, 5, 1, 0]
7 41 42 43 44 6 [0, 1, 2, 3, 4, 5]
41 6 44 43 42 7 [1, 5, 4, 3, 2, 0]
7 45 46 47 48 6 [0, 1, 2, 3, 4, 5]
6 47 45 7 46 48 [5, 3, 1, 0, 2, 4]
49 2 50 51 52 6 [0, 1, 2, 3, 4, 5]
当我想将这样的 csv 文件导入 numpy 数组时,如下所示;
dataset = numpy.loadtxt('dataset/demo_dataset.csv', delimiter='\t', dtype='str')
我获得了一个具有(25,)
形状的 numpy 数组。
我想将此 csv 文件导入两个 numpy 数组,分别称为 X 和 Y。
X 将包括前 6 列,Y 将包括最后一列作为列表值,而不是 str。
我该如何管理它?
【问题讨论】:
将 6 列加载为整数,最后一列加载为字符串很容易。dtype=None
应该这样做,或者更精致的自定义 dtype。但是[]
字符串需要特殊处理,在genfromtxt
之前或之后。
【参考方案1】:
我设法通过自定义方法实现了这一点:
import numpy
with open('dataset/demo_dataset.csv', 'r') as fin:
lines = fin.readlines()
# remove '\n' characters
clean_lines = [l.strip('\n') for l in lines]
# split on tab so that we get lists from strings
A = [cl.split('\t') for cl in clean_lines]
# get lists of ints instead of lists of strings
X = [map(int, row[0:6]) for row in A]
# last column in Y
Y = [row[6] for row in A]
# convert string to int values
for i in xrange(len(Y)):
Y[i] = map(int, Y[i].strip('[]').split(','))
【讨论】:
【参考方案2】:一些使用genfromtxt
的选项:
In [1047]: txt=b"""7\t8\t9\t10\t11\t6\t [0, 1, 2, 3, 4, 5]"""
In [1048]: txt=[txt,txt,txt]
In [1049]: txt
Out[1049]:
[b'7\t8\t9\t10\t11\t6\t [0, 1, 2, 3, 4, 5]',
b'7\t8\t9\t10\t11\t6\t [0, 1, 2, 3, 4, 5]',
b'7\t8\t9\t10\t11\t6\t [0, 1, 2, 3, 4, 5]']
加载为默认浮点数 - 最后一列是nan
:
In [1050]: np.genfromtxt(txt,delimiter='\t')
Out[1050]:
array([[ 7., 8., 9., 10., 11., 6., nan],
[ 7., 8., 9., 10., 11., 6., nan],
[ 7., 8., 9., 10., 11., 6., nan]])
作为字符串
In [1051]: np.genfromtxt(txt,delimiter='\t',dtype='str')
Out[1051]:
array([['7', '8', '9', '10', '11', '6', ' [0, 1, 2, 3, 4, 5]'],
['7', '8', '9', '10', '11', '6', ' [0, 1, 2, 3, 4, 5]'],
['7', '8', '9', '10', '11', '6', ' [0, 1, 2, 3, 4, 5]']],
dtype='<U19')
让它决定最合适的 - 结果是一个结构化数组,具有 int 字段和一个字符串字段。
In [1052]: np.genfromtxt(txt,delimiter='\t',dtype=None)
Out[1052]:
array([(7, 8, 9, 10, 11, 6, b' [0, 1, 2, 3, 4, 5]'),
(7, 8, 9, 10, 11, 6, b' [0, 1, 2, 3, 4, 5]'),
(7, 8, 9, 10, 11, 6, b' [0, 1, 2, 3, 4, 5]')],
dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4'), ('f3', '<i4'), ('f4', '<i4'), ('f5', '<i4'), ('f6', 'S19')])
In [1053]: _['f6']
Out[1053]:
array([b' [0, 1, 2, 3, 4, 5]', b' [0, 1, 2, 3, 4, 5]',
b' [0, 1, 2, 3, 4, 5]'],
dtype='|S19')
优化 dtype - 一个字段有 6 列,另一个是字符串:
In [1055]: np.genfromtxt(txt,delimiter='\t',dtype='6int,S20')
Out[1055]:
array([([7, 8, 9, 10, 11, 6], b' [0, 1, 2, 3, 4, 5]'),
([7, 8, 9, 10, 11, 6], b' [0, 1, 2, 3, 4, 5]'),
([7, 8, 9, 10, 11, 6], b' [0, 1, 2, 3, 4, 5]')],
dtype=[('f0', '<i4', (6,)), ('f1', 'S20')])
第一个字段是您想要的X
;最后一个字段中的字符串需要进一步处理(根据您的其他问题):
In [1060]: _['f0']
Out[1060]:
array([[ 7, 8, 9, 10, 11, 6],
[ 7, 8, 9, 10, 11, 6],
[ 7, 8, 9, 10, 11, 6]])
In [1061]: __['f1']
Out[1061]:
array([b' [0, 1, 2, 3, 4, 5]', b' [0, 1, 2, 3, 4, 5]',
b' [0, 1, 2, 3, 4, 5]'],
最后一个字段可以像 @chefarov
与 Y
变量一样转换。
想一想,我可以通过再次调用genfromtxt
来处理该字符串字段。我仍然需要删除[]
。
In [1101]: data=np.genfromtxt(txt,delimiter='\t',dtype='6int,S20')
In [1102]: data['f1']
Out[1102]:
array([b'[0, 1, 2, 3, 4, 5]', b'[0, 1, 2, 3, 4, 5]', b'[0, 1, 2, 3, 4, 5]'],
dtype='|S20')
In [1103]: np.genfromtxt([l.strip(b'[]') for l in data['f1']],delimiter=',',dtype=int)
Out[1103]:
array([[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]])
在其他情况下,我建议对行进行预处理以删除引号、括号和问题分隔符。 genfromtxt
接受来自任何提供它的线路的输入。但在这种情况下,所需的处理是@chefarov
建议的大部分 - 减去int
转换。
genfromtxt
也接受转换器,但我在其他问题中发现转换器无法将一个字段更改为多个字段。
还有genfromtxt
迭代文件行,解码每个行并收集列表中的值。所以它对于自定义阅读器没有任何速度优势。
【讨论】:
【参考方案3】:如果您使用pandas
,则有一种(可以说)更简单的方法来读取数据。首先,可以构造一个pandas.DataFrame
实例,我们可以将自定义函数应用于其最后一列,以将字符串元素转换为np.ndarray
类型:
import pandas as pd
import numpy as np
df = pd.read_table('dataset/demo_dataset.csv', delimiter='\t', names='abcdefg')
convert = lambda a: np.fromstring(a[1:-1], count = a.count(',') + 1, sep = ', ', dtype=int)
df.g = df.g.apply(convert)
一旦构建了混合数据框,X
和 Y
可以以简单的方式提取为数组:
X = df.values[:, :-1].astype(int)
Y = np.vstack(df.values[:, -1])
【讨论】:
以上是关于将制表符分隔的 csv 读入具有不同数据类型的 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章
使用 phpMyAdmin 将带有部分数据的制表符分隔的 csv 文件导入 mysql 表