#python #numpy
#python #numpy
Вопрос:
У меня есть следующий массив:
values = [1, 1, 1, [1,2], 1,[3,4,5],[6,7]]
Я хотел бы умножить каждое число внутри него на 5
. Следующий код не сработал:
import numpy as np
m = np.array(values)
print(m * 5)
вывод:
[5 5 5 list([1, 2, 1, 2, 1, 2, 1, 2, 1, 2]) 5
list([3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5])
list([6, 7, 6, 7, 6, 7, 6, 7, 6, 7])]
Комментарии:
1. Вы должны обрабатывать внутренние списки отдельно. Numpy не очень подходит для этой задачи.
Ответ №1:
Как упоминалось в комментариях, numpy плох в этом, потому что numpy предназначен для массивов одинаковой длины в каждом измерении: вы не можете преобразовать свой список в массив numpy. Но это ИМЕННО то, для чего предназначен awkward
пакет: смотрите https://github.com/scikit-hep/awkward-1.0#readme
Установить с pip install awkward1
Затем:
import awkward1 as ak
values = [1, 1, 1, [1,2], 1,[3,4,5],[6,7]]
result = ak.Array(values) * 5
print(result.tolist())
выдает
[5, 5, 5, [5, 10], 5, [15, 20, 25], [30, 35]]
Ответ №2:
Другим способом добиться успеха была бы старая добрая рекурсивная функция:
values = [1, 1, 1, [1,2], 1,[3,4,5],[6,7]]
def listmult(x, c):
out = []
for v in x:
if isinstance(v, list):
out.append(listmult(v, c))
else:
out.append(v*c)
return out
print(listmult(values, 5))
[5, 5, 5, [5, 10], 5, [15, 20, 25], [30, 35]]
Ответ №3:
In [232]: alist = [1, 1, 1, [1,2], 1,[3,4,5],[6,7]]
По состоянию на 1.19
numpy
предупреждает о создании массива из такого списка:
In [233]: np.array(alist)
/usr/local/bin/ipython3:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
#!/usr/bin/python3
Out[233]:
array([1, 1, 1, list([1, 2]), 1, list([3, 4, 5]), list([6, 7])],
dtype=object)
Обратите внимание, что этот массив содержит числа и списки:
In [234]: np.array(alist, object)
Out[234]:
array([1, 1, 1, list([1, 2]), 1, list([3, 4, 5]), list([6, 7])],
dtype=object)
Для массива объекта dtype он выполняет итерацию (со скоростью python) по элементам и делегирует действие собственному методу элемента. Для списка *5
означает реплицировать:
In [235]: np.array(alist, object)*5
Out[235]:
array([5, 5, 5, list([1, 2, 1, 2, 1, 2, 1, 2, 1, 2]), 5,
list([3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5]),
list([6, 7, 6, 7, 6, 7, 6, 7, 6, 7])], dtype=object)
Теперь, если бы список содержал массивы вместо списков:
In [236]: alist = [1, 1, 1, np.array([1,2]), 1,np.array([3,4,5]),np.array([6,7])]
In [237]: np.array(alist, object)
Out[237]:
array([1, 1, 1, array([1, 2]), 1, array([3, 4, 5]), array([6, 7])],
dtype=object)
теперь умножение работает для элементов массива — с числовым умножением.
In [238]: np.array(alist, object)*5
Out[238]:
array([5, 5, 5, array([ 5, 10]), 5, array([15, 20, 25]), array([30, 35])],
dtype=object)
Математика для массивов объектов dtype является случайной, в зависимости от типа элементов. Это работает для некоторых, а не для других, в зависимости от того, как операция реализуется элементами. И даже там, где это работает, скорость больше похожа на понимание списка, чем многомерного массива.
In [244]: timeit np.array(alist, object)*5
13.3 µs ± 333 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [245]: timeit [i*5 for i in alist]
6.43 µs ± 140 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [246]: timeit np.array([i*5 for i in alist],object)
9.98 µs ± 47.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Ответ №4:
Боюсь, ваша структура данных не допускает такой операции. По крайней мере, не с помощью numpy. Если вы приведете список списков разной размерности к массиву numpy, результирующий тип данных будет object
, но без числового типа данных (int, float и т.д.):
>>> import numpy as np
>>> np.array([1, [1]])
array([1, list([1])], dtype=object)
Таким образом, numpy не видит содержимое вашего массива как числовое и, следовательно, не может транслировать числовые операции.
Убедитесь, что все входные данные имеют одинаковую размерность, чтобы после преобразования вашего списка списков в массив numpy dtype
был числовым типом данных:
>>> np.array([[1], [1]]).dtype
dtype('int64')