将pandas DataFrame中的对角三角形设置为NaN

Tho*_*hew 4 python numpy pandas

给定以下数据框:

import pandas as pd
import numpy as np
a = np.arange(16).reshape(4, 4)
df = pd.DataFrame(data=a, columns=['a','b','c','d'])
Run Code Online (Sandbox Code Playgroud)

我想产生以下结果:

df([[ NaN,  1,  2,  3],
    [ NaN,  NaN,  6,  7],
    [ NaN,  NaN,  NaN, 11],
    [ NaN,  NaN,  NaN,  NaN]])
Run Code Online (Sandbox Code Playgroud)

到目前为止,我尝试使用np.tril_indicies,但是它仅适用于将df转换为numpy数组的情况,并且仅适用于整数分配(不适用于np.nan):

il1 = np.tril_indices(4)
a[il1] = 0
Run Code Online (Sandbox Code Playgroud)

给出:

array([[ 0,  1,  2,  3],
       [ 0,  0,  6,  7],
       [ 0,  0,  0, 11],
       [ 0,  0,  0,  0]])
Run Code Online (Sandbox Code Playgroud)

...这几乎是我在寻找的东西,但是在分配NaN时bar之以鼻:

ValueError: cannot convert float NaN to integer
Run Code Online (Sandbox Code Playgroud)

而:

df[il1] = 0
Run Code Online (Sandbox Code Playgroud)

给出:

TypeError: unhashable type: 'numpy.ndarray'
Run Code Online (Sandbox Code Playgroud)

因此,如果我想用NaN填充数据框的底部三角形,是否必须1)必须是一个numpy数组,或者我可以直接用熊猫来做到这一点?2)是否有一种方法可以用NaN填充底部三角形,而不是numpy.fill_diagonal在整个DataFrame中逐行使用和递增偏移量?

另一个失败的解决方案:用零填充np数组的对角线,然后在零上屏蔽并重新分配给np.nan。当应将其保留为零时,它将对角线上方的零值转换为NaN!

jez*_*ael 5

你需要投地float a,因为typeNaNfloat

import numpy as np
a = np.arange(16).reshape(4, 4).astype(float)
print (a)
[[  0.   1.   2.   3.]
 [  4.   5.   6.   7.]
 [  8.   9.  10.  11.]
 [ 12.  13.  14.  15.]]


il1 = np.tril_indices(4)
a[il1] = np.nan
print (a)
[[ nan   1.   2.   3.]
 [ nan  nan   6.   7.]
 [ nan  nan  nan  11.]
 [ nan  nan  nan  nan]]

df = pd.DataFrame(data=a, columns=['a','b','c','d'])
print (df)
    a    b    c     d
0 NaN  1.0  2.0   3.0
1 NaN  NaN  6.0   7.0
2 NaN  NaN  NaN  11.0
3 NaN  NaN  NaN   NaN
Run Code Online (Sandbox Code Playgroud)

  • pandas 解决方案类似于 `Divakar` - `df = df.mask(np.arange(4)[:,None] >= np.arange(4))` (4认同)

Div*_*kar 5

使用np.where-

m,n = df.shape
df[:] = np.where(np.arange(m)[:,None] >= np.arange(n),np.nan,df)
Run Code Online (Sandbox Code Playgroud)

样品运行-

In [93]: df
Out[93]: 
    a   b   c   d
0   0   1   2   3
1   4   5   6   7
2   8   9  10  11
3  12  13  14  15

In [94]: m,n = df.shape

In [95]: df[:] = np.where(np.arange(m)[:,None] >= np.arange(n),np.nan,df)

In [96]: df
Out[96]: 
    a    b    c     d
0 NaN  1.0  2.0   3.0
1 NaN  NaN  6.0   7.0
2 NaN  NaN  NaN  11.0
3 NaN  NaN  NaN   NaN
Run Code Online (Sandbox Code Playgroud)