更改SparseDataFrame中的fill_values - 替换throws TypeError

时间:2018-01-09 04:28:47

标签: python pandas sparse-matrix sparse-dataframe

当前的pandas版本:0.22

我有一个SparseDataFrame。

A = pd.SparseDataFrame(
    [['a',0,0,'b'],
     [0,0,0,'c'],
     [0,0,0,0],
     [0,0,0,'a']])

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

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

A.replace(0, np.nan)

但是这给了

TypeError: cannot convert int to an sparseblock

这并不能帮助我理解我做错了什么。

我知道我能做到

A.to_dense().replace(0, np.nan).to_sparse()

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

2 个答案:

答案 0 :(得分:14)

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

以下所有内容适用于pandas 0.20.3,但不适用于任何较新版本:

A.replace(0,np.nan)
A.replace({0:np.nan})
A.replace([0],[np.nan])
等等......(你明白了)。

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

然而,那些(以及我尝试过的大部分解决方法)都有效,因为我们不小心做错了。如果我们这样做你会立刻猜到:

A.density

1.0

这个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)

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

这是因为初始化程序无法推断列的dtypes。 引自pandas docs

  

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

     
      
  • float64:np.nan
  •   
  • int64:0
  •   
  • bool:False
  •   

但我们的SparseDataFrame的dtypes是:

A.dtypes

0    object
1    object
2    object
3    object
dtype: object

这就是为什么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
奇怪的是:
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
你可以看到,这是不正确的!
根据我自己对不同版本的pandas的实验,似乎SparseDataFrame.replace()仅适用于非填充值。 要更改填充值,您有以下选项:

  • 根据pandas文档,如果更改dtypes,则会自动更改填充值。 (这对我不起作用)。
  • 转换为密集DataFrame,进行替换,然后转换回SparseDataFrame
  • 手动重建新的SparseDataFrame,例如Wen's answer,或将default_fill_value设置为新的填充值。

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

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

B.density
0.25

B.default_fill_value
nan

到目前为止,这么好。但是......:

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

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

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)

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

答案 1 :(得分: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