我如何“稀疏化”两个价值观?

时间:2016-11-14 17:29:34

标签: python pandas numpy scipy sparse-matrix

考虑一下大熊猫系列s

n = 1000
s = pd.Series([0] * n + [1] * n, dtype=int)

s.memory_usage()

8080

我可以使用to_sparse

“稀疏化”这一点
s.to_sparse(fill_value=0).memory_usage()

4080

但我只有两种类型的整数。我想我可以两次稀疏化。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:3)

由于您使用scipy对此进行了标记,因此我会向您展示scipy.sparse矩阵的内容:

In [31]: n=100
In [32]: arr=np.array([[0]*n+[1]*n],int)
In [33]: M=sparse.csr_matrix(arr)
In [34]: M.data
Out[34]: 
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1], dtype=int32)
In [35]: M.indices
Out[35]: 
array([100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
       113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
       126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
       139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
       152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
       165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
       178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
       191, 192, 193, 194, 195, 196, 197, 198, 199], dtype=int32)
In [36]: M.indptr
Out[36]: array([  0, 100], dtype=int32)

它已将n arr元素替换为2个数组,每个数组都包含n/2个元素。即使我将int替换为uint8M.indices数组仍然是int32

你的pandas版本有一半的内存使用量,这表明它只是存储索引,有些人注意到data部分都是1。但这只是猜测。

您期望有多大的分裂?

====================

http://pandas.pydata.org/pandas-docs/stable/sparse.html

这个例子看起来像是pandas正在实施某种类型的'运行'压缩:

In [4]: sts
Out[4]: 
0    0.469112
1   -0.282863
2         NaN
3         NaN
4         NaN
5         NaN
6         NaN
7         NaN
8   -0.861849
9   -2.104569
dtype: float64
BlockIndex
Block locations: array([0, 8], dtype=int32)
Block lengths: array([2, 2], dtype=int32)

它确定了2个区块,每个区块长度为2。它仍然必须将4个非填充值存储在某个数组中。

csr稀疏等价物(对于行数组):

In [1052]: arr=np.random.rand(10)
In [1053]: arr[2:-2]=0
In [1055]: M=sparse.csr_matrix(arr)
In [1056]: M
Out[1056]: 
<1x10 sparse matrix of type '<class 'numpy.float64'>'
    with 4 stored elements in Compressed Sparse Row format>
In [1057]: M.data
Out[1057]: array([ 0.37875012,  0.73703368,  0.7935645 ,  0.22948213])
In [1058]: M.indices
Out[1058]: array([0, 1, 8, 9], dtype=int32)
In [1059]: M.indptr
Out[1059]: array([0, 4], dtype=int32)

如果填充值出现在块中,则pandas版本可能更紧凑。但我怀疑

0         1.0
1         1.0
2         NaN
3         NaN
4         NaN
5         NaN
6         NaN
7         NaN
8         1.0
9         1.0

将产生相同的块。我没有看到证据表明它正在尝试识别相同的1.0值,并将其存储为值加上计数。

=====

基于@MaxU回答您的ds存储1000 1's,以及两个单元素数组,告诉它存储这些值的位置。

In [56]: sp.memory_usage()
Out[56]: 1080

In [57]: sp.sp_index
Out[57]:
BlockIndex
Block locations: array([1000])
Block lengths: array([1000])

只要非填充值出现在大运行中,block数组就会很小。但是,如果你将这1000个值分散到整个系列中,你就可以将块数基本上相乘

 block locations: array([1,3,6,10,...])
 block lengths: array([1,1,1,2,1,...])

我可以想象csr布局和熊猫块之间的映射,但是没有计算出细节。 csr布局适用于2d数组,具有明确的行和列概念。看起来稀疏数据帧只包含稀疏系列对象。

===================

https://stackoverflow.com/a/38157234/901925显示了如何从稀疏数据帧值映射到scipy稀疏矩阵。对于每个列(数据系列),它使用sp_valuesfill_valuesp_index

pandas/pandas/sparse/scipy_sparse.py包含scipy稀疏和数据系列之间的交互代码。

===================

kind='integer' produces sparse structure more like scipy.sparse`:

In [62]: n=5; s=pd.Series([0]*5+[1]*5, dtype=int)
In [63]: ss=s.to_sparse(fill_value=0, kind='integer')
In [64]: ss
Out[64]: 
0    0
1    0
2    0
3    0
4    0
5    1
6    1
7    1
8    1
9    1
dtype: int32
IntIndex
Indices: array([5, 6, 7, 8, 9])

将其与默认block

进行对比
dtype: int32
BlockIndex
Block locations: array([5])
Block lengths: array([5])

等效列稀疏矩阵可以用:

构建
In [89]: data=ss.values
In [90]: data=ss.sp_values
In [91]: rows=ss.sp_index.indices
In [92]: cols=np.zeros_like(rows)
In [93]: sparse.csr_matrix((data,(rows,cols)))
Out[93]: 
<10x1 sparse matrix of type '<class 'numpy.int32'>'
    with 5 stored elements in Compressed Sparse Row format>

有一个to_coo方法,但它只适用于更复杂的pd.MultiIndex对象(为什么?)。

答案 1 :(得分:3)

Pandas documentation说:

  

目前,支持int64boolbool dtypes。

所以让我们尝试将您的系列转换为In [53]: s.memory_usage() Out[53]: 8080 In [54]: s.to_sparse().memory_usage() Out[54]: 4080 In [55]: sp = s.astype(bool).to_sparse() In [56]: sp.memory_usage() Out[56]: 1080 In [57]: sp.sp_index Out[57]: BlockIndex Block locations: array([1000]) Block lengths: array([1000]) 值:

dat$episode <- with(dat, ave(as.character(category), category, FUN = seq_along))