2017-06-15 145 views
0

我有一個字符串/敘述的列表,我需要比較並獲得每個字符串之間的距離度量值。我寫的當前代碼的作品,但是因爲我使用2 for循環,所以需要更長的列表。我用levenshtien距離來衡量琴絃之間的距離。Python /熊貓 - 字符串比較

字符串/敘述的列表存儲在數據框中。

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是n×n的矩陣,其中該行是敘述和列是什麼,敘事相比。例如,對於距離(i,j),它是敘述i和j之間的levenshtien距離。

有沒有一種方法來優化此代碼,以便不需要有太多for循環?或者有沒有計算這個的pythonic方式?

+0

codereview可能是一個更好的地方 – depperm

回答

1

很難給沒有數據/例子確切的代碼,但有幾個建議:

  • 使用列表理解,速度遠遠超過了...在...範圍內根據您的大熊貓的版本
  • ,「df [i] [j]」索引可能很慢,而是使用.iloc或.loc(如果要混合使用.iloc [df.index.get_loc(「itemname」),df.columns)。 get_loc(「itemname」)]把loc轉換成iloc,如果你有這個問題的話(我認爲它只有在獲得寫入數據幀片的警告標誌時纔會很慢並且很大程度上取決於你的python/pandas版本有,但沒有廣泛測試)
  • 更好的是,運行所有計算,然後根據您的使用情況一次性投入數據框
  • 如果您喜歡for循環的pythonic閱讀,請儘量避免至少使用「in range」,而應使用「for j例如在X [:,0]中。我覺得這是在大多數情況下更快,你可以用枚舉使用,以保持指數值(如下圖所示)

例子/定時:

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))) 

輸出:

test1: 0.0492231889643 
test2: 0.0587620022106 
test3: 0.123777403419 
test4: 12.6396287782 

因此列表理解速度快250倍,列舉速度比「範圍內的x」快兩倍。儘管真正的減速是對你的數據框的單獨索引(即使使用.loc或.iloc,這仍然是你的瓶頸,所以我建議儘可能使用df之外的數組)

希望這有助於你能夠適用於你的情況。我建議閱讀地圖,過濾器,減少,(也許枚舉)的功能,以及他們很快,可能會幫助你:http://book.pythontips.com/en/latest/map_filter.html

不幸的是,我不是真的很熟悉你的使用情況,但我不沒有看到它不適用於此類代碼調整的原因。