如何在熊猫数据框上制作一个矩形矩阵正方形

时间:2018-07-09 21:08:55

标签: python-3.x pandas numpy dataframe

我有以下形式的矩阵(不一定是正方形):

   A    B    C    D
A  0   0.2  0.3  0.5
E 0.2  0.6  0.9  0.2
D 0.5  0.3  0.6   0
F 0.1  0.4  0.5  0.3

我想将其转换为方阵,如下所示

   A    B    C    D    E    F
A  0   0.2  0.3  0.5  0.2  0.1
B 0.2   0    0   0.3  0.6  0.4
C 0.3   0    0   0.6  0.9  0.5
D 0.5  0.3  0.6   0   0.2  0.3
E 0.2  0.6  0.9  0.2   0    0
F 0.1  0.4  0.5  0.3   0    0

换句话说,我想同时扩展行和列,以便它是一个对称的方矩阵(行和列的顺序相同),缺失的值填充为0。

我猜想应该有一种方法可以使用熊猫的内置函数轻松/有效地做到这一点,但我对该软件包并不熟悉。

为方便起见:

df = pd.DataFrame([[0, 0.2, 0.3, 0.5],
                   [0.2, 0.6, 0.9, 0.2],
                   [0.5, 0.3, 0.6, 0],
                   [0.1, 0.4, 0.5, 0.3]],
                   index=['A', 'E', 'D', 'F'],
                   columns=['A', 'B', 'C', 'D'])

2 个答案:

答案 0 :(得分:2)

就像您认为的那样,您绝对可以在Pandas中简洁地做到这一点。

一种方法是使用非常好的combine_first方法。

result = df.combine_first(df.T).fillna(0.0)

但是,在我使用timeit进行的测试中,每个循环的时钟频率为3.62 ms±29.2 µs,实际上比我为your method获得的时间稍慢(每个循环3.5 ms±28.6 µs)

但是,通过使用update方法在Pandas中更直接地进行计算,我能够将其降低到2.04 ms±17.2 µs /每环µs /环(〜1.7倍的速度)。

# Find the combination of both indices
full_index = df.index.union(df.columns)
# Resize the DataFrame to include all the rows and columns
all_data = df.reindex(labels=full_index, axis=0).reindex(labels=full_index, axis=1)
# Update any values we have from the transpose 
all_data.update(all_data.T)
# Fill the missing entries
result = all_data.fillna(0.0)

老实说,我无法获得我认为可以得到的最大性能提升,但是至少两个基于熊猫的版本对我而言至少更具可读性。

答案 1 :(得分:1)

# create three groups
common = set.intersection(set(df.columns.values), set(df.index))
missing_row = set(df.index) - common
missing_col = set(df.columns.values) - common

# put groups in order (might not be necessary)
ordered = list(common)+list(missing_col)+list(missing_row)

def symmetrize(a):
    return a + a.T

# take the common part and extend it to order
common_part = df.loc[common, common]
common_part = common_part.reindex(index=ordered, columns=ordered, fill_value=0)

# take the remaining part
to_add = df.copy().reindex(index=ordered, columns=ordered, fill_value=0) - common_part
# make sure its symmetric, we can do a+a.T because here every value is only written once and its symmetric position is 0
to_add = symmetrize(to_add.values)

# convert to final form
common_part = common_part+common_part.T
result = pd.DataFrame(common_part + to_add, columns=ordered, index=ordered)
result = result[[*ordered]]
result = result.reindex(ordered)