为numpy数组中的不同列分配不同的数据类型

时间:2016-10-25 16:27:27

标签: python arrays csv numpy

我有一个numpy数组,形状为(8000000, 7)

我希望将numpy数组的前6列保留为float32数据类型,将最后一列保留为int8类型。

最后,我想将其保存为csv文件。

我该如何管理?

3 个答案:

答案 0 :(得分:2)

你可以构造一个结构化数组,但我想知道你是否需要,特别是如果你想要的只是一个csv文件。 fmt参数控制savetxt写入列的方式。

首先使用默认的fmt和column_stack

In [1484]: a=np.random.rand(5,3)
In [1485]: b=np.arange(5,dtype=np.int8)

In [1486]: np.savetxt('test.txt',np.column_stack((a,b)))
In [1487]: cat test.txt
3.513972543477327237e-01 8.468274950931957701e-01 6.587019305719005180e-01 0.000000000000000000e+00
...

使用更简单的浮动格式:

In [1492]: np.savetxt('test.txt',np.column_stack((a,b)),fmt='%f')
In [1493]: cat test.txt
0.351397 0.846827 0.658702 0.000000
0.566257 0.419570 0.183939 1.000000
0.276351 0.341277 0.706639 2.000000
0.515183 0.296801 0.321054 3.000000
0.305349 0.407097 0.328825 4.000000

或者通过指定每列的格式:

In [1496]: np.savetxt('test.txt',np.column_stack((a,b)),fmt=['%f']*3+['%d'])
In [1497]: cat test.txt
0.351397 0.846827 0.658702 0
0.566257 0.419570 0.183939 1
0.276351 0.341277 0.706639 2
0.515183 0.296801 0.321054 3
0.305349 0.407097 0.328825 4

==============================

使用这样的数据构造结构化数组的一个很好的方法是定义2个字段,并使第一个成为数组:

In [1503]: dt=np.dtype('(3)f,i8')
In [1504]: A=np.empty((5,),dtype=dt)
In [1505]: A['f0']=a
In [1506]: A['f1']=b
In [1507]: A
Out[1507]: 
array([([0.35139724612236023, 0.846827507019043, 0.6587019562721252], 0),
       ([0.566256582736969, 0.41956955194473267, 0.18393920361995697], 1),
       ([0.27635079622268677, 0.3412773013114929, 0.706638514995575], 2),
       ([0.5151825547218323, 0.29680076241493225, 0.32105395197868347], 3),
       ([0.30534881353378296, 0.4070965051651001, 0.3288247585296631], 4)], 
      dtype=[('f0', '<f4', (3,)), ('f1', '<i8')])

不幸的是savetxt无法处理那种'嵌套'dtype。我能做的最好的事情是将第一个字段格式化为字符串,使用[]

In [1509]: np.savetxt('test.txt',A,fmt=['%s','%d'])
In [1511]: cat test.txt
[ 0.35139725  0.84682751  0.65870196] 0
[ 0.56625658  0.41956955  0.1839392 ] 1
[ 0.2763508   0.3412773   0.70663851] 2
[ 0.51518255  0.29680076  0.32105395] 3
[ 0.30534881  0.40709651  0.32882476] 4

相反,我需要做一个扁平的dtype;我可以使用相同的字节布局将其应用于视图(或从头开始构造数组)

In [1512]: dt1=np.dtype('f,f,f,i8')
In [1514]: A.view(dt1)
Out[1514]: 
array([(0.35139724612236023, 0.846827507019043, 0.6587019562721252, 0),
       (0.566256582736969, 0.41956955194473267, 0.18393920361995697, 1),
       (0.27635079622268677, 0.3412773013114929, 0.706638514995575, 2),
       (0.5151825547218323, 0.29680076241493225, 0.32105395197868347, 3),
       (0.30534881353378296, 0.4070965051651001, 0.3288247585296631, 4)], 
      dtype=[('f0', '<f4'), ('f1', '<f4'), ('f2', '<f4'), ('f3', '<i8')])

现在我可以用与之前相同的fmt来编写它:

In [1515]: np.savetxt('test.txt',A.view(dt1),fmt=['%f']*3+['%d'])
In [1516]: cat test.txt
0.351397 0.846828 0.658702 0
0.566257 0.419570 0.183939 1
0.276351 0.341277 0.706639 2
0.515183 0.296801 0.321054 3
0.305349 0.407097 0.328825 4

如果您的一个或多个列是字符串,那么您将需要使用结构化数组。但只要所有列都是数字,您就可以使用全浮点数组,并使用fmt控制打印。

答案 1 :(得分:1)

那么你可以构造dtype然后使用零或空来获得一个准备好数据的空shell。希望这会给你一些想法

