이전 글에서, 여러 파일을 열어 하나의 워크시트로 통합하는 매크로를 소개드린 적이 있습니다. (바로가기 : Module 3)
이렇게 통합해둔 데이터는 기본적으로 동일한 행 갯수를 갖는 데이터는 아래와 같은 구조를 가지게 됩니다. 각 주기마다 동일한 데이터 배열을 가지고, header 갯수도 동일하게 됩니다. 또한, fitting을 하기위한 X 변수가 반드시 1번째 열에 있지 않을 수도 있습니다.
어쨋거나, 이렇게 데이터들이 배열이 되어있다면, 엑셀에서 일일이 X열과 Y1열을 선택해서 산점도를 그리고, 다시 regression하는 것이 매우 번거로운 일이 됩니다. 엑셀에서 산점도는 앞의 열을 X로, 뒤의 열을 Y로 취급하기 때문에, 차트를 그린 후, 수작업으로 X, Y열을 바꿔줘야합니다.
만약, 데이터가 수십개의 파일로부터 합쳐진 데이터라면, X, Y열을 일일이 마우스로 클릭하는 것조차 번거롭고, 실수할 가능성이 높아집니다.
아래의 매크로 예제는 일정한 주기를 갖고 반복된 구조의 데이터에서 간단히 X, Y쌍으로 지정하는 함수이며, 이로부터 반환된 결과는 다양하게 응용하실 수 있습니다. 또한, 개인적으로 많이 사용하는 패턴이 있다면, 본인의 용도에 맞게 적당히 수정하여 사용하실 수도 있을 것입니다.
사용방법은 다음과 같습니다.
우선 X, Y 데이터 전체의 영역을 선택합니다
주기적으로 반복된 데이터인지 체크하여, 반복된 데이터라면 '주기'를 먼저 선택하고, 해당 주기 데이터에서 X열과 Y열로 나눠줍니다. 이때 X는 1개의 열만 선택하도록 하고, Y열은 여러개의 열도 선택할수 있게 해줍니다.
X와 Y열이 쌍을 이룰 수 있도록 X열과 Y열을 배열에 순서대로 할당해서 반환해주며, 헤더 정보가 있는 데이터라면 헤더의 행 수를 입력받도록 합니다.
인터페이스가 그다지 고급스럽지는 않더라도, 그래도 마우스 클릭 몇번만으로 (X, Y)쌍으로 할당해줄 수 있기 때문에 한번 만들어두면 반복작업에서 시간을 크게 단축시킬 수 있을 것입니다.
그리고, 아래 함수 중 UnionRange, HasIntersect 함수는 이전 글에서 작성했던 함수들이며, 엑셀에서 제공하는 Application.Union, Application.Intersect의 변형 함수입니다.
다음에는 이렇게 (X, Y) 쌍으로 지정된 정보를 이용하여, 일괄 fitting을 수행하도록 하겠습니다.
'-----------------------------------------------------
On Error GoTo ErrorHandler
Dim tRange As Range, tSelRange As Range, tUsedRange As Range, tPeriod As Range, tXCol As Range, tYCol As Range, tYCols() As Range
Dim tSelCol As Range, tCheck As Boolean
Dim i As Long, j As Long, n As Long
Dim tStr As String, tMSG
Set tUsedRange = tSelRange.Worksheet.UsedRange
If HasIntersect(tSelRange, tUsedRange) Then
Set tSelRange = tSelRange.CurrentRegion
Else
Set tSelRange = tUsedRange
End If
End If
If tSelRange.Areas.Count = 1 Then
If tSelRange.Columns.Count > 1 Then
Do
tSelRange.Select
tSelRange.Cells(1, 1).Activate
Set tPeriod = Application.InputBox("단위 주기를 선택하세요." & vbCrLf & "(XYY..XYY..와 같이 주기적으로 배열된 데이터인 경우)", "주기 선택", tSelRange.Address, Type:=8)
Set tPeriod = Application.Intersect(tSelRange, tPeriod.EntireColumn)
If tPeriod.Areas.Count <> 1 Then If MsgBox("단위 주기는 1개의 영역으로 선택하세요.", vbOKCancel, "선택 오류") = vbCancel Then GoTo ErrorHandler
Loop Until tPeriod.Areas.Count = 1
tPeriod.Select
tPN = tPeriod.Columns.Count
Do
tPeriod.Select
Set tXCol = Application.InputBox("X열을 선택하세요.", "X열 선택", tPeriod.Columns(1).Address, Type:=8)
If HasIntersect(tXCol.EntireColumn, tPeriod) Then
Set tXCol = Application.Intersect(tPeriod, tXCol.EntireColumn)
tCheck = (tXCol.Areas.Count = 1 And tXCol.Columns.Count = 1)
If Not tCheck Then MsgBox "X열은 1개만 선택하세요.", vbInformation, "선택 오류"
Else
tCheck = False
MsgBox "선택영역 내에서 X열을 선택하세요.", vbInformation, "선택 오류"
End If
Loop Until tCheck
Set tRange = Nothing
For i = 1 To tPeriod.Columns.Count
If tPeriod.Columns(i).Column <> tXCol.Column Then Set tRange = UnionRange(tRange, tPeriod.Columns(i))
Next
Do
tPeriod.Select
Set tYCol = Application.InputBox("Y열을 선택하세요.", "Y열 선택", tRange.Address, Type:=8)
If HasIntersect(tYCol.EntireColumn, tPeriod) Then
tCheck = True
Set tYCol = Application.Intersect(tPeriod, tYCol.EntireColumn)
Else
tCheck = False
MsgBox "선택영역 내에서 Y열을 선택하세요.", vbInformation, "선택 오류"
End If
Loop Until tCheck
n = 0
For i = 1 To tYCol.Areas.Count
For j = 1 To tYCol.Areas(i).Columns.Count
If tYCol.Areas(i).Columns(j).Column <> tXCol.Column Then
n = n + 1
ReDim Preserve tYCols(1 To n)
Set tYCols(n) = tYCol.Areas(i).Columns(j)
End If
Next
Next
If n = 0 Then MsgBox "X, Y열은 서로 다른 열을 선택하세요.", vbInformation, "선택 오류": GoTo ErrorHandler
n = 0
For i = 1 To tSelRange.Columns.Count Step tPN
For j = 1 To UBound(tYCols)
If tYCols(j).Column < tSelRange.Column + tSelRange.Columns.Count Then
n = n + 1
ReDim Preserve oXCol(1 To n)
ReDim Preserve oYCol(1 To n)
Set oXCol(n) = tXCol
Set oYCol(n) = tYCols(j)
Set tYCols(j) = tYCols(j).Offset(0, tPN)
End If
Next
Set tXCol = tXCol.Offset(0, tPN)
Next
SelectedColIntoXYPair = n
Else
MsgBox "2개 열 이상을 선택하세요.", vbInformation, "선택 오류"
GoTo ErrorHandler
End If
Else
n = 0
For i = 1 To tSelRange.Areas.Count
For j = 1 To tSelRange.Areas(i).Columns.Count
n = n + 1
ReDim Preserve tYCols(1 To n)
Set tYCols(n) = tSelRange.Areas(i).Columns(j)
Next
Next
tMSG = MsgBox("XY,XY,…로 배열되어 있습니까?" & vbCrLf & "예 : XY,XY,… , 아니오 : YX,YX,… , 취소 : 작업 취소", vbYesNoCancel, "입력 선택")
n = 0
If tMSG = vbYes Then
For i = 2 To UBound(tYCols) Step 2
n = n + 1
ReDim Preserve oXCol(1 To n)
ReDim Preserve oYCol(1 To n)
Set oXCol(n) = tYCols(i - 1)
Set oYCol(n) = tYCols(i)
Next
ElseIf tMSG = vbNo Then
For i = 2 To UBound(tYCols) Step 2
n = n + 1
ReDim Preserve oXCol(1 To n)
ReDim Preserve oYCol(1 To n)
Set oYCol(n) = tYCols(i - 1)
Set oXCol(n) = tYCols(i)
Next
Else
GoTo ErrorHandler
End If
SelectedColIntoXYPair = n
End If
tStr = InputBox("Header로 사용할 행의 갯수를 입력하세요.", "Header 수", 0)
If StrPtr(tStr) = 0 Then GoTo ErrorHandler
oHeader = Int(Val(tStr))
Exit Function
ErrorHandler:
SelectedColIntoXYPair = 0
End Function
'-----------------------------------------------------
댓글 없음:
댓글 쓰기
의견이나 질문이 있으신 분은 언제든지 댓글을 달아주세요~