Копирование списка в массив numpy преобразует числа с плавающей запятой в строки

#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 решает использовать строки для всего, когда инициализируется смешанным списком чисел с плавающей запятой и строк.