numpy 在pandas dataframe的左下角到右上角对角线下方的单元格中分配NaN的更干净的方法

vcudknz3  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(84)

我不知道确切的术语是什么,我期待这样做的道歉,如果我没有正确地描述所需的结果。下面的例子来说明我的意思,应该使它清楚。
此外,我确实有一个解决方案,是工作,但它的超级笨重。我希望有人能帮我找到一个更干净的方法来做这件事。

  • 问题:**

我尝试获取一个值的 Dataframe ,像这样(值是什么并不重要,但请注意列是从0到任何值的整数):

In  [1]: a = np.random.randint(0,10,(5,5))
In  [2]: df = pd.DataFrame(a, index=['A','B','C','D','E'],columns=[x for x in range(5)])
In  [3]: df
Out [3]:
    0   1   2   3   4
A   0   8   9   4   5
B   3   4   5   0   1
C   8   5   5   4   1
D   8   5   3   8   3
E   7   2   6   7   2

期望结果:

然后我要做的是返回一个df的版本,它在“左下到右上”对角线下方的右下角有NaN。
所以期望的输出是这样的:

0   1   2   3   4
A   0   8.0 9.0 4.0 5.0
B   3   4.0 5.0 0.0 NaN
C   8   5.0 5.0 NaN NaN
D   8   5.0 NaN NaN NaN
E   7   NaN NaN NaN NaN

我已经找到了几个关于指定对角线上的特定值的答案,但没有一个与此完全相同。

工作溶液:

正如我提到的,我确实得到了一个非常笨拙的解决方案,但我希望有人有一个更干净的方法来做到这一点。以下是我所做的:

In [4]: check_digit_max = df.columns[-1] # the columns are ints, so just get the highest value
In [5]: df['check_digit'] = [i for i,x in enumerate(df.index)]

所以现在我有这个:

In  [6]: df
Out [6]:
0   1   2   3   4   check_digit
A   0   8   9   4   5   0
B   3   4   5   0   1   1
C   8   5   5   4   1   2
D   8   5   3   8   3   3
E   7   2   6   7   2   4

因此,基本上如果列号加上校验位大于check_*digit_*max,则值应为NaN。而这个混乱的循环就能做到这一点:

In  [7]: for col in df.iloc[:,:-1].columns:
            df[col] = [x if int(col)+y <= check_digit_max else np.nan
                   for x,y in zip(df[col], df['check_digit'])]
In  [8]: df.drop('check_digit',axis=1)
Out [8]:
    0   1   2   3   4
A   0   8.0 9.0 4.0 5.0
B   3   4.0 5.0 0.0 NaN
C   8   5.0 5.0 NaN NaN
D   8   5.0 NaN NaN NaN
E   7   NaN NaN NaN NaN

希望有人有更好的方法来做这件事。任何帮助感谢!

8gsdolmq

8gsdolmq1#

IIUC,您可以使用numpy.tril_indices_from来执行以下任务:

mask = np.zeros_like(df, dtype=bool)
mask[np.tril_indices_from(mask, k=-1)] = True

df[np.flip(mask, 1)] = np.nan
print(df)

图纸:

0    1    2    3    4
A  4  5.0  1.0  9.0  6.0
B  3  2.0  7.0  6.0  NaN
C  3  2.0  4.0  NaN  NaN
D  1  0.0  NaN  NaN  NaN
E  3  NaN  NaN  NaN  NaN
eanckbw9

eanckbw92#

使用简单的掩码检查i/j索引:

mask = (np.arange(df.shape[0])[:,None]
       +np.arange(df.shape[1])) < min(df.shape)

out = df.where(mask)

对于在位修改:

mask = (np.arange(df.shape[0])[:,None]
       +np.arange(df.shape[1])) >= min(df.shape)

df[mask] = np.nan

输出量:

0    1    2    3    4
A  0  1.0  6.0  8.0  1.0
B  2  3.0  2.0  6.0  NaN
C  2  6.0  9.0  NaN  NaN
D  0  0.0  NaN  NaN  NaN
E  3  NaN  NaN  NaN  NaN
  • 注意:如果DataFrame的形状不是正方形,你必须选择你认为的对角线,并最终与max(df.shape)进行比较。*
# min(df.shape)
   0    1    2    3   4
A  7  0.0  7.0  8.0 NaN
B  1  4.0  2.0  NaN NaN
C  8  1.0  NaN  NaN NaN
D  6  NaN  NaN  NaN NaN

# max(df.shape)
   0  1    2    3    4
A  7  0  7.0  8.0  2.0
B  1  4  2.0  9.0  NaN
C  8  1  2.0  NaN  NaN
D  6  1  NaN  NaN  NaN

相关问题