#python #numpy
Вопрос:
У меня есть массив Numpy, и я могу успешно обновить все его элементы одной строкой:
array_1 = np.array([1, 2, 3, 4])
array_1 = array_1 / 10.0
print(array_1)
# [0.1 0.2 0.3 0.4] -- Success!
Однако, когда у меня есть список массивов Numpy и я перебираю их с for in
помощью цикла, я не могу применить ту же операцию и получить желаемые результаты.
array_1 = np.array([1, 2, 3, 4])
array_2 = np.array([5, 6, 7, 8])
array_3 = np.array([9, 10, 11, 12])
print(array_1) # [1 2 3 4]
print(array_2) # [5 6 7 8]
print(array_3) # [ 9 10 11 12]
for array in [array_1, array_2, array_3]:
array = array / 10.0
print(array_1) # [1 2 3 4] -- No changes??
print(array_2) # [5 6 7 8]
print(array_3) # [ 9 10 11 12]
Почему я не могу обновить эти массивы внутри цикла? Насколько я понимаю, в этой строке
for array in [array_1, array_2, array_3]:
array
будет указателем на каждый из трех массивов Numpy.
Как я могу решить эту проблему?
Комментарии:
1. Вы должны отличать «переменную» от «значения». В первом примере вы создаете новое значение и изменяете привязку переменной
array_1
к новому значению. Во втором примере вы создаете новое значение и изменяете привязкуarray
— ноarray_1
все еще содержите старое значение.2. При назначении на
array
он указывает на новый массив, но не обновляет массив, на который он указывает.
Ответ №1:
Вы можете сделать неглубокую копию целевого массива внутри цикла for, чтобы отредактировать оригинал.
for array in [array_1,array_2,array_3]:
array[:] = array / 10.0
РЕДАКТИРОВАТЬ С Пояснением—
В цикле for управляющая переменная является собственным объектом, который глубоко копирует повторяемый элемент. Мы можем использовать операцию [:] для создания неглубокой копии целевого элемента, ссылающегося на исходный объект. Следующий код демонстрирует эту концепцию:
array_1 = ['foo']
print(id(array_1)) # Original object id
for array in [array_1]:
array = [1]
print(id(array)) # Deep copy id
for array in [array_1]:
array[:] = [1]
print(id(array)) # Original object id
Комментарии:
1. Не могли бы вы, пожалуйста, объяснить немного подробнее? Зачем нам нужно использовать
array[:] =
?2. Да, без проблем, должно было быть понятнее @stackoverflowuser2010
Ответ №2:
Потому что вы только присваиваете новые значения управляющей переменной цикла, поэтому вам нужно обратиться к фактическим элементам путем индексации:
arrays = [array_1, array_2, array_3]
for i in range(len(arrays)):
arrays[i] = arrays[i] / 10.0
или даже более всесторонне:
arrays = [array / 10.0 for array in arrays]
или даже путем фильтрации:
arrays = list(filter(lambda x: x / 10.0, arrays))
Редактировать:
Как @ForceBru
отмечается в разделе комментариев, разделение на месте приведет к возвращению массива float
типов, в то время как исходный int
. Таким образом, в первом фрагменте кода было изменено следующее: arrays[i] /= 10.0 -> arrays[i] = arrays[i] / 10.0
Комментарии:
1. Это не работает для меня. Я получаю эту ошибку:
TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'l') according to the casting rule ''same_kind''
указываю наarrays[i] /= 10.0
линию. Я использую Python 3.7.2. @stackoverflowuser2010, на самом деле, я получил ту же ошибку. Похоже, что массивы имеют целочисленный тип, но для деления на месте с помощью double (
10.0
) потребуется массив типа double, однако вы не можете записать double в массив целых чисел, отсюда и ошибка. Разделение вродеnp.array([9, 10, 11, 12]) / 10.0
работает нормально, потому что оно создает новый массив.3. @ForceBru: Это ошибка или функция?
4. @stackoverflowuser2010, ну, это не позволило вам записать число с плавающей запятой в массив целых чисел-я думаю, это имеет смысл, так как вы не запрашивали никакого приведения. Однако NumPy 1.8 не вызывает никаких ошибок в одном и том же коде и автоматически преобразует результирующие значения с плавающей точкой в целые числа. Я думаю, что это функция, которая обеспечивает лучший набор текста
5. @ForceBru: Подожди. Почему это работает?
arrays[0] = arrays[0] / 10.0
. LHS-это массив int, а RHS-массив double.