我如何 "sparsify" 两个值?
How can I "sparsify" on two values?
考虑 pandas 系列 s
n = 1000
s = pd.Series([0] * n + [1] * n, dtype=int)
s.memory_usage()
8080
我可以 "sparsify" 使用 to_sparse
s.to_sparse(fill_value=0).memory_usage()
4080
但是我只有两种整数。我想我可以稀疏化两次。有办法吗?
既然你用 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)
它用 2 个数组替换了 arr
的 n
个元素,每个数组都有 n/2
个元素。即使我将 int
替换为 uint8
,M.indices
数组仍将是 int32
.
事实上,您的 pandas
版本有一半的内存使用,这表明它只是存储索引,以及如何注意到 data
部分全为 1。但这只是一个猜测。
您期望稀疏度提高多少?
====================
http://pandas.pydata.org/pandas-docs/stable/sparse.html
这个例子看起来 pandas 正在实施某种 'run' 压缩:
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
布局和 pandas 块之间的映射,但还没有弄清楚细节。 csr
布局用于二维数组,具有清晰的行和列概念。看起来稀疏数据框只包含稀疏系列对象。
===================
显示如何从稀疏数据帧值映射到 scipy 稀疏矩阵。对于每一列(数据系列),它使用 sp_values
、fill_value
、sp_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
对象(为什么?)。
Currently, float64
, int64
and bool
dtypes are supported.
所以让我们尝试将您的系列转换为 bool
值:
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])
考虑 pandas 系列 s
n = 1000
s = pd.Series([0] * n + [1] * n, dtype=int)
s.memory_usage()
8080
我可以 "sparsify" 使用 to_sparse
s.to_sparse(fill_value=0).memory_usage()
4080
但是我只有两种整数。我想我可以稀疏化两次。有办法吗?
既然你用 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)
它用 2 个数组替换了 arr
的 n
个元素,每个数组都有 n/2
个元素。即使我将 int
替换为 uint8
,M.indices
数组仍将是 int32
.
事实上,您的 pandas
版本有一半的内存使用,这表明它只是存储索引,以及如何注意到 data
部分全为 1。但这只是一个猜测。
您期望稀疏度提高多少?
====================
http://pandas.pydata.org/pandas-docs/stable/sparse.html
这个例子看起来 pandas 正在实施某种 'run' 压缩:
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
布局和 pandas 块之间的映射,但还没有弄清楚细节。 csr
布局用于二维数组,具有清晰的行和列概念。看起来稀疏数据框只包含稀疏系列对象。
===================
sp_values
、fill_value
、sp_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
对象(为什么?)。
Currently,
float64
,int64
andbool
dtypes are supported.
所以让我们尝试将您的系列转换为 bool
值:
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])