更改SparseDataFrame中的fill_values - 替换throws TypeError

cs9*_*s95 14 python sparse-matrix pandas sparse-dataframe

目前的熊猫版: 0.22


我有一个SparseDataFrame.

A = pd.SparseDataFrame(
    [['a',0,0,'b'],
     [0,0,0,'c'],
     [0,0,0,0],
     [0,0,0,'a']])
Run Code Online (Sandbox Code Playgroud)

A

   0  1  2  3
0  a  0  0  b
1  0  0  0  c
2  0  0  0  0
3  0  0  0  a
Run Code Online (Sandbox Code Playgroud)

现在,填充值是0.但是,我想将fill_values更改为np.nan.我的第一直觉是打电话replace:

A.replace(0, np.nan)
Run Code Online (Sandbox Code Playgroud)

但这给了

TypeError: cannot convert int to an sparseblock
Run Code Online (Sandbox Code Playgroud)

这并没有真正帮助我理解我做错了什么.

我知道我能做到

A.to_dense().replace(0, np.nan).to_sparse()
Run Code Online (Sandbox Code Playgroud)

但有更好的方法吗?或者我对稀疏数据帧的基本理解存在缺陷?

Qus*_*man 15

tl;博士:这绝对是一个错误.
但请继续阅读,还有更多......

所有以下工作都适用于pandas 0.20.3,但不适用于任何较新的版本:

A.replace(0,np.nan)
A.replace({0:np.nan})
A.replace([0],[np.nan])
Run Code Online (Sandbox Code Playgroud)

等......(你明白了).

(从现在开始,所有代码都是用pandas 0.20.3完成的).

然而,那些(以及我尝试过的大多数解决方法)都有效,因为我们不小心做错了什么.如果我们这样做,你会马上猜到:

A.density

1.0
Run Code Online (Sandbox Code Playgroud)

这个SparseDataFrame实际上是密集的!
我们可以通过传递修复此问题default_fill_value=0:

A = pd.SparseDataFrame(
     [['a',0,0,'b'],
     [0,0,0,'c'],
     [0,0,0,0],
     [0,0,0,'a']],default_fill_value=0)
Run Code Online (Sandbox Code Playgroud)

现在A.density将按0.25预期输出.

发生这种情况是因为初始化程序无法推断列的dtypes.引自熊猫文档:

稀疏数据应与其密集表示具有相同的dtype.目前,支持float64,int64和bool dtypes.根据原始dtype,fill_value默认更改:

  • float64:np.nan
  • int64:0
  • 布尔:错了

但我们的SparseDataFrame的dtypes是:

A.dtypes

0    object
1    object
2    object
3    object
dtype: object
Run Code Online (Sandbox Code Playgroud)

这就是为什么SparseDataFrame无法决定使用哪个填充值,因此使用了默认值np.nan.

好的,现在我们有一个SparseDataFrame.让我们尝试替换其中的一些条目:

A.replace('a','z')
    0   1   2   3
0   z   0   0   b
1   0   0   0   c
2   0   0   0   0
3   0   0   0   z
Run Code Online (Sandbox Code Playgroud) 奇怪的是:
A.replace(0,np.nan)
    0   1   2   3
0   a   0   0   b
1   0   0   0   c
2   0   0   0   0
3   0   0   0   a
正如你所看到的,这是不正确的!
根据我自己对不同版本的熊猫的实验,它似乎SparseDataFrame.replace()仅适用于非填充值.要更改填充值,您有以下选项:

  • 根据pandas docs,如果你改变dtypes,那将自动改变填充值.(这对我不起作用).
  • 转换成密集DataFrame,做替换,然后转换回SparseDataFrame.
  • 手动重建一个新的SparseDataFrame,如Wen的答案,或者将default_fill_valueset 传递给新的填充值.

当我在尝试最后一个选项时,发生了一些更奇怪的事情:

B = pd.SparseDataFrame(A,default_fill_value=np.nan)

B.density
0.25

B.default_fill_value
nan
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.但......:

B
    0   1   2   3
0   a   0   0   b
1   0   0   0   c
2   0   0   0   0
3   0   0   0   a
Run Code Online (Sandbox Code Playgroud)

起初这让我很震惊.这甚至可能!?
继续,我试着看看列中发生了什么:

B[0]

0    a
1    0
2    0
3    0
Name: 0, dtype: object
BlockIndex
Block locations: array([0], dtype=int32)
Block lengths: array([1], dtype=int32)
Run Code Online (Sandbox Code Playgroud)

object的dtype 是,但BlockIndex与之关联的dtype 是int32,因此是奇怪的行为.
还有更多"奇怪"的事情发生,但我会在这里停下来.
从以上所有,我可以说你应该避免使用SparseDataFrame直到完全重写它发生:).


WeN*_*Ben 6

这就是我所尝试过的

pd.SparseDataFrame(np.where(A==0, np.nan, A))

     0    1    2    3
0    a  NaN  NaN    b
1  NaN  NaN  NaN    c
2  NaN  NaN  NaN  NaN
3  NaN  NaN  NaN    a
Run Code Online (Sandbox Code Playgroud)