在Pandas的对角线上设置值,DataFrame

v440hwme  于 2023-02-02  发布在  其他
关注(0)|答案(8)|浏览(252)

我有一个Pandas Dataframe ,我想把对角线设为0

import numpy
import pandas

df = pandas.DataFrame(numpy.random.rand(5,5))
df

Out[6]:
     0           1           2           3               4
0    0.536596    0.674319    0.032815    0.908086    0.215334
1    0.735022    0.954506    0.889162    0.711610    0.415118
2    0.119985    0.979056    0.901891    0.687829    0.947549
3    0.186921    0.899178    0.296294    0.521104    0.638924
4    0.354053    0.060022    0.275224    0.635054    0.075738
5 rows × 5 columns

现在我想把对角线设为0:

for i in range(len(df.index)):
    for j in range(len(df.columns)):
        if i==j:
            df.loc[i,j] = 0
df
Out[9]:
     0           1           2           3           4
0    0.000000    0.674319    0.032815    0.908086    0.215334
1    0.735022    0.000000    0.889162    0.711610    0.415118
2    0.119985    0.979056    0.000000    0.687829    0.947549
3    0.186921    0.899178    0.296294    0.000000    0.638924
4    0.354053    0.060022    0.275224    0.635054    0.000000
5 rows × 5 columns

但肯定有比这更像Python的方式!?

brgchamk

brgchamk1#

In [21]: df.values[[np.arange(df.shape[0])]*2] = 0

In [22]: df
Out[22]: 
          0         1         2         3         4
0  0.000000  0.931374  0.604412  0.863842  0.280339
1  0.531528  0.000000  0.641094  0.204686  0.997020
2  0.137725  0.037867  0.000000  0.983432  0.458053
3  0.594542  0.943542  0.826738  0.000000  0.753240
4  0.357736  0.689262  0.014773  0.446046  0.000000

请注意,只有当df的行数和列数相同时,这种方法才有效。另一种适用于任意形状的方法是使用np.fill_diagonal

In [36]: np.fill_diagonal(df.values, 0)
t2a7ltrp

t2a7ltrp2#

使用np.fill_diagonal(df.values, 1)是最简单的,但是你需要确保你的列都有相同的数据类型,我有一个np.float64和python浮点的混合体,它只会影响numpy值。要解决这个问题,你必须把所有的东西都转换成numpy。

owfi6suc

owfi6suc3#

unutbu's answer中的两种方法都假设标签是不相关的(它们对底层值进行操作)。
OP代码使用.loc,所以是基于标签的(也就是说,在行-列中具有相同标签的单元格上放置0,而不是在位于对角线上的单元格上放置0--诚然,这在给定的特定示例中是无关紧要的,在该示例中,标签只是位置)。
由于需要“基于标签”的对角填充(使用DataFrame描述不完整的邻接矩阵),我能想到的最简单的方法是:

def pd_fill_diagonal(df, value):
    idces = df.index.intersection(df.columns)
    stacked = df.stack(dropna=False)
    stacked.update(pd.Series(value,
                             index=pd.MultiIndex.from_arrays([idces,
                                                              idces])))
    df.loc[:, :] = stacked.unstack()
vhmi4jdf

vhmi4jdf4#

这个解决方案是矢量化的,非常快,除非其他建议的解决方案适用于任何列名和df矩阵的大小。

def pd_fill_diagonal(df_matrix, value=0): 
    mat = df_matrix.values
    n = mat.shape[0]
    mat[range(n), range(n)] = value
    return pd.DataFrame(mat)

507列和行的 Dataframe 的性能

% timeit pd_fill_diagonal(df, 0)

1000圈,三局两胜:145 µs/循环

yshpjwxd

yshpjwxd5#

另一种实现方法是获得反单位矩阵,并将 Dataframe 与之相乘。
df * abs(np.eye(len(df))-1)

m528fe3b

m528fe3b6#

这里有一个处理名词性恒等式的方法

df.where(np.identity(df.shape[0]) != 1,0)

输出:

0         1         2         3         4
0  0.000000  0.674319  0.032815  0.908086  0.215334
1  0.735022  0.000000  0.889162  0.711610  0.415118
2  0.119985  0.979056  0.000000  0.687829  0.947549
3  0.186921  0.899178  0.296294  0.000000  0.638924
4  0.354053  0.060022  0.275224  0.635054  0.000000
dpiehjr4

dpiehjr47#

下面是一个对我有效的黑客:

def set_diag(self, values): 
    n = min(len(self.index), len(self.columns))
    self.values[[np.arange(n)] * 2] = values
pd.DataFrame.set_diag = set_diag

x = pd.DataFrame(np.random.randn(10, 5))
x.set_diag(0)
o75abkj4

o75abkj48#

所有依赖于修改DataFrame.values的答案都依赖于未记录的行为。values属性被允许返回数据的副本,但是修改values的解决方案假设它返回视图。有时它确实返回视图,但是panda文档没有保证它何时返回。

相关问题