Понимание списка Python для Numpy

Я ищу метод понимания списка или аналогичный в Numpy, чтобы исключить использование цикла for, например. index_values ​​— это список списков словаря Python (каждый список содержит разное количество значений индекса), а s — это пустой вектор:

for i in range(33):
    s[index_values[i]] += 4.1

Есть ли доступный метод, позволяющий исключить цикл for?


person Henry Thornton    schedule 01.01.2012    source источник
comment
Я не думаю, что есть более общий способ, чем использование списков Python... но если вы делаете что-то конкретное, например, конкретную математическую операцию, возможно, есть способ. Что ты пытаешься сделать?   -  person Emil Stenström    schedule 02.01.2012


Ответы (2)


Я не совсем понимаю, что это за объект index_values. Но если бы это был ndarray или его можно было преобразовать в ndarray, вы могли бы просто сделать это:

>>> s = numpy.arange(20)
>>> index_values = (numpy.random.random((3, 3)) * 20).astype('i')
>>> s[index_values] = 4
>>> s
array([ 0,  1,  4,  4,  4,  5,  6,  4,  8,  4,  4, 11, 12, 
       13,  4, 15,  4,  4,  4, 19])

Изменить: Но похоже, что в данном случае это не сработает. На основе ваших правок и комментариев, вот метод, который, я думаю, может сработать для вас. Случайный список списков разной длины...

>>> index_values = [list(range(x, x + random.randrange(1, 5)))
...                 for x in [random.randrange(0,50) for y in range(33)]]

... не сложно преобразовать в массив:

>>> index_value_array = numpy.fromiter(itertools.chain(*index_values), 
                                       dtype='i')

Если вы знаете длину массива, укажите count для лучшей производительности:

>>> index_value_array = numpy.fromiter(itertools.chain(*index_values), 
                                       dtype='i', count=83)

Поскольку ваше редактирование указывает на то, что вы хотите поведение, подобное гистограмме, простая индексация не подойдет, как указал Роберт Керн. Так что используйте numpy.histogram:

>>> hist = numpy.histogram(index_value_array, bins=range(0, 51))

histogram действительно создан для гистограмм с плавающей запятой. Это означает, что бины должны быть немного больше, чем ожидалось, потому что последнее значение включается в последний бин, и поэтому 48 и 49 были бы в одном бине, если бы мы использовали более интуитивно понятный range(0, 50). Результатом является кортеж с массивом из n счетчиков и массивом из n + 1 границ ячеек:

>>> hist
(array([2, 2, 1, 2, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 5, 5, 5, 3, 3, 
        3, 3, 3, 2, 1, 0, 2, 3, 3, 1, 0, 2, 3, 2, 2, 2, 3, 2, 1, 1, 2, 2, 
        2, 0, 0, 0, 1, 0]), 
 array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
        34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]))

Теперь мы можем увеличить подсчеты в 4,1 раза и выполнить сложение векторов:

>>> s = numpy.arange(50, dtype='f')
>>> hist[0] * 4.1 + s
array([  8.2,   9.2,   6.1,  11.2,   8.1,   5. ,   6. ,   7. ,  12.1,
        13.1,  14.1,  15.1,  16.1,  13. ,  18.1,  19.1,  20.1,  37.5,
        38.5,  39.5,  32.3,  33.3,  34.3,  35.3,  36.3,  33.2,  30.1,
        27. ,  36.2,  41.3,  42.3,  35.1,  32. ,  41.2,  46.3,  43.2,
        44.2,  45.2,  50.3,  47.2,  44.1,  45.1,  50.2,  51.2,  52.2,
        45. ,  46. ,  47. ,  52.1,  49. ])

Я понятия не имею, подходит ли это для ваших целей, но это кажется хорошим подходом, и, вероятно, он должен происходить на скорости, близкой к c, поскольку он использует только numpy и itertools.

person senderle    schedule 01.01.2012
comment
Это правильный ответ для массивов numpy. Единственное, на что следует обратить внимание, это расширение этого на расширенное назначение. Когда в index_values есть повторения, расширенное присваивание не будет повторяться, как в полном цикле for (по причинам, которые сложно понять). Таким образом, вы не можете использовать этот тип индексации для создания специальных гистограмм, как это пытаются сделать многие люди. - person Robert Kern; 02.01.2012
comment
index_values ​​- это список списков словаря Python, например. [[3, 6, 7], [5, 7, 11, 25, 99], [8, 45]]. index_values ​​не может быть ndarray — извините! - person Henry Thornton; 02.01.2012
comment
@dbv, я думаю, что меня смущает список списков в словаре. Я не знаю, что такое список словарей. Вы имеете в виду просто словарь списков? Если да, то почему вы используете ints для его индексации? Почему бы просто не использовать список списков? Список списков может быть передан numpy.array для создания ndarray соответствующей формы, например: numpy.array([[1, 2, 3], [1, 2, 3]]). Если вы должны использовать словарь, вы можете, по крайней мере, ускорить понимание, например: numpy.array([d[i] for i in range(2)]). - person senderle; 02.01.2012
comment
@dev, использующий ndarray для индексирования s, почти определенно является правильным решением. Сообщите нам, почему вы думаете, что вы не можете превратить index_values ​​в ndarray, и, возможно, мы сможем придумать исправление. Также существует относительно простое решение проблемы, поднятой Робертом Керном, дайте мне знать, если это актуально в вашем случае, и я опубликую код. - person Bi Rico; 02.01.2012
comment
ребята, сегодня я удалю этот вопрос и переформулирую как новый вопрос. спасибо и, надеюсь, увидимся на другой стороне. - person Henry Thornton; 02.01.2012
comment
@dbv, это законный вопрос, и никто не голосовал за его закрытие. Я бы посоветовал вам не удалять его. Если ваш фактический вопрос сильно отличается и поэтому не будет считаться дубликатом, создайте новый вопрос. Если это не так уж отличается, отредактируйте свой текущий вопрос. - person senderle; 02.01.2012

Что о:

s[reduce(lambda x,y: x+y, [index_values[x] for x in range(33)], [])] = 4.1
person Ricardo Cárdenes    schedule 01.01.2012
comment
см. комментарий под Tadeck. Спасибо! - person Henry Thornton; 02.01.2012
comment
Под Тадеком? :? В данный момент Тадека не видно :) (люди продолжают удалять свои ответы, и их трудно отследить!) - person Ricardo Cárdenes; 02.01.2012
comment
Да, только что увидел, что ответ @Tadeck был удален. Я отредактировал исходный вопрос выше, чтобы показать, что вектор Numpy обновляется на месте. - person Henry Thornton; 02.01.2012
comment
Да, конечно. Мой комментарий к ответу @Tadeck был о том, как он использовал понимание и фильтр, а не о конечном результате. Конечно, я понимаю, что вы собираетесь изменить части s, а не создавать новый массив :) - person Ricardo Cárdenes; 02.01.2012
comment
Функция сокращения накапливает значения в index_values[x]. Допустим, index_value[x] = [4, 7, 9, 11, 13], тогда мы хотим s[[4, 7, 9, 11, 13]] = s[[4, 7, 9, 11, 13]] + 4,1 т.е. s[4] += 4.1, s[7] += 4.1 и т. д. для x в диапазоне (33). - person Henry Thornton; 02.01.2012
comment
Ах, черт! Хорошо, что += не было в начале, не так ли? Потому что, конечно, код, который я написал, не делает то, что вы хотите! - person Ricardo Cárdenes; 02.01.2012