我有一个pandas数据帧我想将对角线设为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
但必须有更多的pythonic方式!?
答案 0 :(得分:41)
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)
答案 1 :(得分:3)
unutbu's answer中的两种方法都假设标签不相关(它们对基础值进行操作)。
OP代码与.loc
一起使用,因此基于标签(即在行列中的单元格上使用相同的标签,而不是在对角线上的单元格中放置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()
答案 2 :(得分:1)
此解决方案是矢量化且速度非常快,除非其他建议的解决方案适用于任何列名称和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次循环,最佳3次:每次循环145μs
答案 3 :(得分:0)
这是一个对我有用的黑客:
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)
答案 4 :(得分:0)
最简单的方法是使用np.fill_diagonal(df.values, 1)
,但是您需要确保所有列都具有相同的数据类型,我混合使用了np.float64和python floats,这只会影响numpy值。要修复,您必须将所有内容都强制转换为numpy。
答案 5 :(得分:0)
所有依赖于修改 values
的答案都取决于未记录的行为。 values
属性允许返回数据副本,但修改 cron:
的解决方案假设它返回一个视图。有时它确实会返回一个视图,但 Pandas 文档并不能保证它何时会返回。