2011-03-27 5 views
2
내가 루비로 작성 다음 SVD recommendation system을 번역하고있어

, 내부 할당 문제 :티카 SVD 추천 시스템, 티카에 루프

Clear[s, u, v, s2, u2, v2, m, n, testdata, trainingdata, user, user2d]; 
find1nn[trainingdata_, user_] := { 
    {u , s, v} = SingularValueDecomposition[Transpose[trainingdata]]; 
    (* Reducr to 2 dimensions. *) 
    u2 = u[[All, {1, 2}]]; 
    s2 = s[[{1, 2}, {1, 2}]]; 
    v2 = v[[All, {1, 2}]]; 
    user2d = user.u2.Inverse[s2]; 
    {m, n} = Dimensions[v2]; 
    closest = -1; 
    index = -1; 
    For[a = 1, a < m, a++, 
    {distance = 1 - CosineDistance[v2[[a, {1, 2}]], user2d];, 
     If[distance > closest, {closest = distance, index = a}];}]; 
    closestuserratings = trainingdata[[index]]; 
    closestuserratings 
    } 
rec[closest_, userx_] := { 
    d = Dimensions[closest]; 
    For[b = 1, b <= d[[2]], b++, 
    If[userx[[b]] == 0., userx[[b]] = closest[[1, b]]] 
    ] 
    userx 
    } 
finalrec[td_, user_] := rec[find1nn[td, user], user] 
(*Clear[s,u,v,s2,u2,v2,m,n,testdata,trainingdata,user,user2d]*) 
testdata = {{5., 5., 3., 0., 5., 5.}, {5., 0., 4., 1., 4., 4.}, {0., 
    3., 0., 5., 4., 5.}, {5., 4., 3., 3., 5., 5.}}; 
bob = {5., 0., 4., 0., 4., 5.}; 
(*recommend[testdata,bob]*) 
find1nn[testdata, bob] 
finalrec[testdata, bob] 

경우 :

여기
require 'linalg' 

users = { 1 => "Ben", 2 => "Tom", 3 => "John", 4 => "Fred" } 
m = Linalg::DMatrix[ 
      #Ben, Tom, John, Fred 
      [5,5,0,5], # season 1 
      [5,0,3,4], # season 2 
      [3,4,0,3], # season 3 
      [0,0,5,3], # season 4 
      [5,4,4,5], # season 5 
      [5,4,5,5] # season 6 
      ] 

# Compute the SVD Decomposition 
u, s, vt = m.singular_value_decomposition 
vt = vt.transpose 

# Take the 2-rank approximation of the Matrix 
# - Take first and second columns of u (6x2) 
# - Take first and second columns of vt (4x2) 
# - Take the first two eigen-values (2x2) 
u2 = Linalg::DMatrix.join_columns [u.column(0), u.column(1)] 
v2 = Linalg::DMatrix.join_columns [vt.column(0), vt.column(1)] 
eig2 = Linalg::DMatrix.columns [s.column(0).to_a.flatten[0,2], s.column(1).to_a.flatten[0,2]] 

# Here comes Bob, our new user 
bob = Linalg::DMatrix[[5,5,0,0,0,5]] 
bobEmbed = bob * u2 * eig2.inverse 

# Compute the cosine similarity between Bob and every other User in our 2-D space 
user_sim, count = {}, 1 
v2.rows.each { |x| 
    user_sim[count] = (bobEmbed.transpose.dot(x.transpose))/(x.norm * bobEmbed.norm) 
    count += 1 
    } 

# Remove all users who fall below the 0.90 cosine similarity cutoff and sort by similarity 
similar_users = user_sim.delete_if {|k,sim| sim < 0.9 }.sort {|a,b| b[1] <=> a[1] } 
similar_users.each { |u| printf "%s (ID: %d, Similarity: %0.3f) \\n", users[u[0]], u[0], u[1] } 

# We'll use a simple strategy in this case: 
# 1) Select the most similar user 
# 2) Compare all items rated by this user against your own and select items that you have not yet rated 
# 3) Return the ratings for items I have not yet seen, but the most similar user has rated 
similarUsersItems = m.column(similar_users[0][0]-1).transpose.to_a.flatten 
myItems = bob.transpose.to_a.flatten 

not_seen_yet = {} 
myItems.each_index { |i| 
    not_seen_yet[i+1] = similarUsersItems[i] if myItems[i] == 0 and similarUsersItems[i] != 0 
} 

printf "\\n %s recommends: \\n", users[similar_users[0][0]] 
not_seen_yet.sort {|a,b| b[1] <=> a[1] }.each { |item| 
    printf "\\tSeason %d .. I gave it a rating of %d \\n", item[0], item[1] 
} 

print "We've seen all the same seasons, bugger!" if not_seen_yet.size == 0 

는 해당 티카 코드 어떤 이유로 함수 내부에서 사용자의 인덱스를 지정하지 않지만 외부에서는 수행합니다. 이것이 일어날 수있는 원인은 무엇입니까?

+0

질문을 편집하고 원본 스 니펫을 게시 할 수 있습니까? 해당 링크가 끊어지면이 질문의 _entire_ 컨텍스트가 손실됩니다. –

+0

나는 내 자신의 번역을 피곤하지만, http://farm1.static.flickr.com/133/358494623_db22603640_o.png에 대한 표식은 일치하지 않습니다. 이게 뭐야? –

+0

@Mr. 이상한 수의 오류가 두 부분에서 오는 오류를 합산합니다. –

답변

3

