Я пишу функцию, которая извлекает верхние значения x из разреженного вектора (меньше значений, если их меньше x). Я хотел бы включить опцию "на месте", как и многие функции, где ...

1
amquack 30 Дек 2020 в 02:31

1 ответ

Лучший ответ

Вы действительно не хотите зацикливаться на периоде. Перераспределение этих массивов на каждой итерации цикла с помощью .eliminate_zeros() - самая медленная вещь, но не единственная причина, по которой этого не делать.

import numpy as np
from scipy.sparse import csr_matrix

max_loc=20
data=[1,3,3,2,5]
rows=[0]*len(data)
indices=[4,2,8,12,7]

sparse_test=csr_matrix((data, (rows,indices)), shape=(1,max_loc))

Что-то вроде этого было бы лучше:

def top_x_in_sparse(in_vect,top_x,inplace=False):
    
    n = len(in_vect.data)
    
    if top_x >= n:
        if inplace:
            out_data = in_vect.data.tolist()
            in_vect.data = np.array([], dtype=in_vect.data.dtype)
            in_vect.indices = np.array([], dtype=in_vect.indices.dtype)
            in_vect.indptr = np.array([0, 0], dtype=in_vect.indptr.dtype)
            return out_data
        else:
            return in_vect.data.tolist()
        
    else:
        k = n - top_x
        partition_idx = np.argpartition(in_vect.data, k)

        if inplace:
            out_data = in_vect.data[partition_idx[k:n]].tolist()
            in_vect.data = in_vect.data[partition_idx[0:k]]
            in_vect.indices = in_vect.indices[partition_idx[0:k]]
            in_vect.indptr = np.array([0, len(in_vect.data)], dtype=in_vect.indptr.dtype)            
            return out_data
        else:
            return in_vect.data[partition_idx[k:n]].tolist()
    

Если вам нужно отсортировать возвращаемые значения, вы, конечно, тоже можете это сделать.

a=top_x_in_sparse(sparse_test,3,inplace=False)

>>> print(a)
[3, 5, 3]

>>> print(sparse_test)
  (0, 2)    3
  (0, 4)    1
  (0, 7)    5
  (0, 8)    3
  (0, 12)   2

b=top_x_in_sparse(sparse_test,3,inplace=True)

>>> print(b)
[3, 5, 3]

>>> print(sparse_test)
  (0, 4)    1
  (0, 12)   2

Также согласно вашему вопросу из комментариев: мелкая копия объекта разреженного массива не будет копировать массивы numpy, содержащие данные. Разреженный объект имеет ссылку только на эти объекты. Глубокая копия получит их, но использование встроенного метода копирования уже позаботится о том, чтобы знать, какие вещи, на которые есть ссылки, нужно скопировать, а какие нет.

1
CJR 31 Дек 2020 в 18:01