Ваши 2 массива:
In [88]: aa = np.array([1,2,3,4])
...: bb = np.array(['a','b','c','d'])
...: a, b = np.meshgrid(aa,bb)
In [89]: a
Out[89]:
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])
In [90]: b
Out[90]:
array([['a', 'a', 'a', 'a'],
['b', 'b', 'b', 'b'],
['c', 'c', 'c', 'c'],
['d', 'd', 'd', 'd']], dtype='<U1')
Некоторая версия concatenate
может использоваться для объединения двух массивов. stack
с осью 2 делает то же самое, np.array((a,b))
с последующей транспонированием.
In [91]: np.stack((a,b),axis=2)
Out[91]:
array([[['1', 'a'],
['2', 'a'],
['3', 'a'],
['4', 'a']],
[['1', 'b'],
['2', 'b'],
['3', 'b'],
['4', 'b']],
[['1', 'c'],
['2', 'c'],
['3', 'c'],
['4', 'c']],
[['1', 'd'],
['2', 'd'],
['3', 'd'],
['4', 'd']]], dtype='<U21')
Но объединенный массив - это строка типа d, а не смесь целых чисел и строк. И не кортежи. Это массив (4,4,2).
Но если мы конвертируем массивы в объект dtype:
In [93]: np.stack((a.astype(object),b.astype(object)),axis=2)
Out[93]:
array([[[1, 'a'],
[2, 'a'],
[3, 'a'],
[4, 'a']],
[[1, 'b'],
[2, 'b'],
...
[4, 'd']]], dtype=object)
Мы можем изменить его на (-1,2), а затем tolist()
, чтобы получить версию списка.
Или мы могли бы создать структурированный массив с целочисленным полем и строковым полем. Его дисплей печати использует кортежи, чтобы пометить внутренние записи (которые отличаются от последнего измерения размера 2 выше).
In [98]: arr = np.zeros(a.shape, dtype='int,U5')
In [99]: arr
Out[99]:
array([[(0, ''), (0, ''), (0, ''), (0, '')],
[(0, ''), (0, ''), (0, ''), (0, '')],
[(0, ''), (0, ''), (0, ''), (0, '')],
[(0, ''), (0, ''), (0, ''), (0, '')]],
dtype=[('f0', '<i8'), ('f1', '<U5')])
In [100]: arr['f0']=a
In [101]: arr['f1']=b
In [102]: arr
Out[102]:
array([[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')],
[(1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')],
[(1, 'c'), (2, 'c'), (3, 'c'), (4, 'c')],
[(1, 'd'), (2, 'd'), (3, 'd'), (4, 'd')]],
dtype=[('f0', '<i8'), ('f1', '<U5')])
In [103]: print(arr)
[[(1, 'a') (2, 'a') (3, 'a') (4, 'a')]
[(1, 'b') (2, 'b') (3, 'b') (4, 'b')]
[(1, 'c') (2, 'c') (3, 'c') (4, 'c')]
[(1, 'd') (2, 'd') (3, 'd') (4, 'd')]]
zip
понимание списка делает версию списка приятной:
In [105]: [item for item in zip(a.flat,b.flat)]
Out[105]:
[(1, 'a'),
(2, 'a'),
(3, 'a'),
(4, 'a'),
(1, 'b'),
...
(4, 'd')]
Для этого размера выборки понимание списка происходит быстрее. Попытка избежать петель не всегда самый эффективный способ.
===
Элементы arr
являются np.void
объектами, хотя они отображаются как кортежи. Чтобы получить реальные кортежи, мы должны преобразовать их в dtype списка или объекта:
In [109]: arr.tolist()
Out[109]:
[[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')],
[(1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')],
[(1, 'c'), (2, 'c'), (3, 'c'), (4, 'c')],
[(1, 'd'), (2, 'd'), (3, 'd'), (4, 'd')]]
In [110]: arr.astype(object)
Out[110]:
array([[(1, 'a'), (2, 'a'), (3, 'a'), (4, 'a')],
[(1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')],
[(1, 'c'), (2, 'c'), (3, 'c'), (4, 'c')],
[(1, 'd'), (2, 'd'), (3, 'd'), (4, 'd')]], dtype=object)
In [111]: type(_[0,0])
Out[111]: tuple
Поля структурированного массива доступны по имени:
In [112]: arr['f0']
Out[112]:
array([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])