#python #numpy
#python #numpy
Вопрос:
У меня есть список с 4 столбцами, 3 из которых являются np.floats, а 1 из них — str, когда я запускаю это
print("cluster", clusters[0], type(clusters[0][0]))
numpyClusters = np.copy(clusters)
print("numpyCluster", numpyClusters[0], type(numpyClusters[0][0]))
finalizedClusters = kMeansAlgorithm(dataSet, centeroids, clusters, oldClusters, k)
он печатает
cluster [0.12072145106500658, 1, 1.0337254896570043, 'winter'] <class 'numpy.float64'>
numpyCluster ['0.12072145106500658' '1' '1.0337254896570043' 'winter'] <class 'numpy.str_'>
Позже мне нужно, чтобы первые 3 столбца были числами с плавающей запятой,
Можете ли вы скопировать список в массив numpy со всеми значениями внутри, сохраняя их исходный тип?
Комментарии:
1. Массив numpy имеет 1 тип данных, в то время как список python может содержать элементы с разными типами данных. numpy.org/doc/stable/reference/generated/numpy.array.html
Ответ №1:
Как указано @couka, массив numpy может содержать только один тип данных. Хотя вы можете немного схитрить, поскольку numpy допускает object
dtype. Например:
>>> import numpy as np
>>> test = ["a", 1, 2, 3]
>>> test_array = np.array(test)
>>> test_array
array(['a', '1', '2', '3'], dtype='<U1')
>>> test_array * 2
numpy.core._exceptions.UFuncTypeError: ufunc 'multiply' did not contain a loop with signature matching types (dtype('<U3'), dtype('<U3')) -> dtype('<U3')
>>> test_array_object = np.array(test, dtype="O")
>>> test_array_object
array(['a', 1, 2, 3], dtype=object)
>>> test_array_object * 2
array(['aa', 2, 4, 6], dtype=object)
Когда значение dtype
массива равно object
и выполняется операция, numpy просто применяет соответствующую операцию к его элементам. Например, при умножении массива на целое число numpy вызовет __mul__
метод каждого объекта в массиве.
Однако у этого метода есть несколько недостатков. Если вы хотите применить операцию только к целым числам, вам нужно выполнить некоторую индексацию:
>>> test_array_object[1:] *= 2
>>> test_array_object
array(['a', 2, 4, 6], dtype=object)
Что еще более важно, numpy не может использовать каждую оптимизацию, которую он обычно использует для целых массивов, поэтому при этом у вас будут накладные расходы на ускорение выполнения.
Я думаю, что самый простой метод — просто использовать класс данных для хранения ваших данных и определить операции, которые вы хотите применить к нему, например:
from dataclasses impoort dataclass
import numpy as np
@dataclass
class NamedArray:
name: str
array: np.ndarray
который затем вы бы использовали следующим образом:
>>> test = ["a", 1., 2., 3.]
>>> named_test = NamedArray(test[0], np.array(test[1:]))
>>> named_test
NamedArray(name='a', array=array([1, 2, 3]))
>>> named_test.array
array([1., 2., 3.])
>>> named_test.array.dtype
dtype('float64')
Затем вы можете свободно работать с named_test.array
вашими вычислениями в массиве, сохраняя при этом оптимизацию numpy для выполняемых вами операций и не заботясь о str
том, что удерживается named_test.name
.
Ответ №2:
Из: https://numpy.org/doc/stable/reference/generated/numpy.array.html (Курсив мой)
numpy.array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0, like=None)
[…]
dtype : тип данных, необязательно желаемый тип данных для массива. Если не задано, то тип будет определен как минимальный тип, необходимый для хранения объектов в последовательности.
Поскольку вы можете представить любое число с плавающей запятой в виде строки, но не наоборот, numpy решает использовать строки для всего, когда инициализируется смешанным списком чисел с плавающей запятой и строк.