関心のあるコンテキスト内でパフォーマンスが改善されたvlookupの代替手段を探しています。
コンテキストは次のとおりです。
VLOOKUP
の最後の引数はFALSE
です)説明するスキーマ:
参照シート:("sheet1"
)
A B
1
2 key1 data1
3 key2 data2
4 key3 data3
... ... ...
99999 key99998 data99998
100000 key99999 data99999
100001 key100000 data100000
100002
ルックアップシート:
A B
1
2 key51359 =VLOOKUP(A2;sheet1!$A$2:$B$100001;2;FALSE)
3 key41232 =VLOOKUP(A3;sheet1!$A$2:$B$100001;2;FALSE)
4 key10102 =VLOOKUP(A3;sheet1!$A$2:$B$100001;2;FALSE)
... ... ...
99999 key4153 =VLOOKUP(A99999;sheet1!$A$2:$B$100001;2;FALSE)
100000 key12818 =VLOOKUP(A100000;sheet1!$A$2:$B$100001;2;FALSE)
100001 key35032 =VLOOKUP(A100001;sheet1!$A$2:$B$100001;2;FALSE)
100002
2.67 GHzのCore i7 M 620では、これは約10分で計算されます
このコンテキストでパフォーマンスが向上したVLOOKUPの代替手段はありますか?
次の代替案を検討しました。
比較したパフォーマンスは次のとおりです。
同じリファレンスシートを使用する
1)ルックアップシート:(vlookup array formula version)
A B
1
2 key51359 {=VLOOKUP(A2:A10001;sheet1!$A$2:$B$100001;2;FALSE)}
3 key41232 formula in B2
4 key10102 ... extends to
... ... ...
99999 key4153 ... cell B100001
100000 key12818 ... (select whole range, and press
100001 key35032 ... CTRL+SHIFT+ENTER to make it an array formula)
100002
2)ルックアップシート:(match + index version)
A B C
1
2 key51359 =MATCH(A2;sheet1!$A$2:$A$100001;) =INDEX(sheet1!$B$2:$B$100001;B2)
3 key41232 =MATCH(A3;sheet1!$A$2:$A$100001;) =INDEX(sheet1!$B$2:$B$100001;B3)
4 key10102 =MATCH(A4;sheet1!$A$2:$A$100001;) =INDEX(sheet1!$B$2:$B$100001;B4)
... ... ... ...
99999 key4153 =MATCH(A99999;sheet1!$A$2:$A$100001;) =INDEX(sheet1!$B$2:$B$100001;B99999)
100000 key12818 =MATCH(A100000;sheet1!$A$2:$A$100001;) =INDEX(sheet1!$B$2:$B$100001;B100000)
100001 key35032 =MATCH(A100001;sheet1!$A$2:$A$100001;) =INDEX(sheet1!$B$2:$B$100001;B100001)
100002
3)ルックアップシート:(vbalookupバージョン)
A B
1
2 key51359 {=vbalookup(A2:A50001;sheet1!$A$2:$B$100001;2)}
3 key41232 formula in B2
4 key10102 ... extends to
... ... ...
50000 key91021 ...
50001 key42 ... cell B50001
50002 key21873 {=vbalookup(A50002:A100001;sheet1!$A$2:$B$100001;2)}
50003 key31415 formula in B50001 extends to
... ... ...
99999 key4153 ... cell B100001
100000 key12818 ... (select whole range, and press
100001 key35032 ... CTRL+SHIFT+ENTER to make it an array formula)
100002
[〜#〜] nb [〜#〜]:何らかの(外部の内部)理由により、vbalookupは一度に65536を超えるデータを返すことができません。そのため、配列式を2つに分割する必要がありました。
および関連するVBAコード:
Function vbalookup(lookupRange As Range, refRange As Range, dataCol As Long) As Variant
Dim dict As New Scripting.Dictionary
Dim myRow As Range
Dim I As Long, J As Long
Dim vResults() As Variant
' 1. Build a dictionnary
For Each myRow In refRange.Columns(1).Cells
' Append A : B to dictionnary
dict.Add myRow.Value, myRow.Offset(0, dataCol - 1).Value
Next myRow
' 2. Use it over all lookup data
ReDim vResults(1 To lookupRange.Rows.Count, 1 To lookupRange.Columns.Count) As Variant
For I = 1 To lookupRange.Rows.Count
For J = 1 To lookupRange.Columns.Count
If dict.Exists(lookupRange.Cells(I, J).Value) Then
vResults(I, J) = dict(lookupRange.Cells(I, J).Value)
End If
Next J
Next I
vbalookup = vResults
End Function
注意:Scripting.Dictionary
にはMicrosoft Scripting Runtime
への参照が必要です。これは手動で追加する必要があります(Excel VBAウィンドウの[ツール]-> [参照]メニュー)
結論:
このコンテキストでは、ディクショナリを使用するVBAはVLOOKUPを使用するよりも100倍速く、MATCH/INDEXよりも20倍高速です。
また、「double Vlookup」メソッドの使用を検討することもできます(私の考えではなく、他の場所で見られます)。シート1で説明したものと同じデータセットを使用して、シート2で100,000のルックアップ値(ランダムにソート)でテストし、4秒弱で時間を計りました。コードも少し単純です。
Sub FastestVlookup()
With Sheet2.Range("B1:B100000")
.FormulaR1C1 = _
"=IF(VLOOKUP(RC1,Sheet1!R1C1:R100000C1,1)=RC1,VLOOKUP(RC1,Sheet1!R1C1:R100000C2,2),""N/A"")"
.Value = .Value
End With
End Sub
Excel 2013に切り替えて、データモデルを使用します。そこで、両方のテーブルで一意のIDキーを持つ列を定義し、ピボットテーブルでこれらの2つのテーブルをリレーションシップでバインドできます。どうしても必要な場合は、Getpivotdata()を使用して最初のテーブルを埋めることができます。同様の〜250K行テーブルでvlookupを実行する〜250K行テーブルがありました。 1時間後にExcelが計算を停止しました。 Data Modelを使用すると、10秒もかかりませんでした。