从 pandas 中的数据框和矩阵创建新矩阵

Creating new matrix from dataframe and matrix in pandas

我有一个数据框 df,它看起来像这样:

    id1  id2  weights
0   a    2a   144.0
1   a    2b   52.5
2   a    2c   2.0
3   a    2d   1.0
4   a    2e   1.0
5   b    2a   2.0
6   b    2e   1.0
7   b    2f   1.0
8   b    2b   1.0
9   b    2c   0.008

以及id2列元素之间的相似度矩阵mat

    2a    2b   2c   2d   2e   2f
2a  1     0.5  0.7  0.2  0.1  0.3
2b  0.5   1    0.6  0.4  0.3  0.4
2c  0.7   0.6  1    0.1  0.4  0.2
2d  0.2   0.4  0.1  1    0.8  0.7
2e  0.1   0.3  0.4  0.8  1    0.8
2f  0.3   0.4  0.2  0.7  0.8  1

现在我想在 id1 的元素和 id2 的元素之间创建一个相似矩阵。为此,我将 id1 的元素视为 id2 ind 我的数据帧 df 中相应元素的重心(具有相应的 weights)。

我第一次尝试使用循环 (aouch):

ids = df.id1.unique()
output = pd.DataFrame(columns = mat.columns,index = ids)
for id in ids:
    df_slice = df.loc[df.id1 == id]
    to_normalize = df_slice.weights.sum()
    temp = mat.loc[df_slice.id2]
    for art in df_slice.id2:
        temp.loc[art] *= df_slice.ix[df_slice.id2 == art,'weights'].values[0]
        temp.loc[art] /= (1.*to_normalize)
    output.loc[id] = temp.sum()

但这当然不是 pythonic,并且需要很长时间(timeit 对于这些小矩阵显示 21.3ms 对于 10k 行 df 和 3k x 3k mat).更 clean/efficient 的方法是什么?

期望的输出:

    2a          2b          2c          2d          2e          2f
a   0.857606    0.630424    0.672319    0.258354    0.163342    0.329676
b   0.580192    0.540096    0.520767    0.459425    0.459904    0.559425

有没有办法计算 id1 的元素之间的另一个相似性矩阵(根据此数据)?

提前谢谢你。

以下时钟为 6–7 毫秒(相比之下,您的方法在我的机器上大约需要 30 毫秒)。

import io

import pandas as pd


raw_df = io.StringIO("""\
  id1  id2  weights
0   a    2a   144.0
1   a    2b   52.5
2   a    2c   2.0
3   a    2d   1.0
4   a    2e   1.0
5   b    2a   2.0
6   b    2e   1.0
7   b    2f   1.0
8   b    2b   1.0
9   b    2c   0.008
""")
df = pd.read_csv(raw_df, delim_whitespace=True)

raw_mat = io.StringIO("""\
    2a    2b   2c   2d   2e   2f
2a  1     0.5  0.7  0.2  0.1  0.3
2b  0.5   1    0.6  0.4  0.3  0.4
2c  0.7   0.6  1    0.1  0.4  0.2
2d  0.2   0.4  0.1  1    0.8  0.7
2e  0.1   0.3  0.4  0.8  1    0.8
2f  0.3   0.4  0.2  0.7  0.8  1
""")
mat = pd.read_csv(raw_mat, delim_whitespace=True)


df['norm'] = df.groupby('id1')['weights'].transform('sum')

m = pd.merge(df, mat, left_on='id2', right_index=True)
m[mat.index] = m[mat.index].multiply(m['weights'] / m['norm'], axis=0)

output = m.groupby('id1')[mat.index].sum()
output.columns.name = 'id2'
print(output)    

输出:

id2        2a        2b        2c        2d        2e        2f
id1                                                            
a    0.857606  0.630424  0.672319  0.258354  0.163342  0.329676
b    0.580192  0.540096  0.520767  0.459425  0.459904  0.559425