2

У меня есть большой 2D-массив, который я бы хотел объявить один раз, и изменил значение только значений в зависимости от параметра, не пересекая весь массив.Python lazy оценка numpy ndarray

Чтобы построить этот массив, я подклассифицировал класс numpy ndarray с помощью dtype=object и назначил элементам, которые я хочу изменить, например. :

def f(parameter): 
    return parameter**2 

for i in range(np.shape(A)[0]): 
    A[i,i]=f 
    for j in range(np.shape(A)[0]): 
     A[i,j]=1. 

Я затем переопределен метод __getitem__ так, что он возвращает оценку функции с заданным параметром, если она является вызываемой, в противном случае возвращает само значение.

def __getitem__(self, key): 
     value = super(numpy.ndarray, self).__getitem__(key) 
     if callable(value): 
      return value(*self.args) 
     else: 
      return value 

, где self.args ранее были приведены к экземпляру MyClass.

Тем не менее, мне нужно работать с массивами с плавающей точкой в ​​конце, и я не могу просто преобразовать этот массив в массив с помощью этой техники. Я также попытался использовать виды numpy, которые не работают ни для dtype=object.

У вас есть альтернатива? Должен ли я переопределить метод view, а не getitem?

Редактировать Возможно, мне придется использовать Cython в будущем, поэтому, если у вас есть решение, включающее, например, C указатели, мне интересно.

+0

Это интересный подход, но я не уверен, что для него подходят массивы numpy. В общем случае, когда вы работаете с numpy, вы должны использовать векторизованные операции с использованием полных массивов или срезов, а не по элементам доступа. Подклассифицируя ndarrays так, как вы, вы по существу теряете все преимущества быстрых операций numpy. Возможно, вам лучше просто создать свой собственный класс с нуля и сохранить все, в чистые структуры python (списки и т. Д.). Показательно, что это будет сопоставимо. Зачем вам нужна ленивая оценка? Вы можете эффективно изменять только некоторые элементы с помощью фантазийной индексации. – rth

+1

У вас есть только одна функция 'f'? С постоянными аргументами? –

+1

Вы знакомы с 'scipy.sparse'? Формат 'dok' - это словарь, с ключом' (i, j) 'tuple. Это и 'lil' (список списков) являются двумя наиболее быстрыми способами доступа к/изменения выбранных элементов. – hpaulj

ответ

1

В этом случае не нужно связывать функцию преобразования с каждым индексом вашего массива.

Вместо этого более эффективным подходом было бы определить преобразование как функцию вместе с подмножеством массива, к которому оно относится. Вот базовая реализация,

import numpy as np 

class LazyEvaluation(object): 
    def __init__(self): 
     self.transforms = [] 

    def add_transform(self, function, selection=slice(None), args={}): 
     self.transforms.append((function, selection, args)) 

    def __call__(self, x): 
     y = x.copy() 
     for function, selection, args in self.transforms: 
      y[selection] = function(y[selection], **args) 
     return y 

, которые могут быть использованы следующим образом:

x = np.ones((6, 6))*2 

le = LazyEvaluation() 
le.add_transform(lambda x: 0, [[3], [0]]) # equivalent to x[3,0] 
le.add_transform(lambda x: x**2, (slice(4), slice(4,6))) # equivalent to x[4,4:6] 
le.add_transform(lambda x: -1, np.diag_indices(x.shape[0], x.ndim),) # setting the diagonal 
result = le(x) 
print(result) 

, который печатает,

array([[-1., 2., 2., 2., 4., 4.], 
     [ 2., -1., 2., 2., 4., 4.], 
     [ 2., 2., -1., 2., 4., 4.], 
     [ 0., 2., 2., -1., 4., 4.], 
     [ 2., 2., 2., 2., -1., 2.], 
     [ 2., 2., 2., 2., 2., -1.]]) 

Таким образом, вы можете легко поддерживать все передовые индексацию Numpy (элемент по доступ к элементам, нарезка, удобная индексация и т. д.), в то же время сохраняя ваши данные в массиве с собственным типом данных (float, int и т. д.) whi ch намного эффективнее, чем использование dtype='object'.

+0

Спасибо, я реализовал это в основном как подкласс dict, и он работает практически так, как я хочу. Однако, как любопытство, я хотел бы знать, можно ли реализовать нечто подобное в C/C++ с указателями гораздо более элегантным способом? Например, можно было бы объявить таблицу указателей (float), а во время объявления каждый указатель направил бы либо нуль, либо результат функции, чтобы я мог обновить матрицу, просто вызвав одну (или несколько) функцию. – Damlatien

+0

Но для этого вызов вызова функции должен быть привязан к одному конкретному указателю, и я не уверен, что это выполнимо. Надеюсь, я был достаточно ясен. – Damlatien

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