Как я могу выполнить операцию только для одного значения на лету в массиве numpy?(или лучший способ) - PullRequest
0 голосов
/ 13 июня 2018

У меня есть массив, например, a = np.arange(0, 5), и он выглядит так array([0, 1, 2, 3, 4]).

Теперь я хочу добавить, например, только в индексе 2 значение, подобное 5, и получить новый numpy.объект массива.

Примерно так: b = add_value_on_idx(a, 2, 5) # This should return a new object

Я пробовал этот подход для достижения этого

#! /usr/bin/python3.5

import numpy as np

from time import time

# Get a numpy array first
a = np.random.randint(0, 10, (5, ))

# Define a new tuple of zeros with only one number at the
# specific index
def do_add_at_idx_1(arr, idx, val):
    return arr+(((0, )*(idx))+(val, )+(0, )*(arr.shape[0]-idx-1))

# Or do it like this
def do_add_at_idx_2(arr, idx, val):
    one_val_vec = np.zeros((arr.shape[0], )).astype(arr.dtype)
    one_val_vec[idx] = val
    return arr+one_val_vec

# Or add it directly to the given array
def do_add_at_idx_3(arr, idx, val):
    arr = arr.copy()
    arr[idx] += val
    return arr

# Or use directly np.add.at function (but need a copy first)
def do_add_at_idx_4(arr, idx, val):
    arr = arr.copy()
    np.add.at(arr, idx, val)
    return arr

a_old = a.copy()
print("a: {}".format(a))
print("do_add_at_idx_1(a, 2, 5): {}".format(do_add_at_idx_1(a, 2, 5)))
print("do_add_at_idx_2(a, 2, 5): {}".format(do_add_at_idx_2(a, 2, 5)))
print("do_add_at_idx_3(a, 2, 5): {}".format(do_add_at_idx_3(a, 2, 5)))
print("do_add_at_idx_4(a, 2, 5): {}".format(do_add_at_idx_4(a, 2, 5)))
print("Was 'a' modified? {}".format("No." if np.all(a==a_old) else "YES!!"))

, который будет выводить что-то вроде этого:

a: [6 6 9 2 8]
do_add_at_idx_1(a, 2, 5): [ 6  6 14  2  8]
do_add_at_idx_2(a, 2, 5): [ 6  6 14  2  8]
do_add_at_idx_3(a, 2, 5): [ 6  6 14  2  8]
do_add_at_idx_4(a, 2, 5): [ 6  6 14  2  8]
Was 'a' modified? No.

Я также проверил разницу во времени для этих функций:

n = 100000
print("n: {}".format(n))
idxs = np.random.randint(0, a.shape[0], (n, ))
vals = np.random.randint(0, 10, (n, ))

for i in range(1, 5):
    func_name = "do_add_at_idx_{}".format(i)
    func = globals()[func_name]

    start = time()
    for idx, val in zip(idxs, vals):
        func(a, idx, val)
    delta = time()-start

    print("Taken time for func '{}': {:2.4f}s".format(func_name, delta))

С этим в качестве вывода:

Taken time for func 'do_add_at_idx_1': 2.1899s
Taken time for func 'do_add_at_idx_2': 1.4600s
Taken time for func 'do_add_at_idx_3': 0.5757s
Taken time for func 'do_add_at_idx_4': 2.8043s

Есть ли какие-либо лучшие способы сделать этот подход?

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