2016-09-07 3 views
1

Я получил (нормализованную) разреженную матрицу смежности и список меток для соответствующих строк матрицы. Поскольку некоторые узлы были удалены другой функцией санитизации, в матрице есть несколько строк, содержащих NaN. Я хочу найти эти строки и удалить их , а также их соответствующих лейблов. Вот функция, я писал:Удалите ряды nan в scipy разреженной матрице

def sanitize_nan_rows(adj, labels): 
    # convert to numpy array and keep dimension 
    adj = np.array(adj, ndmin=2) 

    for i, row in enumerate(adj): 
     # check if row all nans 
     if np.all(np.isnan(row)): 
      # print("Removing nan row label in %s" % i) 
      # remove row index from labels 
      del labels[i] 
    # remove all nan rows 
    adj = adj[~np.all(np.isnan(adj), axis=1)] 
    # return sanitized adj and labels_clean 
    return adj, labels 

labels простой список Python и adj имеет тип <class 'scipy.sparse.lil.lil_matrix'> (содержащий элементы типа <class 'numpy.float64'>), которые одновременно являются результатом

adj, labels = nx.attr_sparse_matrix(infected, normalized=True) 

На исполнение I получите следующую ошибку:

--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-503-8a404b58eaa9> in <module>() 
----> 1 adj, labels = sanitize_nans(adj, labels) 

<ipython-input-502-ead99efec677> in sanitize_nans(adj, labels) 
     6  for i, row in enumerate(adj): 
     7   # check if row all nans 
----> 8   if np.all(np.isnan(row)): 
     9    print("Removing nan row label in %s" % i) 
    10    # remove row index from labels 

TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe'' 

Так что я думал, что SciPy NaNs отличаются от numpy NaNs. После этого я попытался преобразовать разреженную матрицу в массив numpy (рискуя затопить мою RAM, потому что матрица имеет около 40k строк и столбцов). При его запуске ошибка остается прежней. Кажется, что np.array() вызова просто обернута разреженная матрица и не превратить ее, как type(row) внутри цикл по-прежнему выводит <class 'scipy.sparse.lil.lil_matrix'>

Так что мой вопрос заключается в том, чтобы решить эту проблему, и есть ли лучший подход, который получает Работа выполнена. Я довольно новичок в numpy и scipy (как используется в networkx), поэтому я буду благодарен за объяснение. Спасибо!

EDIT: После изменения преобразования к тому, что hpaulj предложил, я получаю MemoryError:

--------------------------------------------------------------------------- 
MemoryError        Traceback (most recent call last) 
<ipython-input-519-8a404b58eaa9> in <module>() 
----> 1 adj, labels = sanitize_nans(adj, labels) 

<ipython-input-518-44201f4ff35c> in sanitize_nans(adj, labels) 
     1 def sanitize_nans(adj, labels): 
----> 2  adj = adj.toarray() 
     3 
     4  for i, row in enumerate(adj): 
     5   # check if row all nans 

/usr/lib/python3/dist-packages/scipy/sparse/lil.py in toarray(self, order, out) 
    348  def toarray(self, order=None, out=None): 
    349   """See the docstring for `spmatrix.toarray`.""" 
--> 350   d = self._process_toarray_args(order, out) 
    351   for i, row in enumerate(self.rows): 
    352    for pos, j in enumerate(row): 

    /usr/lib/python3/dist-packages/scipy/sparse/base.py in_process_toarray_args(self, order, out) 
    697    return out 
    698   else: 
--> 699    return np.zeros(self.shape, dtype=self.dtype, order=order) 
    700 
    701 

MemoryError: 

Так, по-видимому, мне придется придерживаться разреженной матрицы для сохранения памяти.

+0

Редкая матрица не является плотным массивом. Посмотрите на 'adj.data' и' adj.rows'. Для матрицы 'lil' это массивы объектов списка, одна пара подсписок для каждой строки массива. – hpaulj

+0

'adj.A' или' adj.toarray() 'производит массив – hpaulj

+0

Спасибо за ваш быстрый ответ! Я отредактировал вопрос в соответствии с вашими предложенными изменениями и моими результатами. (Я просто изменил строку преобразования на 'adj = adj.toarray()') – dmuhs

ответ

0

Если я делаю массив образца:

In [328]: A=np.array([[1,0,0,np.nan],[0,np.nan,np.nan,0],[1,0,1,0]]) 
In [329]: A 
Out[329]: 
array([[ 1., 0., 0., nan], 
     [ 0., nan, nan, 0.], 
     [ 1., 0., 1., 0.]]) 

In [331]: M=sparse.lil_matrix(A) 

Эта лил разреженная матрица хранится в 2-х массивов:

In [332]: M.data 
Out[332]: array([[1.0, nan], [nan, nan], [1.0, 1.0]], dtype=object) 
In [333]: M.rows 
Out[333]: array([[0, 3], [1, 2], [0, 2]], dtype=object) 

С вашей функции, строки не будут удалены, даже если средний ряд разреженной матрицы содержит только nan.

In [334]: A[~np.all(np.isnan(A), axis=1)] 
Out[334]: 
array([[ 1., 0., 0., nan], 
     [ 0., nan, nan, 0.], 
     [ 1., 0., 1., 0.]]) 

я мог проверить строки M для nan, и определить те, которые содержат только nan (помимо 0s). Но, вероятно, легче собрать те, которые мы хотим сохранить.

In [346]: ll = [i for i,row in enumerate(M.data) if not np.all(np.isnan(row))] 
In [347]: ll 
Out[347]: [0, 2] 
In [348]: M[ll,:] 
Out[348]: 
<2x4 sparse matrix of type '<class 'numpy.float64'>' 
    with 4 stored elements in LInked List format> 
In [349]: _.A 
Out[349]: 
array([[ 1., 0., 0., nan], 
     [ 1., 0., 1., 0.]]) 

Ряд M список, но np.isnan(row) преобразует его в массив и сделать это тест массив.

+0

Это очень помогло! Я соответствующим образом адаптировал свой код. Я также нарезал 'adj = adj [ll,:] [:, ll]', чтобы сохранить симметрию матрицы смежности. Однако либо этот, либо список индексов 'll', похоже, наводняют мою оперативную память. Есть ли более эффективный способ сделать это? Матрица имеет примерно 40 тыс. Строк и столбцов. – dmuhs

+0

Индексирование строк 'lil' является эффективным, но удаление столбцов будет беспорядочным, требующим изменений для каждого подмассива. Мне нужно будет посмотреть его код, чтобы посмотреть, как работают столбцы. – hpaulj