将 dtype 分配给 numpy 数组的每个列

assign a dtype to each colum of a numpy array

提问人:caesar753 提问时间:4/10/2023 最后编辑:caesar753 更新时间:4/11/2023 访问量:65

问:

我正在尝试为 numpy 数组的每一列投射一个 dtype,但我没有运气。 我尝试了一些在stackoverflow上找到的解决方案(例如,像这里一样为每一列使用函数,或者尝试按照这里的建议显式声明数据类型,但没有任何效果......astype()np.array(..., dtype = [])

特别是对于第二种解决方案,如果我尝试此代码

with open('posizioni_mm.txt') as f:
    a, b, c, d, e  = [x for x in next(f).split()]
   
    dt = [('A', 'int'), ('B', 'float'), ('C', 'float'), ('D', 'float'), ('E', '<U32')]

    array = np.array([([x for x in line.split()]) for line in f], dtype = dt )

我收到此错误

ValueError: could not convert string to float: 'link_2'

由于数组移动了一列(“link_2”应该是 E 列,它的 dtype 应该是字符串,但它被放在 D 列中),如果我尝试生成没有数据类型的数组,然后生成一个具有正确 dtypes 的空数组

array2 = np.zeros(np.shape(array), dtype = dt)

它生成一个数组,每行有 5 个元组,每个元组有 5 个元素

[[(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., 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., '')]]

怎么了?

编辑: 这是文件的内容posizioni_mm.txt

30 0.78 227.31 270.7 link_1
30 0.73 310.79 268.72 link_2
30 0.32 141.41 276.87 link_3
35 0.45 72.47 212.11 link_4
30 0.18 163.22 205.95 link_5
8 0.25 109.69 207.49 link_6
24 0.3 295.15 197.14 link_7
45 0.3 390.97 179.96 link_8
8 0.45 153.08 101.1 link_9
33 0.36 87.44 114.32 link_10
8 0.24 285.9 94.27 link_11
30 0.42 326.87 90.97 link_12
33 0.4 221.15 96.92 link_13
18 0.2 257.49 56.61 link_14
51 0.16 194.71 53.96 link_15
数组 numpy 转换

评论

0赞 RomanPerekhrest 4/10/2023
您可以分享链接(或内容)吗?'posizioni_mm.txt'
0赞 caesar753 4/10/2023
是的,当然,它在编辑中
0赞 tevemadar 4/10/2023
由于数组移动了一列 - 您实际上应该检查一下。写代替测试行。print([([x for x in line.split()]) for line in f])array =
0赞 hpaulj 4/10/2023
如果指定 dt = [('A', 'int'), ('BCD', 'float', (3,)), ('E', '<U32')]np.zerosloadtxt' 数组将有 3 个字段,一个整数,一个字符串,另一个浮点数。 将是一个 (n,3) 数组。, then the , or arr['BCD']
0赞 hpaulj 4/10/2023
loadtxt或 with ,将自动推断字段 dtypes。您仍然可以获得一维结构数组。另一个想法是用于加载除最后一列(字符串一列)之外的所有列。其余的可以加载为浮点数,您可以自由地进行“数学运算”genfromtxtdtype=Noneusecols

答:

0赞 RomanPerekhrest 4/10/2023 #1

使用 numpy.loadtxt 从文本文件简单加载数据:

with open('posizioni_mm.txt') as f:
    dt = [('A', 'int'), ('B', 'float'), ('C', 'float'), ('D', 'float'), ('E', '<U32')]
    arr = np.loadtxt(f, dtype=dt)
    print(arr)

[(30, 0.78, 227.31, 270.7 , 'link_1') (30, 0.73, 310.79, 268.72, 'link_2')
 (30, 0.32, 141.41, 276.87, 'link_3') (35, 0.45,  72.47, 212.11, 'link_4')
 (30, 0.18, 163.22, 205.95, 'link_5') ( 8, 0.25, 109.69, 207.49, 'link_6')
 (24, 0.3 , 295.15, 197.14, 'link_7') (45, 0.3 , 390.97, 179.96, 'link_8')
 ( 8, 0.45, 153.08, 101.1 , 'link_9')
 (33, 0.36,  87.44, 114.32, 'link_10')
 ( 8, 0.24, 285.9 ,  94.27, 'link_11')
 (30, 0.42, 326.87,  90.97, 'link_12')
 (33, 0.4 , 221.15,  96.92, 'link_13')
 (18, 0.2 , 257.49,  56.61, 'link_14')
 (51, 0.16, 194.71,  53.96, 'link_15')]

现在,您可以按名称访问列,例如:'E'


print(arr['E'])

['link_1' 'link_2' 'link_3' 'link_4' 'link_5' 'link_6' 'link_7' 'link_8'
 'link_9' 'link_10' 'link_11' 'link_12' 'link_13' 'link_14' 'link_15']

评论

0赞 caesar753 4/10/2023
感谢您的回答,但是我需要操作矩阵中的数据,特别是我需要在 B 列中计算数据的均值和标准偏差。在加载“link_”名称之前,我能够在 numpy(浮点)数组 ''' groups = np.split(array[:, 0:], np.cumsum(np.unique(array[:, 0], return_counts=True)[1])[:-1]) group_stats = np.array([(g[0, 0], len(g), np.mean(g[:, 1]), np.std(g[:, 1])) for g in groups]) ''' 但现在它们不起作用。
0赞 caesar753 4/10/2023
特别是,我可以创建修改第一行的组,但我无法相应地修改第二行groups = np.split(array['A'], np.cumsum(np.unique(array['A'], return_counts=True)[1])[:-1])
0赞 hpaulj 4/10/2023
有了 like,您可以创建一个(有据可查)。虽然非常适合加载 csv,但您不能跨此类数组的字段进行数学运算。数组是一维的,有字段,而不是列。compound dtypedtstructured array
0赞 hpaulj 4/10/2023
我建议再问一个问题,以证明您想用 .也许有一个带有 2d 浮点数组的示例,然后有一个带有结构化数组的示例(可能失败)。groups
0赞 kcw78 4/10/2023 #2

将数据放在数组中后,就可以轻松计算字段(列)的平均值和标准差。此答案显示了如何扩展上面@RomanPerekhrest发布的解决方案。

f = 'posizioni_mm.txt'
dt = [('A', 'int'), ('B', 'float'), ('C', 'float'), ('D', 'float'), ('E', '<U32')]
arr = np.loadtxt(f, dtype=dt)
col_B = arr['B'] # to load column B values to an array
print(f"Col B mean = {np.mean(col_B):.2f}") # reference col_B above
print(f"Col B stddev = {np.std(arr['B']):.2f}") # Or just use arr['B']

数据的打印值:

Col B mean = 0.37
Col B stddev = 0.18
0赞 hpaulj 4/11/2023 #3

为了方便复制粘贴,我用字符串列表代替您的文件:

In [27]: txt = """30 0.78 227.31 270.7 link_1
    ...: 30 0.73 310.79 268.72 link_2
    ...: 30 0.32 141.41 276.87 link_3
    ...: 35 0.45 72.47 212.11 link_4
    ...: 30 0.18 163.22 205.95 link_5""".splitlines()

您的化合物类型:

In [28]: dt = [('A', 'int'), ('B', 'float'), ('C', 'float'), ('D', 'float'), ('E', '<U32')]

要从数据创建结构化数组,您需要提供元组列表(而不是列表列表)。只需稍作改动,您的代码就可以工作了:

In [29]: np.array([(tuple([x for x in line.split()])) for line in txt], dtype = dt )
Out[29]: 
array([(30, 0.78, 227.31, 270.7 , 'link_1'),
       (30, 0.73, 310.79, 268.72, 'link_2'),
       (30, 0.32, 141.41, 276.87, 'link_3'),
       (35, 0.45,  72.47, 212.11, 'link_4'),
       (30, 0.18, 163.22, 205.95, 'link_5')],
      dtype=[('A', '<i4'), ('B', '<f8'), ('C', '<f8'), ('D', '<f8'), ('E', '<U32')])

loadtxt/genfromtxt 也是如此:

In [30]: data = np.loadtxt(txt,dtype=dt)    
In [31]: data
Out[31]: 
array([(30, 0.78, 227.31, 270.7 , 'link_1'),
       (30, 0.73, 310.79, 268.72, 'link_2'),
       (30, 0.32, 141.41, 276.87, 'link_3'),
       (35, 0.45,  72.47, 212.11, 'link_4'),
       (30, 0.18, 163.22, 205.95, 'link_5')],
      dtype=[('A', '<i4'), ('B', '<f8'), ('C', '<f8'), ('D', '<f8'), ('E', '<U32')])

In [35]: data['A']
Out[35]: array([30, 30, 30, 35, 30])

我不知道你想对小组做什么。请记住,对于结构化数组,您有字段,而不是列。所以 2d 索引不起作用。一般来说,你不能跨领域做数学运算。

可以定义一个将 3 个浮点列组合在一起的 dtype:

In [36]: dt = [('A', 'int'), ('BCD', 'float',3), ('E', '<U32')]    
In [37]: data = np.loadtxt(txt,dtype=dt)    
In [38]: data
Out[38]: 
array([(30, [7.8000e-01, 2.2731e+02, 2.7070e+02], 'link_1'),
       (30, [7.3000e-01, 3.1079e+02, 2.6872e+02], 'link_2'),
       (30, [3.2000e-01, 1.4141e+02, 2.7687e+02], 'link_3'),
       (35, [4.5000e-01, 7.2470e+01, 2.1211e+02], 'link_4'),
       (30, [1.8000e-01, 1.6322e+02, 2.0595e+02], 'link_5')],
      dtype=[('A', '<i4'), ('BCD', '<f8', (3,)), ('E', '<U32')])        
In [40]: data['BCD']
Out[40]: 
array([[7.8000e-01, 2.2731e+02, 2.7070e+02],
       [7.3000e-01, 3.1079e+02, 2.6872e+02],
       [3.2000e-01, 1.4141e+02, 2.7687e+02],
       [4.5000e-01, 7.2470e+01, 2.1211e+02],
       [1.8000e-01, 1.6322e+02, 2.0595e+02]])

或者将所有数值列加载为浮点数,跳过字符串列。这给出了 2d 浮点数组:

In [41]: data = np.genfromtxt(txt,usecols=[0,1,2,3],encoding=None)
In [42]: data
Out[42]: 
array([[3.0000e+01, 7.8000e-01, 2.2731e+02, 2.7070e+02],
       [3.0000e+01, 7.3000e-01, 3.1079e+02, 2.6872e+02],
       [3.0000e+01, 3.2000e-01, 1.4141e+02, 2.7687e+02],
       [3.5000e+01, 4.5000e-01, 7.2470e+01, 2.1211e+02],
       [3.0000e+01, 1.8000e-01, 1.6322e+02, 2.0595e+02]])

评论

0赞 caesar753 4/11/2023
感谢您的回答,我不知道如何创建元组数组,但答案非常简单:-)
0赞 caesar753 4/11/2023 #4

多亏了你们,我以一种非常不优雅的方式解决了这个问题,但是......它有效

简而言之,我大量使用 .astype(...) 方法将字符串(临时)转换为 int 或 float

  1. 从文件 .txt 创建数组后,我使用 argsort 和 astype(int) for array[:,0]
with open(file) as f:
    
    array = np.array([[x for x in line.split()] for line in f])

array = array[array[:, 0].astype(int).argsort()]
  1. 然后我对 array[:,1] 进行操作,使用 .astype(float) 计算平均值和 std
groups = np.split(array[:, 0:], np.cumsum(np.unique(array[:, 0].astype(int), return_counts=True)[1])[:-1])
group_stats = np.array([(g[0, 0], len(g), np.mean(g[:, 1].astype(float)).round(2), np.std(g[:, 1].astype(float)).round(2)) for g in groups])
  1. 然后我将 group_stats 用于其他事情(我必须选择累积置信水平 >0.35 且标准偏差 < 0.2) 的 3 个类