我有一个numpy数组:
m = array([[4, 0, 9, 0],
[0, 7, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 5]])
m的4列标为:
c = array([ 10, 20, 30, 40])
我希望能够切片一个对象o
,这样:
o.vals[0,:] = array([4, 9])
o.vals[1,:] = array([7,])
o.vals[2,:] = array([])
o.vals[3,:] = array([5])
o.cols[0,:] = array([10, 30] )# the non-zero column labels from row 0
o.cols[1,:] = array([20,])
o.cols[2,:] = array([])
o.cols[3,:] = array([40])
是否有一个现有的Python对象可以让我这样做?
我已经看过Scipy稀疏矩阵,但它不是我所寻找的。
2015年8月17日的更新:我已经玩了一些想法,并提出了这个,这几乎与我上周描述的相同:
- https://github.com/jsphon/NumericalFunctions/blob/master/jagged_array/JaggedKeyValueArray.rst
- https://github.com/jsphon/NumericalFunctions/blob/master/jagged_array/jagged_key_value_array.py
你可以通过定义一个包含m
和c
的类来接近你想要的:
import numpy as np
class O(object):
def __init__(self, m, c):
self.m, self.c = m, c
def vals(self, i):
return self.m[i][self.m[i]!=0]
def cols(self, i):
return self.c[self.m[i]!=0]
m = np.array([[4, 0, 9, 0],
[0, 7, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 5]])
c = np.array([ 10, 20, 30, 40])
o = O(m, c)
for i in range(4):
print 'o.vals({0:d}) = {1}'.format(i, o.vals(i))
for i in range(4):
print 'o.cols({0:d}) = {1}'.format(i, o.cols(i))
的回报:
o.vals(0) = [4 9]
o.vals(1) = [7]
o.vals(2) = []
o.vals(3) = [5]
o.cols(0) = [10 30]
o.cols(1) = [20]
o.cols(2) = []
o.cols(3) = [40]
(直接使用索引m[i][m[i]!=0
和c[m[i]!=0]
可能更容易)
您可以使用pandas
(http://pandas.pydata.org/)。(因为你尝试了scipy/numpy
,这不是标准库Python包,我认为建议另一个包是可以的)。
DataFrame
是一个对象,它可以让你完成所有的操作,甚至更多。
import numpy as np
import pandas as pd
m = array([[4, 0, 9, 0], [0, 7, 0, 0], [0, 0, 0, 0], [0, 0, 0, 5]])
# create a dataframe
df = pd.DataFrame(m, columns=[10,20,30,40])
# replace 0 with NaN (to make use of pandas `dropna`)
df.replace(0, np.NaN, inplace=True)
# values per row
df.irow(0).dropna().as_matrix()
array([ 4., 9.])
df.irow(1).dropna().as_matrix()
array([ 7.])
df2.irow(2).dropna().as_matrix()
array([], dtype=float64)
# column labels (as list)
df.irow(1).dropna().index.tolist()
[10, 30]
# or non-zero values per column?
df.icol(0).dropna().as_matrix()
array([ 4.])
# ...
您也可以组合列标签和值,因为dropna
的正常返回是一个DataFrame。
non_zero_1 = df.irow(0).dropna()
labels_1 = non_zero_1.index
Int64Index([10, 30], dtype='int64')
最好试试Pandas,看看它是否符合你的需求。也可以看一下精彩的介绍(http://pandas.pydata.org/pandas-docs/stable/10min.html)
你可以用CSR稀疏矩阵来接近你想要的:
import scipy.sparse as sps
m_csr = sps.csr_matrix(m)
你现在可以实现类似于你所追求的函数,像这样:
def vals(sps_mat, row):
row_slice = slice(sps_mat.indptr[row], sps_mat.indptr[row+1])
return sps_mat.data[row_slice]
def cols(sps_mat, col_labels, row):
col_labels = np.asarray(col_labels)
row_slice = slice(sps_mat.indptr[row], sps_mat.indptr[row+1])
return col_labels[sps_mat.indices[row_slice]]
使用这个函数,我们得到:
>>> for row in range(m_csr.shape[0]):
... print vals(m_csr, row)
...
[4 9]
[7]
[]
[5]
>>> for row in range(m_csr.shape[0]):
... print cols(m_csr, [10, 20, 30, 40], row)
...
[10 30]
[20]
[]
[40]
这对于大的矩阵是非常有效的,尽管语法不是你想要的。
您可以使用嵌套类并重载对象的__getitem__
属性:
import numpy as np
class indexer:
def __init__(self,arr):
self.arr=arr
self.d=self.caldict(self.arr)
self.vals=self.values(self.arr,self.d)
self.cols=self.columns(self.d)
def caldict(self,arr,dd={}):
inds=np.array(np.nonzero(arr)).T
for i,j in inds:
dd.setdefault(i,[]).append(j)
return dd
class values:
def __init__(self,arr,d):
self.arr=arr
self.d=d
def __getitem__(self,index):
try:
return self.arr.take(index,axis=0)[self.d[index]]
except KeyError:
return []
class columns:
def __init__(self,d):
self.d=d
self.c=np.array([ 10, 20, 30, 40])
def __getitem__(self,index):
try:
return self.c.take(self.d[index])
except KeyError:
return []
演示:m=np.array([[4, 0, 9, 0],
[0, 7, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 5]])
o=indexer(m)
print o.vals[0],'n',o.vals[1],'n',o.vals[2],'n',o.vals[3]
print '------------------'
print o.cols[0],'n',o.cols[1],'n',o.cols[2],'n',o.cols[3]
[4 9]
[7]
[]
[5]
------------------
[10 30]
[20]
[]
[40]