Обновите массив, находясь внутри, для цикла над массивами

#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.