2017-03-12 9 views
1

2つの大きなデータセットがあります.1つは50万回、もう1回は70,000回です。これらのデータセットにはアドレスがあります。小さいデータセット内のアドレスのいずれかが大きいものに存在する場合、私は一致させたい。あなたが想像しているように、住所は異なった方法で書かれていても、異なった場合やスペルで書かれていても構いません。したがって、異なるフラットは同じ住所を持ちます。私はいくつかの調査を行い、使用可能なパッケージstringdistを見つけました。一致する文字列に基づいて特定の列を返すためのRファジー文字列一致

私はいくつかの仕事をして、距離に基づいて最も近い一致を得ることができました。しかし、私はアドレスが一致する対応する列を返すことができません。以下は

私はこれはしかし、私はまた、 "の列を持っていると思った、私の3の距離に基づいて、閉じたストリングの照合を返す状況

library(stringdist) 
Address1 <- c("786, GALI NO 5, XYZ","rambo, 45, strret 4, atlast, pqr","23/4, 23RD FLOOR, STREET 2, ABC-E, PQR","45-B, GALI NO5, XYZ","HECTIC, 99 STREET, PQR","786, GALI NO 5, XYZ","rambo, 45, strret 4, atlast, pqr") 
Year1 <- c(2001:2007) 

Address2 <- c("abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR","abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR") 
Year2 <- c(2001:2010) 

df1 <- data.table(Address1,Year1) 
df2 <- data.table(Address2,Year2) 
df2[,unique_id := sprintf("%06d", 1:nrow(df2))] 

fn_match = function(str, strVec, n){ 
    strVec[amatch(str, strVec, method = "dl", maxDist=n,useBytes = T)] 
} 

df1[!is.na(Address1) 
    , address_match := 
     fn_match(Address1, df2$Address2,3) 
    ] 

を説明するために作成したコードと一緒にサンプルダミーデータであり、 df1のdf2から "Year"と "unique_id"を返します。これは、文字列がdf2から照合されたデータの行を知るのに役立ちます。だから、最終的に私がDF2から特定の「年」「UNIQUE_ID」一致する行に指定したとしていた距離に基づいてDF2からクローゼットの試合が何であったかDF1行ごとに知りたいです。

私はマージ(左結合)と関係があると思いますが、重複を維持してどのようにマージして、df1(小さなデータセット)と同じ数の行を持つことができるかわかりません。

どのような種類の解決策が役に立ちますか?あなたがそこに道の90%

+0

