使用以下数据,如何创建一个以'id'列为索引,第二列包含一个Levenshtein距离矩阵的非对角值列表的DataFrame,该列对应于每个id?
d = {'id':[1,1,1,2,2],'string':['roundys','roundys','ppg','brewers','cubs']}
df = pd.DataFrame(data=d)
目标是生成一个看起来像
的DataFramedf_diag = pd.DataFrame({'id':[1,2],'diag_val':['0.0,7.0,7.0','6.0']})
我已经构建了一些可以处理单个列表的粗略部分,但是无法通过“ id”遍历多个列表。我使用大熊猫作为“ pd”,使用numpy作为“ np”,与莱文施泰因的距离作为“ dist”
第1步创建测试列表
aTest = ['roundys','roundys','ppg']
第2步创建从aTest返回编辑距离矩阵的函数
def editDistance(list_o_strings):
matrix = np.zeros(shape = (len(list_o_strings),len(list_o_strings)))
for i in range(len(list_o_strings)):
for j in range(i, len(list_o_strings)):
matrix[i][j] = dist(list_o_strings[i],list_o_strings[j])
for i in range(0, len(list_o_strings)):
for j in range(0,len(list_o_strings)):
if i == j:
matrix[i][j] = 0
elif i > j:
matrix[i][j] = matrix[j][i]
return matrix
第3步创建返回非对角线编辑距离项的函数
def selectElements(matrix):
ws = []
for i in range(0, matrix.shape[0]):
for j in range(0, matrix.shape[1]):
if i <> j and i>j:
ws.append(matrix[i,j])
return ws
第4步测试示例列表
testDistance = editDistance(aTest)
testOffDiag = selectElements(testDistance)
我的下一步是对数据集中的唯一ID值进行迭代。我创建了一个新的ID为ID的数据框,并与一个字符串列表配对
df1 = df.groupby('id').agg(lambda x: ','.join(x))
我试图让功能遍历id项的尝试失败了,有什么建议吗?
答案 0 :(得分:1)
通过安装pip
,您可以获得Levenshtein的距离
pip install python-Levenshtein
然后您可以执行类似的操作
from Levenshtein import distance
from itertools import combinations
def lm(a):
return [distance(*b) for b in combinations(a, 2)]
df.groupby('id').string.apply(lm).reset_index(name='diag_val')
id diag_val
0 1 [0, 7, 7]
1 2 [6]
或
def lm(a):
return ','.join([str(distance(*b)) for b in combinations(a, 2)])
df.groupby('id').string.apply(lm).reset_index(name='diag_val')
id diag_val
0 1 0,7,7
1 2 6
答案 1 :(得分:0)
Scipy具有scipy.spatial.distance.pdist
函数,可让您计算n维空间中元素之间的成对距离。该功能还允许自定义metric
参数。
我们可以将您的值以及使用python-Levenshtein
库计算出的指标函数输入该函数。
设置
from Levenshtein import distance
from scipy.spatial.distance import pdist
使用pdist
和自定义指标:
def lm(x):
return pdist(x.values.reshape(-1, 1), lambda x,y: distance(x[0],y[0]))
res = pd.DataFrame(
[(i, lm(g)) for i, g in df.groupby('id').string],
columns=['id', 'diag_val']
)
id diag_val
0 1 [0.0, 7.0, 7.0]
1 2 [6.0]