Mathematica 설명서에서 변수 지역화 자습서를 찾아보십시오. 문제는 당신의 rec 기능입니다. 이 문제는 Mathematica에서 입력 변수를 정상적으로 수정할 수 없다는 것입니다 (함수가 Hold 속성 중 하나를 가졌 으면 수행 할 수 있으므로 문제의 매개 변수가 미확인 변수로 전달되지만 실제로는 그렇지 않습니다). 여기에) :

rec[closest_, userxi_] := 
Block[{d, b, userx = userxi}, {d = Dimensions[closest]; 
    For[b = 1, b <= d[[2]], b++, 
    If[userx[[b]] == 0., userx[[b]] = closest[[1, b]]]]; 
    userx} 
1

당신이 달성하려고하는 것을 이해하려고하지 않고, 여기에 당신은 더 Mathematca 틱을 가지고 있지만, 코드를 작업) I 희망 (해당.

명시 적 루프가 없어지고 많은 불필요한 변수가 제거되었습니다. 모든 변수가 지역 변수이므로 Clear []를 사용할 필요가 없습니다.

find1nn[trainingdata_, user_] := 
    Module[{u, s, v, v2, user2d, m, distances}, 
    {u, s, v} = SingularValueDecomposition[Transpose[trainingdata]]; 
    v2 = v[[All, {1, 2}]]; 
    user2d = user.u[[All, {1, 2}]].Inverse[s[[{1, 2}, {1, 2}]]]; 
    m = [email protected][v2]; 
    distances = (1 - CosineDistance[v2[[#, {1, 2}]], user2d]) & /@ Range[m - 1]; 
    {trainingdata[[Ordering[distances][[-1]]]]}]; 

rec[closest_, userxi_] := userxi[[#]] /. {0. -> closest[[1, #]]} & /@ 
          Range[Dimensions[closest][[2]]]; 

finalrec[td_, user_] := rec[find1nn[td, user], user]; 

나는 여전히 많이 최적화 될 수 있다고 확신한다.

+1

예 : Position [distanceances, #] [[1,1]] & @ Max [거리]는 더 간결하고 30 % 더 빠른 Ordering [거리] [[- 1]]로 기록 할 수 있습니다. –

+0

@Sjoerd 완료. 그 (그리고 암탉 일부) 개조로 편집. 감사! –

+0

오래된 코드를 남겼습니다 –

1

belisarius의 코드와 Sjoerd의 개선점을 바탕으로 한이 기사는 다음과 같습니다.

find1nn[trainingdata_, user_] := 
    Module[{u, s, v, user2d, distances}, 
    {u, s, v} = SingularValueDecomposition[trainingdata\[Transpose], 2]; 
    user2d = user . u . [email protected]; 
    distances = # ~CosineDistance~ user2d & /@ [email protected]; 
    trainingdata[[ distances ~Ordering~ 1 ]] 
    ] 

rec[closest_, userxi_] := If[# == 0, #2, #] & ~MapThread~ {userxi, closest[[1]]} 
+0

주문하려면 [거리] [-1] 대신 [거리, -1]을 주문하십시오. 이것은 여전히 ​​더 빠릅니다. –

+0

마법사 1 - CosineDistance의 1- 부분을 버리고 최대 값 대신 _smallest_ 값 (Ordering [distanceances, 1])을 테스트 할 수 없습니까? –

+0

@Sjoerd, 나도 몰라. 나는 그것에 대해 생각해야 할 것이다. 그러나 또 다른 걱정거리가 있습니다. 'Ordering'은 한 위치 만 반환 할 것이지만 'Position'은 여러 결과를 반환 할 수 있습니다. 이 일이 무엇을하고 있는지 이해하지 못했기 때문에 나는 그것이 문제인지 알지 못합니다. 이제 원래 코드를 살펴 봐야합니다. –

0
Clear[s, u, v, s2, u2, v2, m, n, testdata, trainingdata, user, user2d]; 
recommend[trainingdata_, user_] := { 
    {u , s, v} = SingularValueDecomposition[Transpose[trainingdata]]; 
    (* Reducera till 2 dimensioner. *) 
    u2 = u[[All, {1, 2}]]; 
    s2 = s[[{1, 2}, {1, 2}]]; 
    v2 = v[[All, {1, 2}]]; 
    user2d = user.u2.Inverse[s2]; 
    {m, n} = Dimensions[v2]; 
    closest = -1; 
    index = -1; 
    For[a = 1, a < m, a++, 
    {distance = 1 - CosineDistance[v2[[a, {1, 2}]], user2d];, 
     If[distance > closest, {closest = distance, index = a}];}]; 
    closestuserratings = trainingdata[[index]]; 
    d = Dimensions[closestuserratings]; 
    updateduser = Table[0, {i, 1, d[[1]]}]; 
    For[b = 1, b <= d[[1]], b++, 
    If[user[[b]] == 0., updateduser[[b]] = closestuserratings[[b]], 
    updateduser[[b]] = user[[b]]] 
    ] 
    updateduser 
    } 
testdata = {{5., 5., 3., 0., 5., 5.}, {5., 0., 4., 1., 4., 4.}, {0., 
    3., 0., 5., 4., 5.}, {5., 4., 3., 3., 5., 5.}}; 
bob = {5., 0., 4., 0., 4., 5.}; 
recommend[testdata, bob] 

{{5. 널, 0 널, 4. 널, 1. 널, 4. 널, 5. 널}}

이제는 작동하지만 왜 널입니까?

+0

누락 되었기 때문입니다. For 루프 다음에. 공격의 의미는 없지만 다른 기여를 보았습니까? 질문은 이미 상당히 개선 된 코드로 결과가 나왔습니다. –