ないが、ご覧 'which.min'(' stringdistをラップするには? ) 'を入力してください。また、ネクタイをどう扱うかを考えてみてください。 – C8H10N4O2

+0

@ C8H10N4O2、ありがとうございます。はい、which.minは最小値を知るのに役立ちますが、この場合、一致する文字列から対応する列がほとんどないようにしたいのです。大きなデータセットに重複アドレスがあるので、一致する行を区別できるようにunique_idを設定し、大きなデータセットに基づいて他の必要な列をunique_idにマージすることができます。 – user1412

+0

@ C8H10N4O2、私は本当にあなたがこれについていくつかの解決策を提案することができると期待しています。大きなデータセットから一致する文字列の行番号を返すことができたとしても、行番号に基づいて必要な列をマージするのに役立ちます。 – user1412

答えて

1

...

はあなたが

に文字列が

あなたがちょうどDF2からマッチしたデータの行を知って欲しいと言いますあなたがすでに持っているコードを理解する必要があります。 ?amatchを参照してください:

tablexの最も近い一致の位置を返すamatch。同じ最小距離メトリックを持つ複数の一致が存在する場合、最初のものが戻されます。言い換えれば

amatchはあなた(あなたのxです)df1の各アドレスの最も近い一致である(あなたのtableです)df2内の行のインデックスを提供します。新しいアドレスを代わりに返すことによって、このインデックスを早期にラップしています。

代わりに、ルックアップまたはの索引自体を、左結合のunique_id(これが本当に一意のIDであると確信している場合)のいずれかから取得します。両方のアプローチの

イラスト:ここ

library(data.table) # you forgot this in your example 
library(stringdist) 
df1 <- data.table(Address1 = c("786, GALI NO 5, XYZ","rambo, 45, strret 4, atlast, pqr","23/4, 23RD FLOOR, STREET 2, ABC-E, PQR","45-B, GALI NO5, XYZ","HECTIC, 99 STREET, PQR","786, GALI NO 5, XYZ","rambo, 45, strret 4, atlast, pqr"), 
        Year1 = 2001:2007) # already a vector, no need to combine 
df2 <- data.table(Address2=c("abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR","abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR"), 
        Year2=2001:2010) 
df2[,unique_id := sprintf("%06d", .I)] # use .I, it's neater 

# Return position from strVec of closest match to str 
match_pos = function(str, strVec, n){ 
    amatch(str, strVec, method = "dl", maxDist=n,useBytes = T) # are you sure you want useBytes = TRUE? 
} 

# Option 1: use unique_id as a key for left join 
df1[!is.na(Address1) | nchar(Address1>0), # I would exclude only on NA_character_ but also empty string, perhaps string of length < 3 
    unique_id := df2$unique_id[match_pos(Address1, df2$Address2,3)] ] 
merge(df1, df2, by='unique_id', all.x=TRUE) # see ?merge for more options 

# Option 2: use the row index 
df1[!is.na(Address1) | nchar(Address1>0), 
    df2_pos := match_pos(Address1, df2$Address2,3) ] 
df1[!is.na(df2_pos), (c('Address2','Year2','UniqueID')):=df2[df2_pos,.(Address2,Year2,unique_id)] ][] 
+0

このソリューションと説明をありがとうございます。それは本当に役立ちます!もう一度ありがとうございます。 – user1412

+0

@ user1412また、一意性をチェックする必要がある場合は、 '?duplicated'のように'!anyDuplicated(...) 'を参照してください。 – C8H10N4O2

+0

ありがとうございました!私はまた、行列を作成し、最小距離を取るためにstringdistmatrixを探索していました。私は達成し、コードが動作しています。このための関数を作成しなければなりませんでした。しかし今、私はさまざまな地域のエリアに基づいてマッチングを行う必要があります。だから、既存の機能に対して別の機能を持たせたい。私は機能を作成することができましたが、機能上は機能が難しいと感じました。まだまだたくさんあります....私はこの質問を投稿しました。 http://stackoverflow.com/questions/42793833/r-function-for-a-function-to-be-repeated-based-on-column-values助けてください! – user1412

0

fuzzyjoinパッケージを使用したソリューションです。これは、ファジーマッチングの可能なタイプの1つとしてdplyrのような構文とstringdistを使用します。

stringdist method = "dl"(またはその他の方が効果的かもしれません)を使用できます。

「df1と同じ行数を確保する」という要件を満たすために、大きなmax_distを使用して、dplyr::group_bydplyr::top_nを使用して、最小距離で最も一致するもののみを取得しました。これはsuggestedで、dgrtwoはfuzzyjoinの開発者です。 (うまくいけば、それは将来的には、パッケージ自体の一部になるでしょう。)

(私も距離ネクタイのイベントで最大YEAR2を取るために仮定をしなければならなかった。)

コード:

library(data.table, quietly = TRUE) 
df1 <- data.table(Address1 = c("786, GALI NO 5, XYZ","rambo, 45, strret 4, atlast, pqr","23/4, 23RD FLOOR, STREET 2, ABC-E, PQR","45-B, GALI NO5, XYZ","HECTIC, 99 STREET, PQR","786, GALI NO 5, XYZ","rambo, 45, strret 4, atlast, pqr"), 
        Year1 = 2001:2007) 
df2 <- data.table(Address2=c("abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR","abc, pqr, xyz","786, GALI NO 4 XYZ","45B, GALI NO 5, XYZ","del, 546, strret2, towards east, pqr","23/4, STREET 2, PQR"), 
        Year2=2001:2010) 
df2[,unique_id := sprintf("%06d", .I)] 

library(fuzzyjoin, quietly = TRUE); library(dplyr, quietly = TRUE) 
stringdist_join(df1, df2, 
       by = c("Address1" = "Address2"), 
       mode = "left", 
       method = "dl", 
       max_dist = 99, 
       distance_col = "dist") %>% 
    group_by(Address1, Year1) %>% 
    top_n(1, -dist) %>% 
    top_n(1, Year2) 

結果:今私のコンピュータで

# A tibble: 7 x 6 
# Groups: Address1, Year1 [7] 
           Address1 Year1        Address2 Year2 unique_id dist 
            <chr> <int>        <chr> <int>  <chr> <dbl> 
1     786, GALI NO 5, XYZ 2001     786, GALI NO 4 XYZ 2007 000007  2 
2  rambo, 45, strret 4, atlast, pqr 2002 del, 546, strret2, towards east, pqr 2009 000009 17 
3 23/4, 23RD FLOOR, STREET 2, ABC-E, PQR 2003     23/4, STREET 2, PQR 2010 000010 19 
4     45-B, GALI NO5, XYZ 2004     45B, GALI NO 5, XYZ 2008 000008  2 
5     HECTIC, 99 STREET, PQR 2005     23/4, STREET 2, PQR 2010 000010 11 
6     786, GALI NO 5, XYZ 2006     786, GALI NO 4 XYZ 2007 000007  2 
7  rambo, 45, strret 4, atlast, pqr 2007 del, 546, strret2, towards east, pqr 2009 000009 17