Как изменить массив с помощью функции в Numpy? - PullRequest
0 голосов
/ 03 августа 2020

У меня проблема. Настройка сложнее, чем то, что я показываю здесь, но это сделано для того, чтобы проблема была более понятной. Представьте, что у меня есть следующий скрипт:

  import numpy as np
  import pandas as pd

  world_exports = np.zeros((4, 1))

  def sum_country_exports(nation, vector):
      vector = np.add(np.array(vector), np.array(exports[nation]))

  countries = ['United States', 'Canada', 'Mexico']

  list_X = [[10, 20, 40], [30, 40, 20], [40, 50, 60], [60, 70, 30]]
  exports = pd.DataFrame(list_X, columns = ['United States', 'Canada', 'Mexico']) 

  for country in countries:
      sum_country_exports(country, world_exports)

У меня есть квартальные данные об экспорте трех стран (США, Канада и Мексика). Идея состоит в том, что объект world_exports представляет собой сумму экспорта этих стран за каждый квартал. Крайне важно, чтобы этот объект был создан вне функции.

Затем я хочу l oop над экспортом каждой из этих стран и добавить его в массив world_exports. Следовательно, ожидаемый результат будет 10 + 20 + 40 = 70 для первого квартала (et c. Для остальных трех кварталов).

В настоящее время world_exports возвращается к нулю каждый раз, когда l oop переходит в новую страну.

Я уже пробовал изменить vector = np.add... на vector[:] = ... внутри функции. Это изменило результаты, но они были очень странными и неверными.

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 04 августа 2020

Это обычная проблема в Python. Даже если тип является изменяемым, x = exp никогда не изменяет объект, на который указывает ссылка, но делает указание локальной переменной на новый.

Это означает, что все ваши вызовы sum_country_exports последовательно передают исходный world_exports, локальная переменная export в сумме указывается на новое выражение, и значение просто отбрасывается, когда функция возвращается, оставляя исходный объект нетронутым.

Как исправить?

Несвязано, но исходная форма вектора должна быть (4,), а не (4,1). В своих тестах я использовал world_exports = np.zeros(4)

  1. изменить переданный параметр

    Вы можете передать список, содержащий world_export, и изменить первый (и единственный) элемент этого список. В конце список будет содержать ожидаемое значение:

     def sum_country_exports(nation, vector):
         vector[0] = np.add(np.array(vector[0]), np.array(exports[nation]))
    
     lst = [world_exports]
     for country in countries:
         sum_country_exports(country, lst)
    
     print(lst[0])
    

    С образцами данных это дает:

     [ 70.  90. 150. 160.]
    
  2. return новое значение

    Когда вы меняете только одно значение, ИМХО намного проще (и меньше подвержено ошибкам) ​​просто вернуть это значение:

     def sum_country_exports(nation, vector):
         return np.add(np.array(vector), np.array(exports[nation]))
    
     for country in countries:
         world_exports = sum_country_exports(country, world_exports)
    
     print(world_exports)
    

    Это тоже дает:

     [ 70.  90. 150. 160.]
    

    Я предпочитаю второй способ, потому что в моем первом коде lst[0] действительно содержит ожидаемые значения, но world_exports все еще равно 0.

  3. используйте * Параметр 1043 * из np.add

    np.add позволяет сохранить результат в ndarray, имеющем ожидаемую форму. Это позволяет фактически изменять переданный массив:

     def sum_country_exports(nation, vector):
         np.add(np.array(vector), np.array(exports[nation]), out=vector)
    
     for country in countries:
         sum_country_exports(country, world_exports)
    
     print(world_exports)
    

    Это тоже дает:

     [ 70.  90. 150. 160.]
    

    Это, вероятно, то, что вы хотите, но numpy указывает c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...