将元组列表转换为结构化numpy数组。

42

我有一个包含Num_tuples个元组的列表,它们都具有相同的长度Dim_tuple

xlist = [tuple_1, tuple_2, ..., tuple_Num_tuples]

为了明确起见,假设 Num_tuples=3Dim_tuple=2

xlist = [(1, 1.1), (2, 1.2), (3, 1.3)]
我希望将xlist使用用户提供的列名列表user_names和变量类型列表user_types,转换为结构化的numpy数组xarr
user_names = [name_1, name_2, ..., name_Dim_tuple]
user_types = [type_1, type_2, ..., type_Dim_tuple]

因此,在创建numpy数组时,

dtype = [(name_1,type_1), (name_2,type_2), ..., (name_Dim_tuple, type_Dim_tuple)]

对于我的玩具示例,所需的最终产品可能如下:

xarr['name1']=np.array([1,2,3])
xarr['name2']=np.array([1.1,1.2,1.3])

如何在不使用循环的情况下对xlist进行切片以创建xarr?


没有任何循环,这是否可能?列表推导呢?另外,你尝试过什么吗? - Aleksander Lidtke
是的,尽管我只能让硬编码的解决方案起作用,首先涉及xlist --> np.array(xlist)。 - aph
例如,xtemp = np.array(xlist),而x1=np.array(xtemp[:,1]),这会创建一个元素为一的元组numpy数组,这不是我想要的。我似乎无法正确地切片,这就是整个问题所在。我意识到应该很简单。 - aph
2个回答

48

一个元组列表是提供数据给结构化数组的正确方式:

In [273]: xlist = [(1, 1.1), (2, 1.2), (3, 1.3)]

In [274]: dt=np.dtype('int,float')

In [275]: np.array(xlist,dtype=dt)
Out[275]: 
array([(1, 1.1), (2, 1.2), (3, 1.3)], 
      dtype=[('f0', '<i4'), ('f1', '<f8')])

In [276]: xarr = np.array(xlist,dtype=dt)

In [277]: xarr['f0']
Out[277]: array([1, 2, 3])

In [278]: xarr['f1']
Out[278]: array([ 1.1,  1.2,  1.3])

或者如果名称很重要:

In [280]: xarr.dtype.names=['name1','name2']

In [281]: xarr
Out[281]: 
array([(1, 1.1), (2, 1.2), (3, 1.3)], 
      dtype=[('name1', '<i4'), ('name2', '<f8')])

http://docs.scipy.org/doc/numpy/user/basics.rec.html#filling-structured-arrays


http://docs.scipy.org/doc/numpy/user/basics.rec.html#filling-structured-arrays

5
这让我回到了起点。 - K.Nicholas

-1
hpaulj的回答很有趣,但也令人恐惧 :)
现代Pythonic的命名列方式是使用pandas,这是一个基于numpy构建的非常流行的包:
import pandas as pd

xlist = [(1, 1.1), (2, 1.2), (3, 1.3)]

# Cast name1 to int because pandas' default is float
df = pd.DataFrame(xlist, columns=['name1', 'name2']).astype({'name1':int})
print(df)

这给你一个DataFramedf,这是你想要的结构。
   name1  name2
0      1    1.1
1      2    1.2
2      3    1.3

你可以用这个做各种奇妙的事情,比如切片和各种操作。
例如,为了创建原始问题中请求的 `xarr` 字典:
>>> xarr = {k:np.array(v) for k,v in df.to_dict(orient='list').items()}
>>> xarr
{'name1': array([1, 2, 3]), 'name2': array([1.1, 1.2, 1.3])}

这个回答并没有解答原始问题,并且建议使用一个更大、臃肿的软件包,而可以通过接受的答案来避免这种情况。 - fwyzard
好的fwyzard,说得对;我已经添加了一行代码,将数据转换为原始问题中要求的确切格式。此外,pandas的“膨胀”可以被视为一个特性而不是一个错误:除非你有非常充分的理由,否则依赖于一个得到良好支持的包可能比试图自己编写基本数据转换任务的解决方案更好。 - Michael Currie
嗨Michael,我同意重复使用受支持的软件。然而,在一台双AMD EPYC 7763服务器上,import pandas需要超过0.5秒的时间...对于一个“简单”的转换来说,这很可能比操作本身所需的时间还要长 :-(如果pandas可以以更模块化的方式使用,我会更开心。 - fwyzard

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