
以下の VBA コードは、6 列のデータ (A1、B1、C1、D1、E1、F1) を必要とする特定のデータから、最も一般的な繰り返しペアとトリプレットを抽出し、その発生回数を表示します。22 列のデータ (A1、B1、C1、...U1、V1) を含むデータ セットから 4 つ組のみを抽出し、同様の方法でその発生回数を表示するコードが欲しいです。Excel で処理するにはデータが多すぎるかどうかはわかりません。
Sub MostCommonPairAndTriplet()
Dim rng As Range
Dim c As Range
Dim strPair As String
Dim strTriplet As String
Dim wsResult As Worksheet
Dim lRow As Long
Dim lRow2 As Long
Dim i As Integer
Dim j As Integer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set rng = Intersect(ActiveSheet.UsedRange, ActiveSheet.Range("A:F"))
If Not rng Is Nothing Then
'Get the result worksheet
On Error Resume Next
Set wsResult = ActiveWorkbook.Worksheets("Results")
If wsResult Is Nothing Then
Set wsResult = ActiveWorkbook.Worksheets.Add
wsResult.Name = "Results"
Else
wsResult.UsedRange.Delete
End If
'column labels
With wsResult
.Range("B1").Value = "Value1"
.Range("C1").Value = "Value2"
.Range("D1").Value = "Count"
.Range("F1").Value = "Value1"
.Range("G1").Value = "Value2"
.Range("H1").Value = "Value3"
.Range("I1").Value = "Count"
End With
On Error GoTo 0
'Find Pairs
lRow = 2
For Each c In rng
If c.Column <= 5 Then
For i = 1 To 6 - c.Column
strPair = c.Value & "_" & c.Offset(0, i).Value
On Error Resume Next
lRow2 = Application.WorksheetFunction.Match(strPair, wsResult.Range("A:A"), False)
If Err.Number > 0 Then
wsResult.Range("A" & lRow).Value = strPair
wsResult.Range("B" & lRow).Value = c.Value
wsResult.Range("C" & lRow).Value = c.Offset(0, i).Value
wsResult.Range("D" & lRow).Value = 1
lRow = lRow + 1
Else
wsResult.Range("D" & lRow2).Value = wsResult.Range("D" & lRow2).Value + 1
End If
On Error GoTo 0
Next i
End If
Next c
'Find Triplets
lRow = 2
For Each c In rng
If c.Column <= 5 Then
For i = 1 To 6 - c.Column
For j = 1 To 6 - c.Offset(0, i).Column
strTriplet = c.Value & "_" & c.Offset(0, i).Value & "_" & c.Offset(0, i + j).Value
On Error Resume Next
lRow2 = Application.WorksheetFunction.Match(strTriplet, wsResult.Range("E:E"), False)
If Err.Number > 0 Then
wsResult.Range("E" & lRow).Value = strTriplet
wsResult.Range("F" & lRow).Value = c.Value
wsResult.Range("G" & lRow).Value = c.Offset(0, i).Value
wsResult.Range("H" & lRow).Value = c.Offset(0, i + j).Value
wsResult.Range("I" & lRow).Value = 1
lRow = lRow + 1
Else
wsResult.Range("I" & lRow2).Value = wsResult.Range("I" & lRow2).Value + 1
End If
On Error GoTo 0
Next j
Next i
End If
Next c
End If
wsResult.Columns("E").Clear
wsResult.Columns("A").Delete
'Sort the pairs
With wsResult
.Columns("A:C").Sort Key1:=.Range("C2"), Order1:=xlDescending
.Columns("E:H").Sort Key1:=.Range("H2"), Order1:=xlDescending
End With
Application.DisplayAlerts = True
Application.ScreenUpdating = True
終了サブ
答え1
1 行あたり 22 個のセルを扱う場合、Quad の可能な数が多くなるため、double や triplet に使用した方法とは異なるアプローチをお勧めします。
私は、クワッドの内容とカウントの両方に関する情報を含むユーザー定義オブジェクト (クラス) を作成します (クワッド項目の配列を作成するメソッドも追加しました)。次に、クワッドを辞書オブジェクトに収集します。以下のコードでは、早期バインディング ( の下に参照を設定) を使用しましたTools --> References
がMicrosoft Scripting Runtime
、これを配布する場合は、遅延バインディングに変更する必要があります。
最初の行の後にクワッドを収集するときに、辞書を使用してクワッドがすでに存在するかどうかをテストできます。存在する場合は、カウントに 1 を追加します。存在しない場合は、新しいクワッドとして保存します。
範囲のサイズは、列 A の最後の行と行 1 の最後の列を探して決定されます。データは (ワークシートに示されているように) A1 から始まり、ヘッダー行がないものと想定されます。そうでない場合は、調整が必要になる場合があります。
また、各行のエントリがソートされていることを前提としています。そうでない場合は、Quad を生成する前にソート ルーチンを追加する必要があります。
編集: Excel の行制限により、必要な出力に 2^20 を超える四分円が含まれている場合、ルーチンはクラッシュします (1004 エラーが発生します)。これを処理するには、少なくとも 2 つの方法があります。
しきい値を増やして、2、3、または1つの列セットに収まるために必要な数の四角形のみを出力するようにします(おそらく最も簡単な方法です)。
出力を複数の列セットに分散するように出力ルーチンを変更します。
クラスモジュール
これを必ずcQuadに名前変更してください
Option Explicit
'Rename cQuad
Private pQ1 As Long
Private pQ2 As Long
Private pQ3 As Long
Private pQ4 As Long
Private pCnt As Long
Private pArr As Variant
Public Property Get Q1() As Long
Q1 = pQ1
End Property
Public Property Let Q1(Value As Long)
pQ1 = Value
End Property
Public Property Get Q2() As Long
Q2 = pQ2
End Property
Public Property Let Q2(Value As Long)
pQ2 = Value
End Property
Public Property Get Q3() As Long
Q3 = pQ3
End Property
Public Property Let Q3(Value As Long)
pQ3 = Value
End Property
Public Property Get Q4() As Long
Q4 = pQ4
End Property
Public Property Let Q4(Value As Long)
pQ4 = Value
End Property
Public Property Get Arr() As Variant
Dim V(1 To 4)
V(1) = Me.Q1
V(2) = Me.Q2
V(3) = Me.Q3
V(4) = Me.Q4
Arr = V
End Property
Public Property Get Cnt() As Long
Cnt = pCnt
End Property
Public Property Let Cnt(Value As Long)
pCnt = Value
End Property
通常モジュール
Option Explicit
'Set Reference to Microsoft Scripting Runtime
Sub CheckForQuads()
Dim cQ As cQuad, dQ As Dictionary
Dim vSrc As Variant, vRes As Variant
Dim I As Long, J As Long
Dim wsData As Worksheet, wsRes As Worksheet, rRes As Range
Dim V, W
Dim sKey As String
Set wsData = Worksheets("Data")
Set wsRes = Worksheets("Results")
Set rRes = wsRes.Cells(1, 10)
With wsData
I = .Cells(.Rows.Count, 1).End(xlUp).Row 'Last Row
J = .Cells(1, .Columns.Count).End(xlToLeft).Column 'Last Column
vSrc = .Range(.Cells(1, 1), .Cells(I, J))
End With
Set dQ = New Dictionary
For I = 1 To UBound(vSrc, 1)
'Size array for number of combos in each row
V = Combos(Application.WorksheetFunction.Index(vSrc, I, 0))
'create an object for each Quad, including each member, and the count
For J = 1 To UBound(V, 1)
Set cQ = New cQuad
With cQ
.Q1 = V(J, 1)
.Q2 = V(J, 2)
.Q3 = V(J, 3)
.Q4 = V(J, 4)
.Cnt = 1
sKey = Join(.Arr, Chr(1))
'Add one to the count if Quad already exists
If Not dQ.Exists(sKey) Then
dQ.Add sKey, cQ
Else
dQ(sKey).Cnt = dQ(sKey).Cnt + 1
End If
End With
Next J
Next I
'Output the results
'set a threshold
Const TH As Long = 1
'Size the output array
I = 0
For Each V In dQ.Keys
If dQ(V).Cnt >= TH Then I = I + 1
Next V
ReDim vRes(0 To I, 1 To 5)
'Headers
vRes(0, 1) = "Value 1"
vRes(0, 2) = "Value 2"
vRes(0, 3) = "Value 3"
vRes(0, 4) = "Value 4"
vRes(0, 5) = "Count"
'Output the data
I = 0
For Each V In dQ.Keys
Set cQ = dQ(V)
With cQ
If .Cnt >= TH Then
I = I + 1
vRes(I, 1) = .Q1
vRes(I, 2) = .Q2
vRes(I, 3) = .Q3
vRes(I, 4) = .Q4
vRes(I, 5) = .Cnt
End If
End With
Next V
'Output the data
Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2))
With rRes
.EntireColumn.Clear
.Value = vRes
With .Rows(1)
.Font.Bold = True
.HorizontalAlignment = xlCenter
End With
.EntireColumn.AutoFit
.Sort key1:=.Columns(.Columns.Count), _
order1:=xlDescending, Header:=xlYes, MatchCase:=False
End With
End Sub
Function Combos(Vals)
Dim I As Long, J As Long, K As Long, L As Long, M As Long
Dim V
ReDim V(1 To WorksheetFunction.Combin(UBound(Vals), 4), 1 To 4)
M = 0
For I = 1 To UBound(Vals) - 3
For J = I + 1 To UBound(Vals) - 2
For K = J + 1 To UBound(Vals) - 1
For L = K + 1 To UBound(Vals)
M = M + 1
V(M, 1) = Vals(I)
V(M, 2) = Vals(J)
V(M, 3) = Vals(K)
V(M, 4) = Vals(L)
Next L
Next K
Next J
Next I
Combos = V
End Function