Python/Pandas - 字符串比较

2024-03-28 13:52:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个字符串/叙述的列表,我需要比较并得到每个字符串之间的距离度量。我编写的当前代码可以工作,但是对于更大的列表,它需要很长时间,因为我使用2 for循环。我用levenshtien距离来测量弦之间的距离。在

字符串/叙述列表存储在数据帧中。在

def edit_distance(s1, s2):
   m=len(s1)+1
   n=len(s2)+1

   tbl = {}
   for i in range(m): tbl[i,0]=i
   for j in range(n): tbl[0,j]=j
   for i in range(1, m):
       for j in range(1, n):
            cost = 0 if s1[i-1] == s2[j-1] else 1
            tbl[i,j] = min(tbl[i, j-1]+1, tbl[i-1, j]+1, tbl[i-1, j-1]+cost)
   return tbl[i,j]

def narrative_feature_extraction(df):
    startTime = time.time()
    leven_matrix = np.zeros((len(df['Narrative']),len(df['Narrative'])))  
    for i in range(len(df['Narrative'])):
        for j in range(len(df['Narrative'])):
            leven_matrix[i][j] = edit_distance(df['Narrative'].iloc[i],df['Narrative'].iloc[j])
    endTime = time.time()
    total = (endTime - startTime)
    print "Feature Extraction (Leven) Runtime:" + str(total)
    return leven_matrix 


X = narrative_feature_extraction(df)

如果列表有n个叙述,则得到的X是nxn矩阵,其中行是叙述,列是与叙述进行比较的内容。例如,对于距离(i,j),它是叙事i和j之间的levenshtien距离

有没有一种方法可以优化这段代码,这样就不需要有这么多for循环了?或者有一种Python式的计算方法吗?在


Tags: 字符串in距离df列表forlentime
1条回答
网友
1楼 · 发布于 2024-03-28 13:52:20

如果没有数据/示例,很难给出准确的代码,但有一些建议:

  • 使用列表理解,比。。。在范围内。。。在
  • 根据您的pandas版本,“df[i][j]”索引可能非常慢,而应该使用.iloc或.loc(如果您想混合使用.iloc[数据框索引获取位置(“项目名称”),df.columns.get_loc(“itemname”)]如果您遇到此问题,请将loc正确转换为iloc。(我认为只有当你收到写入数据帧片段的警告标志时,速度才会变慢,这在很大程度上取决于你有什么版本的python/pandas,但还没有经过广泛的测试)
  • 更好的是,运行所有的calc,然后根据您的用例一次性地放入dataframe
  • 如果你喜欢for循环的python式读取,那么至少要避免使用“in range”,而应该使用“forj in X[:,0]”。我发现这在大多数情况下更快,并且您可以与enumerate一起使用来保存索引值(下面的示例)

示例/时间安排:

def test1(): #list comprehension
    X=np.random.normal(size=(100,2))
    results=[[x*y for x in X[:,0]] for y in X[:,1]]
    df=pd.DataFrame(data=np.array(results))

if __name__ == '__main__':
    import timeit
    print("test1: "+str(timeit.timeit("test1()", setup="from __main__ import test1",number=10)))

def test2(): #enumerate, df at end
    X=np.random.normal(size=(100,2))
    results=np.zeros((100,100))
    for ind,i in enumerate(X[:,0]):
        for col,j in enumerate(X[:,1]):
            results[ind,col]=i*j
    df=pd.DataFrame(data=results)

if __name__ == '__main__':
    import timeit
    print("test2: "+str(timeit.timeit("test2()", setup="from __main__ import test2",number=10)))

def test3(): #in range, but df at end
    X=np.random.normal(size=(100,2))
    results=np.zeros((100,100))
    for i in range(len(X)):
        for j in range(len(X)):
            results[i,j]=X[i,0]*X[j,1]
    df=pd.DataFrame(data=results)

if __name__ == '__main__':
    import timeit
    print("test3: "+str(timeit.timeit("test3()", setup="from __main__ import test3",number=10)))

def test4(): #current method
    X=np.random.normal(size=(100,2))
    df=pd.DataFrame(data=np.zeros((100,100)))
    for i in range(len(X)):
        for j in range(len(X)):
            df[i][j]=(X[i,0]*X[j,1])

if __name__ == '__main__':
    import timeit
    print("test4: "+str(timeit.timeit("test4()", setup="from __main__ import test4",number=10)))

输出:

^{pr2}$

因此,列表理解速度大约是250倍,枚举速度是“范围内x”的两倍。虽然真正的减速是数据帧的单独索引(即使使用.loc或.iloc,这仍然是您的瓶颈,因此我建议尽可能使用df之外的数组)

希望这有帮助,你可以申请你的案件。我建议阅读map、filter、reduce(可能是枚举)函数,因为它们非常快速,可能会对您有所帮助:http://book.pythontips.com/en/latest/map_filter.html

不幸的是,虽然我对您的用例并不熟悉,但我不明白为什么它不适用于这种类型的代码调优或与之兼容。在

相关问题 更多 >