2015-01-17 7 views
3

Есть ли способ получить элементы массива в одной операции для известных строк и столбцов этих элементов? В каждой строке я хотел бы получить доступ к элементам из col_start в col_end (каждая строка имеет разные начальные и конечные индексы). Количество элементов одинаково для каждой строки, элементы - последовательно. Пример:Доступ к нескольким элементам массива

[ . . . . | | | . . . . . ] 
[ | | | . . . . . . . . . ] 
[ . . | | | . . . . . . . ] 
[ . . . . . . . . | | | . ] 

Одним из решений было бы получить индексы (строка-столбец пара) элементов, а не использовать my_array [row_list, col_list].

Есть ли какой-либо другой (более простой) способ без использования для петель?

+0

Да, но можете ли вы предоставить лучший пример? – dursk

+0

В примере (|) находятся элементы, к которым я хочу обратиться, (.) - это другие элементы. Хочешь узнать что-нибудь еще? – recodeFuture

+1

@tjons: что убеждает вас в том, что мы работаем со словарем? OP повторно ссылается на массив; OP добавила тег 'numpy'; представление выглядит намного больше, чем представление массива, чем словарь; и т.п. – DSM

ответ

3
A = np.arange(40).reshape(4,10)*.1 
startend = [[2,5],[3,6],[4,7],[5,8]] 
index_list = [np.arange(v[0],v[1]) + i*A.shape[1] 
       for i,v in enumerate(startend)] 
# [array([2, 3, 4]), array([13, 14, 15]), array([24, 25, 26]), array([35, 36, 37])] 
A.flat[index_list] 

производства

array([[ 0.2, 0.3, 0.4], 
     [ 1.3, 1.4, 1.5], 
     [ 2.4, 2.5, 2.6], 
     [ 3.5, 3.6, 3.7]]) 

Это все еще имеет итерации, но это довольно элементарное один над списком. Я индексирую сплющенную, 1d, версию A. np.take(A, index_list) также работает.

Если интервалы строк отличаются по размеру, я могу использовать np.r_, чтобы объединить их. Это не совсем необходимо, но это удобство при создании индексов из нескольких интервалов и значений.

A.flat[np.r_[tuple(index_list)]] 
# array([ 0.2, 0.3, 0.4, 1.3, 1.4, 1.5, 2.4, 2.5, 2.6, 3.5, 3.6, 3.7]) 

idx, что ajcr использование может быть использована без choose:

idx = [np.arange(v[0], v[1]) for i,v in enumerate(startend)] 
A[np.arange(A.shape[0])[:,None], idx] 

idx как мой index_list за исключением того, что он не добавляет длину строки.

np.array(idx) 

array([[2, 3, 4], 
     [3, 4, 5], 
     [4, 5, 6], 
     [5, 6, 7]]) 

Поскольку каждый arange имеет ту же длину, idx могут быть получены без итерации:

col_start = np.array([2,3,4,5]) 
idx = col_start[:,None] + np.arange(3) 

Первый индекс представляет собой массив столбец, который транслирует, чтобы соответствовать этому idx.

np.arange(A.shape[0])[:,None] 
array([[0], 
     [1], 
     [2], 
     [3]]) 

С этим A и idx я получаю следующие тайминги:

In [515]: timeit np.choose(idx,A.T[:,:,None]) 
10000 loops, best of 3: 30.8 µs per loop 

In [516]: timeit A[np.arange(A.shape[0])[:,None],idx] 
100000 loops, best of 3: 10.8 µs per loop 

In [517]: timeit A.flat[idx+np.arange(A.shape[0])[:,None]*A.shape[1]] 
10000 loops, best of 3: 24.9 µs per loop 

flat индексация происходит быстрее, но вычисления индекса любитель занимает некоторое время.

Для больших массивов доминирует скорость индексации flat.

A=np.arange(4000).reshape(40,100)*.1 
col_start=np.arange(20,60) 
idx=col_start[:,None]+np.arange(30) 

In [536]: timeit A[np.arange(A.shape[0])[:,None],idx] 
10000 loops, best of 3: 108 µs per loop 

In [537]: timeit A.flat[idx+np.arange(A.shape[0])[:,None]*A.shape[1]] 
10000 loops, best of 3: 59.4 µs per loop 

np.choose метод работает в закодированный предел: Need between 2 and (32) array objects (inclusive).


Что из границ idx?

col_start=np.array([2,4,6,8]) 
idx=col_start[:,None]+np.arange(3) 
A[np.arange(A.shape[0])[:,None], idx] 

выдает ошибку, потому что последний idx значение 10, слишком велик.

Вы могли clipidx

idx=idx.clip(0,A.shape[1]-1) 

производить повторяющиеся значения в последней строке

[ 3.8, 3.9, 3.9] 

Вы могли бы также площадку A перед индексированием. Дополнительную информацию см. В разделе np.pad.