>>> import numpy as np
>>> 
>>> flds = ["f{:0>{}}".format(i,2) for i in range(7)]
>>> dt = [(fld, 'float32') for fld in flds]
>>> dt.append(('i01', 'int8'))
>>> a = np.zeros((10,), dtype=dt)
>>> a
array([(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0)], 
      dtype=[('f00', '<f4'), ('f01', '<f4'), ('f02', '<f4'), ('f03', '<f4'), ('f04', '<f4'), ('f05', '<f4'), ('f06', '<f4'), ('i01', 'i1')])
>>> 

使用此示例def

def num_45():
    """(num_45)...
    """
    import numpy as np
    flds = ["f{:0>{}}".format(i,2) for i in range(7)]
    dt = [(fld, 'float32') for fld in flds]
    dt.append(('i01', 'int8'))
    a = np.zeros((10,), dtype=dt)
    b = np.arange(10*8).reshape(10,8)
    c = np.copy(a)
    names = a.dtype.names
    N = len(names)
    for i in range(N):
        c[names[i]] = b[:,i]
    return a, b, c 

结果

>>> a
array([(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0),
       (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0)], 
      dtype=[('f00', '<f4'), ('f01', '<f4'), ('f02', '<f4'), ('f03', '<f4'), ('f04', '<f4'), ('f05', '<f4'), ('f06', '<f4'), ('i01', 'i1')])
>>> b
array([[ 0,  1,  2,  3,  4,  5,  6,  7],
       [ 8,  9, 10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21, 22, 23],
       [24, 25, 26, 27, 28, 29, 30, 31],
       [32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47],
       [48, 49, 50, 51, 52, 53, 54, 55],
       [56, 57, 58, 59, 60, 61, 62, 63],
       [64, 65, 66, 67, 68, 69, 70, 71],
       [72, 73, 74, 75, 76, 77, 78, 79]])
>>> c
array([(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7),
       (8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15),
       (16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23),
       (24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31),
       (32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39),
       (40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47),
       (48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55),
       (56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63),
       (64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71),
       (72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79)], 
      dtype=[('f00', '<f4'), ('f01', '<f4'), ('f02', '<f4'), ('f03', '<f4'), ('f04', '<f4'), ('f05', '<f4'), ('f06', '<f4'), ('i01', 'i1')])

用几行手动代码查看构造的另一个例子

n = ['It', 'is', 'easy']
dt = [(n[0], '<f8'), (n[1], '<i8'), (n[2], 'U5')]
d = np.zeros((10,), dtype=dt)
for i in range(len(n)):
    d[n[i]] = b[:, i]

产量

>>> d.dtype.names
('It', 'is', 'easy')
>>> d.reshape(10,-1)
array([[(0.0, 1, '2')],
       [(8.0, 9, '10')],
       [(16.0, 17, '18')],
       [(24.0, 25, '26')],
       [(32.0, 33, '34')],
       [(40.0, 41, '42')],
       [(48.0, 49, '50')],
       [(56.0, 57, '58')],
       [(64.0, 65, '66')],
       [(72.0, 73, '74')]], 
      dtype=[('It', '<f8'), ('is', '<i8'), ('easy', '<U5')])

答案 2 :(得分:1)

我认为将数组分解为浮点数和整数然后使用zipnp.savetxt的组合将它们全部重新组合在csv中会相对容易。但是Support zip input in savetxt in Python 3表明这种方式是疯狂的。

然而,由于坚持zip想法,我只是将工作转移到标准csv模块。由于numpy数据需要转换为python类型,因此可能会慢一些。但我们正在谈论csv在这里写作,所以希望它只是在噪音中迷失了。

首先,生成测试数组

>>> import numpy as np
>>> array = np.arange(0., 18.*5, 5., dtype=np.float32).reshape((3,6))
>>> array
array([[  0.,   5.,  10.,  15.,  20.,  25.],
       [ 30.,  35.,  40.,  45.,  50.,  55.],
       [ 60.,  65.,  70.,  75.,  80.,  85.]], dtype=float32)

拆分最后一列并重铸为uint8

>>> floats, ints, _after = np.hsplit(array, (5,6))
>>> ints=ints.astype(np.uint8)
>>> floats
array([[  0.,   5.,  10.,  15.,  20.],
       [ 30.,  35.,  40.,  45.,  50.],
       [ 60.,  65.,  70.,  75.,  80.]], dtype=float32)
>>> ints
array([[25],
       [55],
       [85]], dtype=uint8)

使用python csv模块进行写操作。您需要将压缩的数组行转换为元组并将它们一起添加到np.array到python数据类型。

>>> import csv
>>> writer = csv.writer(open('test.csv', 'w'))
>>> writer.writerows(tuple(f)+tuple(i) for f,i in zip(floats, ints))
>>> del writer
>>> print(open('test.csv').read())
0.0,5.0,10.0,15.0,20.0,25
30.0,35.0,40.0,45.0,50.0,55
60.0,65.0,70.0,75.0,80.0,85