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

时间:2016-07-12 11:40:16

标签: python pandas similarity

我有一个数据框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

mat列的元素之间的相似性矩阵id2

    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的相应元素的重心,我的数据框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乘3k {{1} }})。什么是更干净/有效的方法呢?

期望的输出:

mat

有没有办法计算 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 元素之间的另一个相似性矩阵(来自这个数据)?

提前谢谢。

1 个答案:

答案 0 :(得分:2)

以下时钟频率为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