np.pad(A,((0,0),(0,2)),'edge')[np.arange(A.shape[0])[:,None], idx] 

Другим вариантом является удаление значений за пределами границ. idx тогда станет оборванным списком списков (или массивом списков). Подход flat может справиться с этим, хотя результат не будет матрицей.

startend = [[2,5],[4,7],[6,9],[8,10]] 
index_list = [np.arange(v[0],v[1]) + i*A.shape[1] 
       for i,v in enumerate(startend)] 
# [array([2, 3, 4]), array([14, 15, 16]), array([26, 27, 28]), array([38, 39])] 

A.flat[np.r_[tuple(index_list)]] 
# array([ 0.2, 0.3, 0.4, 1.4, 1.5, 1.6, 2.6, 2.7, 2.8, 3.8, 3.9]) 
+0

Считаете ли вы, что использование понимания списка будет быстрее, чем просто использовать цикл for? – recodeFuture

+0

Для диапазонов постоянной длины вам не нужна никакая итерация - просто сложение матрицы. – hpaulj

+0

Спасибо за ваш ответ и тайминги. – recodeFuture

1

Я думаю, что вы ищете что-то вроде ниже. Я не уверен, что вы хотите с ними делать, когда вы обращаетесь к ним.

indexes = [(4,6), (0,2), (2,4), (8, 10)] 
arr = [ 
    [ . . . . | | | . . . . . ], 
    [ | | | . . . . . . . . . ], 
    [ . . | | | . . . . . . . ], 
    [ . . . . . . . . | | | . ] 
] 

for x in zip(indexes, arr): 
    index = x[0] 
    row = x[1] 
    print row[index[0]:index[1]+1] 
+0

проблема только в том, что у вас нет массива numpy –

+0

Я хочу найти максимальное значение для элементов «masked» в каждой строке. Решение для доступа к этим элементам было бы простым, если бы столбцы были одинаковыми для всех строк: my_array [:, col_start: col_end]. То, что я искал, было модификацией предыдущего утверждения в случае разных индексов столбцов. – recodeFuture

+0

Где находится массив numpy? OP ничего не говорит об этом? И @tjons: ничего в моем ответе не есть словарь? – dursk

3

Вы можете использовать np.choose.

Вот пример NumPy массив arr:

array([[ 0, 1, 2, 3, 4, 5, 6], 
     [ 7, 8, 9, 10, 11, 12, 13], 
     [14, 15, 16, 17, 18, 19, 20]]) 

Допустим, мы хотим, чтобы выбрать значения [1, 2, 3] из первого ряда, [11, 12, 13] из второго ряда и [17, 18, 19] из третьего ряда.

Другими словами, мы будем выбирать индексы из каждой строки arr, как показано в массиве idx:

array([[1, 2, 3], 
     [4, 5, 6], 
     [3, 4, 5]]) 

Затем с помощью np.choose:

>>> np.choose(idx, arr.T[:,:,np.newaxis]) 
array([[ 1, 2, 3], 
     [11, 12, 13], 
     [17, 18, 19]]) 

Объяснить что только что произошло: arr.T[:,:,np.newaxis] означает, что arr был временно рассмотрен как 3D-массив с формой (7, 3, 1). Вы можете представить это как 3D-массив, где каждый столбец исходного arr теперь представляет собой двумерный вектор-столбец с тремя значениями. 3D массив выглядит немного как это:

# 0  1  2  3  4  5  6 
[[ 0] [[ 1] [[ 2] [[ 3] [[ 4] [[ 5] [[ 6] # choose values from 1, 2, 3 
[ 7] [ 8] [ 9] [10] [11] [12] [13] # choose values from 4, 5, 6 
[14]] [15]] [16]] [17]] [18]] [19]] [20]] # choose values from 3, 4, 5 

Чтобы получить нулевую строки выходного массива, choose выбирает нулевой элемента из столбца 2D по индексу 1, в нулевого элемент из 2D столбца при индексе 2 и нулевой элемент из 2D столбца при индексе 3.

Чтобы получить первую строку выходного массива, choose выбирает первый элемент из колонки с индексом 2D 4, в первый элемент из колонки 2D с индексом 5, ... и так далее ,

+0

Спасибо, это похоже на то, о чем я думал. Теперь я должен проверить производительность данных решений. – recodeFuture

+0

У меня есть еще один вопрос. Каков наилучший способ создания массива idx, если у меня есть вектор col_start и вектор col_end равно (col_start + n)? – recodeFuture

+0

@soccersniper: один способ может заключаться в использовании 'np.vstack' и понимания списка, например. 'np.vstack ([np.arange (x, x + n) для x в col_start])'. Итак, выше в моем примере, 'n' является' 3' и 'col_start' является' [1, 4, 3] '. –

Смежные вопросы