애들센스


엑셀 숫자 오름차순 정렬 질문드립니다 오피스/VBA/Office.JS

모 커뮤니티에 갔다가 다음과 같은 질문이 있길래 답변을 해주고 블로그로 옮겨 봅니다
안녕하세요. 엑셀 숫자 오름차순에 질문이 있어요..
엑셀 숫자가 오름차순을 하면

2018-2-100
2018-2-1000
2018-2-1001
2018-2-101

이렇게 되는데요ㅜㅜㅠ

2018-2-100 다음에 101이 나왔으면 좋겠거든요..
ㅠㅠㅠㅠ방법이 없을까요..?
감사합니다...도와주세요..

핵심은 데이터 길이가 같은 것끼리 정렬을 하게 해주는 것인듯 하다. 그래서 컬럼을 하나 추가해 LEN()함수로 길이를 구한 후, 1차 정렬기준으로 길이, 2차 정렬기준으로 데이터를 해주면 길이가 같은 데이터끼리 정렬되어 전체적으로 원하는 결과가 나온다.

(업데이트) VBA에서 본 이상한 코드들 오피스/VBA/Office.JS


VBA구문에 충실하게 FM대로 코딩하다가, 다른 사람들이 만든 코드를 보면 초보 입장에서 '이런 코드가 가능해?'하고 의문점을 가질 수 있는 걸 종종 보게 된다. VB/VBA는 c/c++, python, javascript 처럼 다양한 코드 스타일을 만들어 볼 수 있는 유연성이 떨어져 코딩하는 재미가 없는 편이다. 그러나 초보시절부터 현재까지 종종 생각하지 못한 코드를 보았는데, 오늘은 그걸 한번 정리해보려고 한다. 일단 생각나는 대로 적어 보자면:
(이 포스팅을 계속 업데이트 하려는 데, 최근 업데이트 내용을 선두에 두려고 한다. 예전 거는 그냥 두고...)

11. Join으로 배열의 값 한 번에 출력하기(2)(2019-07-01)
(앞서 팁10과 같은 연장선상의 내용이라 추가할까 하다가 아무래도 묻힐 것 같아 새로 번호를 붙입니다)
Join() 함수를 이용하여 배열을 내용을 여러 행으로 나누어 출력할 수 있다. 보통 For루프를 사용하여 출력을 하였다.
    arr = Array("문재인", "트럼프", "김정은", "남북미 정상회담", "토착왜구", "나베")
Dim i As Long

For i = LBound(arr) To UBound(arr)
Debug.Print arr(i)
Next
그러나 Join함수와 vbCrLf(캐리지-리턴,줄바꿈, 상수)를 사용하여 루프없이 출력할 수 있다.
arr = Array("문재인", "트럼프", "김정은", "남북미 정상회담", "토착왜구", "나베")
Debug.Print Join(arr, vbCrLf)


10. Join으로 배열의 값 한 번에 출력하기(1)(2019-05-26)
Join(배열, 구분자)

Join()함수는 주어진 구분자를 이용하여 문자들을 연결하는 함수이다. 가령 m이라는 배열을 다음과 같이 만들었다.
m = Array(1, 2, 3, 4)

이때 이를 출력하려면
Debug.Print m(0); m(1); m(2); m(3)

와 같이 할 것이다. 그러나 Join()함수를 다음과 같이 사용할 수 있다.
Debug.Print Join(m, ", ")

이어지는 내용

없으면 빌려쓰는 ArrayList 오피스/VBA/Office.JS

VBA에는 남다른 철학이 있다. '없으면 빌어다 써라~'. 그런데 '한 푼 줍쑈~'라도 하려면 뭔가 있어야 하는데, 그것이 CreateObject()함수이다. CreateObject()함수를 사용하여 닷넷의 ArrayList를 빌어다 쓸 수 있는데, 다음은 ArrayList를 이용한 정렬이다.
Sub demoArrayList()
Dim it

With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
.Add it: Next

'// 오름차순
.Sort
Debug.Print Join(.toarray, vbLf)
Debug.Print

'// 내림차순
.Sort
.Reverse
Debug.Print Join(.toarray, vbLf)
End With

End Sub
이를 이용하여 다음과 같이 워크시트의 셀 범위를 정렬할 수 있는 데
Sub demoSortArrayList()
Dim sn, j, jj, sp, ai
Dim bln As Boolean

sn = Sheet1.Range("B3:N18")

With CreateObject("System.Collections.Arraylist")
For j = 1 To UBound(sn)
.Add sn(j, 3)
Next

.Sort

sp = .ToArray
.Clear

For j = 0 To UBound(sp)
For jj = 1 To UBound(sn)
If sn(jj, 3) = sp(j) Then
.Add Application.Index(sn, jj)
sn(jj, 3) = ""
Exit For
End If
Next
Next

For j = 0 To .Count - 1
Sheet1.Range("B3:N18").Item(j + 1, 1).Resize(, UBound(sn, 2)) = .Item(j)
Next
End With
End Sub
사실 이렇게 복잡하게 할 필요는 없다. Range개체의 Sort메서드를 이용하는 것이 훨씬 간결하다. 응? 근데 왜 했지?
Sub demoSortRange()
With Sheet1.Range("B3:N18")
.Sort Key1:=.Item(1, 3), Order1:=XlSortOrder.xlDescending, Header:=xlNo
End With
End Sub

전혀 궁금하지 않은 자연상수e 펀드

연속복리를 이야기 하다가 공식( 원금*e^r )에 나오는 e 때문에 잠시 이야기가 새어 버리게 되었다. 오일러 상수 또는 자연상수 e 또는 자연로그의 밑 e의 값은 대충 ≈ 2.71828 18284 59045 23536 이다.

이 값은 복리계산에서 볼 수 있는 데, 가령 1년이라는 기간동안 복리횟수를 무식하게 늘리다 보면 이 숫자를 만나게 된다. 복리 계산식은 원금 A, 이율 r, 기간 n 일 때, S=A(1+r)^n이다.

가령 이율 100%로 1원을 예금한다고 하자.
* 1년후 이율이 100%, 기간은 1이므로
원금은 1*(1+100%)^1 = 1*(1+1)^1 = 2가 된다.
* 6개월 복리라면 이율은 100%÷2, 기간은 2이므로
원금은 1*(1+50%)^2 = 1*(1+0.5)^2 =2.25가 된다
* 분기 복리라면 이율은 100%÷4분기, 기간은 4이므로
원금은 1*(1+25%)^4 = 1*(1+0.25)^4 =2.4414가 된다
* 월 복리라면 이율은 100%÷12개월, 기간은 12이므로
원금은 1*(1+8.33%)^12 = 1*(1+0.0833)^12 =2.61207…가 된다
* 매주 복리라면 이율은 100%÷52주, 기간은 52이므로
원금은 1*(1+1.92%)^52 = 1*(1+0.0192)^52 =2.688373…가 된다
* 매일 복리라면 이율은 100%÷365일, 기간은 365이므로
원금은 1*(1+0.27%)^365 = 1*(1+0.0027)^365 =2.7146…가 된다
* 매시간마다 복리라면 이율은 100%÷8760시간, 기간은 8760이므로
원금은 1*(1+0.0114%)^8760 = 1*(1+0.000114)^8760 =2.714432…가 된다
* 매분마다 복리하면 이율은 100%÷525600분, 기간은 525600이므로
원금은 1*(1+0.00019%)^525600 = 1*(1+0.0000019)^525600 =2.71458…가 된다
* 매초마다 복리라면 이율은 100%÷31536000초, 기간은 31536000이므로
원금은 1*(1+0.0000032%)^31536000 = 1*(1+0.0000000317)^31536000 =2.71828…가 된다


타임버드: 복리횟수가 늘어날 수로 자연상수에 가까워지고 있다. 놀랍지 않은 가?

고문당하는 자: 전혀요~

타임버드: 밀리초, 나노초라면...?

고문당하는 자: 이제 고만 알아보자. 더 이상 안궁금하다. 오히려 이유없이 기분이 나빠질 뿐이다.


(수학)A light in a park can illuminate effectively up to a distance of 100m. 삽질의 추억

A light in a park can illuminate effectively up to a distance of 100m. A point on a bike path is 150m from the light. The sight line to the light makes an angle of 23˚ with the bike path. What length of the bike path, to the nearest metre, is effectively illuminated by the light?


(엑셀) 마지막 일자 구하기 오피스/VBA/Office.JS

이 팁을 알기 전에는 마지막 일자를 구하는 방법은 대충 이러했다.

어느 달의 마지막 일자를 구하려면
1) 한달을 더한 다음
2) 그 달의 1일을 날짜로 만들고
3) 다시 거기서 하루를 빼는 식
이었다.

그런데 다음과 같이 DATE()함수를 가지고 쉽게 구할 수 있다.
=DATE(year, month, 0)

일자를 0으로 두면 month의 이전 달 마지막 날짜를 가져온다. 즉 이전 달의 마지막 일자를 물어다 준다.

가령 6월이라면
=DATE(2019, 6, 0)은 '2019-05-31'을 돌려준다.

만일 1월이라면 어떨까?
=DATE(2019, 1, 0)은 '2018-12-31'을 돌려준다.

만일 month자리에 0을 넣으면?
=DATE(2019, 0, 0)은 '2018-11-30'을 돌려준다.
month=0으로 2019년의 직전월인 12월이 나오고 다시
day=0이므로 12월의 이전 달인 11월을 가리키는 것이다.

만일 month자리에 -1을 넣으면?
=DATE(2019, -1, 0)은 '2018-10-31'을 돌려준다.

즉 month자리에 0이하 값을 넣으면 이전 연도의 월을 가리키는 것이고
day 자리에 0을 넣으면 이전 달의 마지막 일자를 가져온다.

(업데이트)기하평균을 구하다가 에러를 만나다 증권

신심리지수나 Williams'R을 계산하다가 과열국면에서 침체국면 또는 침체국면에서 과열국면으로 지표값이 이동시 평균수익률이 어느 정도일까 궁금했다.


이때 사용하는 평균은 일반적으로 아는 산술평균이 아니라 기하평균이다. 산술평균은 "수치의 합계"를 "수치의 개수"로 나누지만 기하평균은 수치의 곱을 수치의 개수만큼의 제곱근을 취해 산출된다. 기하평균은 인구성장률이나 투자이율 등 성장률의 평균을 산출할 때 사용한다. 기하평균의 대표적인 예가 CAGR(Compound Average Growth Rate)이다 CAGR은 국가 GDP나 기업매출액의 성장률을 나타내는 수치이다.

엑셀에서는 다음과 같은 워크시트 함수나 수식을 사용할 수 있다.
  1. =GEOMEAN(datarange)

  2. =POWER(PRODUCT(datarange),(1/count(datarange)))

  3. {=EXP(AVERAGE(LN(datarange)))}
3번의 경우 배열수식이다.

그런데 수익률의 평균을 계산하려고 할때(수익률계산이 아니라 계산된 수익률들의 평균) 우리가 평소에 보던 방식(자산의 변동분을 비율로 표시하는 수익률)으로 계산한 수익율(-10%, +25% 등등)을 가지고 기하평균을 계산하려다 보니 문제가 생겼다. 수익률중 "0" 이하인 경우가 있는 경우 #NUM! 에러가 생긴다.

이는 루트안에 음수가 에러를 내기 때문이다. 기하평균은 (현재 값) : (이전 값) 비율을 가지고 계산한다. 이걸 the decimal multiplier equivalent values이라고 하는 데 우리 말로는 뭐라고 할 지 모르겠다.

현재값/이전값, 현재자산크기/이전자산크기와 같은 방식이 아니라 변동분의 비율(=평소 익숙한 표시방식의 수익률) 을 가지고 계산하는 경우 1 을 더하여 (기간만큼의) 제곱근을 계산한 후 앞서 더해 준 1을 다시 빼는 방식으로 하면 된다. 즉 아래 그림과 같다.

6%는 1.06이 되고 -3%는 0.97


이 된다. 다음은 엑셀에서 간단히 마이너스 수익률이 있는 데이터의 기하평균을 구하는 예이다.

심야의 걱정 삽질의 추억

통계 원고를 쓰는 중인데 내용이 쉽고 뻔해서 결국 내가 쓴 글이랑 남들이 쓴 글이랑 비슷하고 심지어 예제마저 소름끼칠 정도로 닮아서 베껴 쓴 것으로 보일 까 싶다.   분산과 표준편차를 1,2,3,4,5 다섯 개의 숫자로 예를 들어 쓰려고 긁적이는데, 나와 같은 생각을 가진 사람의 글을 보았다.
안본 눈 삽니다~

도박사의 오류(Gambler's Fallacy; Monte Carlo Fallacy)


어느 환자가 진료를 받고 있었다. 담당의사가 ‘이 병은 생존률이 1/100입니다.’ 그러자 환자가 깜짝 놀라면서 물었다. ‘그러면 저는 죽는 건가요?’ 의사는 느긋하게 대답한다. ‘그러나 걱정마세요. 당신은 완쾌될 것입니다. 그동안 이 병으로 나에게 진료받은 다른 99명의 환자가 죽었으니까요’

위의 이야기는 여러 가지 버전이 있는 데, 모두 도박사의 오류를 말하는 것이다. 도박사의 오류란:
서로 영향을 주지 않는 확률적 사건들속에서 그들간의 상관관계를 찾으려는 사고의 오류를 말한다. 서로 영향을 주지 않는 말은 독립적이라고 하는데, 즉 확률적 결과를 가지는 사건이 동일한 실행조건하에 반복시행하여 이번 사건의 발생이 다른 사건에 영향을 받거나 주지 않는 것이다.

동전을 던지는 경우 앞면과 뒷면이 나올 확률은 언제나 각각 1/2이며, 이번에 동전을 던지는 것이 이전 동전을 던진 결과와는 아무런 상관이 없다. 그러나 ‘앞서 동전을 10번 던져 앞면이 7번 나왔으니 이번에도 앞면이 나올 것이다’ 라고 판단하는 것이 도박사의 오류이다.

일상생활속에서도 볼 수 있는 도박사의 오류는 로또번호중 어느 번호가 가장 많이 나왔는 지 분석하는 것이다. 로또 추첨은 언제나 앞 회차와는 독립적이다.

'얘네들 미친 거 아냐!'

하는 생각을 잠시 했습니다. 2018년 결산이라니...지금 5월말인데, 거의 반 년이 지났는데 무슨 결산을 이제 하나 싶네요. 예전엔 연초에 한 듯 했는데...회사가 어렵나 싶네요.

이글루스가 초창기 블로깅 플랫폼이라는 상징성은 있었는데, 지금은 너무 낡아서 워드프레스로 옮겨야 하나 싶네요.  에디터도 낡고 스킨도 그렇고 구글광고 붙이는 것도 그렇고 이래저래 낡은 티가 팍팍 납니다.

그런데 예전에 플랫폼 옮기신 인기블로거분들이 다시 역이민오는 걸 보면, 손님이 블로거를 따라 가시는 건 아닌 듯합니다. 저 역시 다른 플랫폼으로 이민갈 생각을 궁리중인데, HOXY 따라 오실 분 있으세요? 절대 대표 블로거로 뽑히지 않아서 그런 건 아닙니다. ㅎㅎ

그래도 한 줌밖에 안되는 글을 찾아와 주시는 분들께 감사드립니다.

Exponential growth

If the population of a certain country is 1 billion and it is growing at 1.5%, find the population after 3 years.
1*e^(0.015*3)=e^0.045=1.046

A certain population is 60 million and it is growing at 3% continuous per annum. Find the population after 5 years.
Population is:
60*e^(5*0.03)=60*e^0.15=60*1.161834=69.7

If the growth multiple per annum is 1.16, find the continuous growth rate per annum.
e^r=1.16
ln e^r=ln 1.16
r*ln e = r = ln 1.16 = 14.842%

하스켈의 zipWith 함수 따라하기 오피스/VBA/Office.JS

함수형 프로그래밍 랭귀지인 Haskell의 Prelude모듈에는 zipWith()함수가 있는 데, 일단은 리스트를 받아서 리스트를 돌려주는 함수이다. 입력받은 리스트와 함수를 가지고, 각 리스트내 해당위치의 원소를 입력받은 함수에 적용한 결과를 리스트로 돌려준다. map함수와 유사하다.

하스켈의 zipWith() 함수 사용 예를 몇 가지 보면 짐작이 갈 것이다.
*[1,2,3]과 [3,2,1]의 원소를 연산자 + 에 적용하여 4,4,4,의 결과를 리스트로 만든다
Input: zipWith (+) [1,2,3] [3,2,1]
Output: [4,4,4]

*5가 10개인 리스트, (replicate 10 5)와 1~10까지 10개의 리스트, [1..10]를 가지고 5의 거듭제곱(**)을 계산한다
5^1, 5^2, 5^3, 5^4, 5^5, 5^6, 5^7, 5^8, 5^9, 5^10
Input: zipWith (**) (replicate 10 5) [1..10]
Output: [5.0,25.0,125.0,625.0,3125.0,15625.0,78125.0,390625.1,1.95313e+06,9.76563e+06]

* 리스트 [1..4]과 [5..8]를 가지고 2*x+y 식에 대입하여 계산결과를 리스트로 만들어 돌려준다.
Input: zipWith (\x y -> 2*x + y) [1..4] [5..8]
Output: [7,10,13,16]

다음은 VBA버전 zipWith함수이다.
Function ZipWith(f As String, A As Variant, B As Variant)
    'assumes that A,B are 1-dimensional variant arrays with the same bounds
    'and f is the name of a function with two variables
    Dim i As Long
    Dim m As Variant

    ReDim m(LBound(A) To UBound(A))
    For i = LBound(A) To UBound(A)
        Select Case f:
            Case "+":
                m(i) = A(i) + B(i)
            Case "-":
                m(i) = A(i) - B(i)
            Case "*":
                m(i) = A(i) * B(i)
            Case "/":
                m(i) = A(i) / B(i)
            Case "&":
                m(i) = A(i) & B(i)
            Case "^":
                m(i) = A(i) ^ B(i)
            Case Else:
                m(i) = Application.Run(f, A(i), B(i))
        End Select
    Next i
    ZipWith = m
End Function

Sub demoZip()
    Dim A As Variant, B As Variant, products As Variant

    A = Array(2, 3, 4)
    B = Array(5, 6, 7)
   
    products = ZipWith("*", A, B)

    Debug.Print Join(products, " ")
End Sub

VBA의 파이썬 따라잡기 오피스/VBA/Office.JS

파이썬의 map() 함수는 built-in 함수로 list 나 dictionary 와 같은 데이터를 받아 개별요소를 함수의 인자로 전달하여 결과를 list로 형태로 반환해 주는 함수이다. 글로 설명하면
def func(x):
  return x * 2
func()는 평범한 파이썬 함수로 매개변수로 받은 정수를 두배로 곱하여 반환해 주는 함수이다.
이 함수에 인자를 map() 함수를 이용해 전달해 보자.
>>> map( func, [1, 2, 3, 4] )
[2, 4, 6, 8]
위와 같이 map() 함수는 for문과 같은 반복문을 사용하지 않아도 지정한 함수로 매개변수를 여러 번 전달해 그 결과를 리스트로 뽑아 주는 유용한 함수이다. VBA는 이게 매우 부럽다. 남들은 한 줄로 간결하게 처리할 수 있는 데, VBA는 아직도 여러 줄의 반복문 블럭을 만들어야 한다. 그래서 흉내를 내보았다. 핵심은 빤스런 아니, Application.run() 이다.
Sub demoMap()
Dim m

m = map("func", Array(1, 2, 3, 4))

Debug.Print m(0); m(1); m(2); m(3);
End Sub

Function func(x)
func = x * 2
End Function

Function map(f As String, A As Variant) As Variant
'assumes that A is a 1-dimensional variant array
'and f is the name of a function that can be applied to it

Dim i As Long
Dim m As Variant

ReDim m(LBound(A) To UBound(A))
For i = LBound(A) To UBound(A)
m(i) = Application.Run(f, A(i))
Next
map = m
End Function
어떠신가? 그럴 듯 하지 아니한 가?


50만원이 100만원 되려면 몇 년이 걸릴 까? 펀드

이자율 1%일 때 50만원이 그 두 배인 100만원이 되려면 몇 년이 걸릴까? 아마 화성으로 우주선을 보내는 것이 더 빠를지도 모르겠다. n이 두 배가 되기 위해 필요한 시간(연)이라면 다음과 같이 식을 설정할 수 있다.

500000 * ( 1 + 0.01) ^n = 1000000

위의 식을 푸는 핵심은 양변에 로그를 씌우는 것이다. 그래서 아래와 같이 전개하면;
Log 500000 * ( 1 + 0.01) ^n = Log10^6
Log 1000000/2 + n * Log 1.01 = 6
Log 10^6 - Log 2 + n * Log 1.01 = 6
6 - Log 2 + n * Log 1.01 = 6
n * Log 1.01 = Log 2
n * (0.004321) = 0.30103
n = 69.66(년)

Log 값을 구하려면 계산기가 필요하지만, 그래도 눈에 가시같은 지수 n 을 쉽게 구할 수 있는 방법이다.

고인물같은 재무함수 낭비 방법 오피스/VBA/Office.JS

위키백과에서 정의한 현재가치는 미래에 얻게 될 확실한 부(富)의 가치를 현재의 가치로 환산한 값이다.
1기간 후부터 n기간까지의 미래에 일정한 현금흐름이 반복된다면 이를 현재가치로 환산하는 식은 다음과 같다.

엑셀의 PV함수 사용시 주의할 점은 매개변수중 pmt의 부호이다. pmt는 기간 동안 일정하게 지금 받거나 납입하는 금액을 말하는데, 현금이 들어오는 경우는 "+", 나가는 경우면 "-" 이다. 그리고 그 결과는 pmt의 부호방향과 반대이다.

가령 PV(0,1,-3) = 3, PV(0,1,3) = -3 이다.

그런데 PV공식을 보면 여러 개의 할인된 현금흐름(CF)이 ➕로 연결되어 있다. 만일 + 로 연결한 현금흐름에서 r=0이면 분모가 1이 되어 그 결과는 CF*n 이 된다. 결국 CF는 n기간동안 상수이고 , n 역시 상수이므로 단순곱셈이다. 그래서 3 곱하기 4는 12인데(구구단을 외우다니...처..천잰데..), PV를 이용하면 PV(0,3,4) = -12 이다. 엑셀의 PV함수 특성상 부호방향이 반대일 뿐이다. 즉 PV(0,1,1) = -1이고 PV(0,1,-1) = 1이다.

그래서 PV(0,1,PV(0,3,4))는 3 곱하기 4의 결과와 같다. 처음 나오는 PV는 부호를 변경하기 위한 것이고, 두 번째 PV는 곱셈연산을 한다. 곱셈을 참 어렵게 한다~ 그러나 현금흐름이 스칼라값이 아니라 배열이나 벡터와 같은 경우라면 한번에 여러 개의 곱셈연산을 하는 셈이 된다. 다음은 PV()를 이용하여 배열의 각 원소끼리 곱셈을 하는 코드이다.
Dim X, Y, Mult

X = Array(Array(1, 3), Array(2, 4))
Y = Array(1, 2)

With Application
    Mult = .PV(, 1, .PV(, X, Y))
End With
주의할 점은 Worksheetfunction.PV가 아니라 Application.PV를 사용해야 한다. Worksheetfunction.PV는 타입미스매치에러를 낸다.
위의 계산은 Y배열의 원소 1과 2를 배열 X내 1번째 배열 원소 1, 3에 곱하고, 다시 배열 X내 2번째 배열 원소 2, 4에 곱하는 것이다. 즉 원소대 원소 곱셈이다.
  • 배열Y 원소와 배열X의 1번째 배열원소간 곱셈 : 1*1, 2*3
  • 배열Y 원소와 배열X의 2번째 배열원소간 곱셈 : 1*2, 2*4
비슷한 방법으로 덧셈도 할 수 있다.
Add = .Pmt(, -1, X, Y)
그리고 다음과 같이 몇 가지 연산을 할 수 있는데, 머리 아프니 고만 알아보자.
연산
코드
X-Y
SLN(x, y, 1)
X/Y
SLN(x, y)
X^Y
Power(x, y)
X\Y
Quotient(x, y)
X=Y
Delta(x, y)
X<=Y
GeStep(x, y)

VBA 배열에 앙심을 품은 자 오피스/VBA/Office.JS

언제부터 인지는 모르겠지만 VBA 배열을 다루는 게 은근 재미있다. 그래서 어떻게 괴롭힐까 고민을 한다. 벡터연산이 없는 VBA을 갖고, 비스무리한 걸 만드는 데 ()희열을 느낄지도 모른다. 이른 바 VBA 변태~

몇 달 전에 스택오버플로 포스팅을 하나 북마크 해두고 나중에 봐야지 했는데, 이번에 코드를 함 뜯어 볼 참이다. 코드는 다음과 같다. 코드는 같은 길이, 같은 타입을 가진 두 개의 배열을 가지고 각 배열의 매칭되는 원소끼리 곱하는 짓거리이다.

코드의 핵심은
z = [GetX()*GetY()]

이다.

GetX()와 GetY()는 전역변수인 X, Y 배열을 돌려주는 역할만 한다. []는 'Square brackets'라고 부르는 데, 우리말로는 꺽쇠(마당쇠같은 머슴이름 아님). 이것은 벡터연산의 핵심인 Evaluate함수의 줄임말로 보면 된다.
expression.Evaluate (Name)
A formula or the name of the object, using the naming convention of Microsoft Excel.
The length of the name must be less than or equal to 255 characters.

[]는 셀 참조를 하는 용도로도 사용한다. 가령 A1 셀을 참조하기 위해서는 Range("A1")이라고 하지만 간단히 [A1]으로 써도 된다. A1과 "A1"은 다른 것이다. A1은 실제 해당 셀을 가리키는 개체상수 정도로 보면 되고, "A1"은 그냥 문자열 상수이다.

Evaluate()함수는 문자열로 전달한 수식이나 함수 등을 계산하는 함수이다.
여기에 들어갈 요소는 엑셀에서 사용가능한 것들, 문자열, 숫자, 배열상수, 연산자, 수식, 함수 등이다. 다음은 마이크로소프트 오피스데브센터에 있는 Evaluate() 사용 예이다.
[a1].Value = 25 
Evaluate("A1").Value = 25

trigVariable = [SIN(45)]
trigVariable = Evaluate("SIN(45)")

Set firstCellInSheet = Workbooks("BOOK1.XLS").Sheets(4).[A1]
Set firstCellInSheet = _
Workbooks("BOOK1.XLS").Sheets(4).Evaluate("A1")
[]안에 배열 X, Y를 직접 넣으면 되지 않을 까 싶지만, 이 배열변수들은 엑셀이 아닌 VBA의 요소이다. 따라서 변수를 넣으면 타입미스매치 에러가 난다.

GetX(), GetY()함수는 엑셀 워크시트에서도 사용가능한 요소이다. 그러므로 Evaluate()함수에서 사용가능한 것이고 둘 사이에 있는 * 는 곱셈연산자인데, 이것 역시 엑셀에서 통용되는 연산자 기호이다.

그래서 X,Y를 전역변수로 두고, 이 변수를 그대로 전달만 해주는 매개체이다. 얘네들은 Evaluate()함수에서 사용가능한 자격이 있기 때문이다.
Dim X, Y

Function GetX(): GetX = X: End Function
Function GetY(): GetY = Y: End Function

Sub MultiplyArrays()
Dim z

X = Array(1, 2, 3, 4, 5)
Y = Array(1, 2, 3, 4, 5)

' []가 과연 뭘까요?
' 변수 X, Y를 직접 사용하지 않고 GetX(), GetY() 함수를 사용할까요?
z = [GetX()*GetY()]

' 합계도 한번 구해 보고,
Debug.Print WorksheetFunction.Sum(z)

' 엑셀 워크시트로 출력도 해본다
Range("A1").Resize(UBound(X)) = WorksheetFunction.Transpose(X)
Range("B1").Resize(UBound(Y)) = WorksheetFunction.Transpose(Y)
Range("C1").Resize(UBound(z)) = WorksheetFunction.Transpose(z)
End Sub
예를 하나 더 보자.
이번에는 배열상수값을 사용한 예이다. {"Zip", "22150";"City", "Springfield"; "State", "VA"}는 엑셀에서 지원하는 상수포맷을 따른다. 마치 JSON개체처럼 보이지만 세미콜론(;)으로 행이 구분되고 컴마(,)로 컬럼이 구분되는 행렬형태의 2차원 배열상수이다.
Sub UsingSquareBrackets()
'The [...] syntax is a shortcut for Application.Evaluate()

Dim vArray As Variant
Dim iCounter As Long

' {}는 무엇일까?
vArray = [{"Zip", "22150";"City", "Springfield"; "State", "VA"}]

For iCounter = LBound(vArray, 1) To UBound(vArray, 1)
Debug.Print vArray(iCounter, 1), vArray(iCounter, 2)
Next

End Sub
Evaluate()함수를 사용하지 않는 경우 어떻게 할까? 위의 코드에서는 배열에 입력해야 하는 값들이 모두 상수여서 활용성이 떨어진다. 다음은 Evaluate()함수를 사용하지 않는 평범한 VBA코드이다. 코드가 약간 길어진다.
Sub UsingArrayInArray()
Dim vArray As Variant

Dim iZip As Long
Dim sCity As String
Dim sState As String

iZip = 22150
sCity = "Springfield"
sState = "VA"
vArray = Array(Array("Zip", iZip), Array("City", sCity), Array("State", sState))

Dim iCounter As Long

For iCounter = LBound(vArray, 1) To UBound(vArray, 1)
Debug.Print vArray(iCounter)(0), vArray(iCounter)(1)
Next

End Sub

쟁고파이썬쉘을 좀 더 편하게 사용하기 파이썬/쟁고


어드민 사이트는 UI화면을 통해 사용자가 CRUD(Create, Read, Update, Delete)를 편하게 작업할 수 있게 해주지만, 다양한 데이터 관리를 위해서는 쟁고파이썬쉘을 이용하는 것이 편리하다. 특히 뷰를 작성하기 위한 테스트 코드를 작성할 때 유용한데, 쟁고파이썬쉘은 manage.py에서 정의한 DJANGO-SETTINGS_MODULE속성을 이용하여 미리 settings.py 모듈을 임포트한다.

다만 문제라면 >>> 프롬프트에서 작업하는 것이 고역이다. 그래서 스택오버플로에서 찾아보니 다분히 파이썬스러운 답이 있는 데, 여러 대안중 가장 맘에 드는 것은
$ ./manage.py shell
...
>>> exec(open('myscript.py').read())
이다.

(엑셀도감) 참조하는 넘, 참조당하는 넘 오피스/VBA/Office.JS

엑셀 사용하면서 수식을 사용하지 않는 사람은 없는 데, 수식에 걸어둔 셀로 이동하거나 본인을 참조한 셀로 이동하는 단축키이다.
그러나 수식에서 참조하는 모든 셀로 이동하는 것은 아닌 듯, 첫 셀이나 셀 영역으로 이동한다.

내침 김에 한글 팁 하나 더 오피스/VBA/Office.JS

오피스를 많이 사용하다가 한글을 사용하려니 불편한 점이 몇 가지 있어 비슷한 기능을 찾아 보게 된다. 이번에는 표안의 값을 수식으로 자동계산되는 기능이다. 워드에도 비슷한 기능이 있는 걸로 기억하는 데, 한글은 이 기능을 [블록 계산식]이라고 한다.

위와 같은 표에서 [매각소유일수]는 보유한 주식을 연속으로 처분하는 데 필요한 시간을 의미한다. 20일간의 평균거래량으로 보유한 주식수를 나눈 값이다. 사실 이런 예상치가 실제와는 큰 차이가 있을 걸로 보이는데, 그 얘기는 주제에 벗어나므로 여기까지만...

엑셀처럼 A,B,C 등 알파벳으로 컬럼을 표시하고 1,2,3 등 숫자로 행을 표시한다. 그래서 표의 최상단 왼쪽 셀은 A1이다. 그리고 같은 행의 오른쪽 컬럼은 B1, C1 등으로 표시하여 수식을 표현할 수 있다. 이런 주소 표현은 엑셀의 절대주소 표시방식과 비슷하다. 상대적인 주소 표현은 [쉬운 범위] 드랍다운박스에서 고를 수 있다. [함수]드랍다운 박스에서는 여러 함수가 있는 데, 이 정도의 함수지원이면 충분해 보인다.




살다보니 한글 팁을 쓰게 될 줄은 몰랐네~ 오피스/VBA/Office.JS

워드프로세서 한글을 그닥 좋아하지 않는 편이다. 정보의 활용측면에서 문서를 테이터로 활용하기 어려운 점이 이유이다. 과거 문서의 지향점이 출력을 해서 보관을 하며 읽기 편하고 이쁜 문서 자체가 목적이었다. 워드프로세서 한글은 아직 예전의 목적에만 부합한다는 생각이 든다. 그러나 아직 그런 목적으로 워드프로세서를 필요로 하고 사용하는 곳이 있으니 선택과 취향의 문제이다.

워드프로세서 한글을 사용하면서 고정적인 서식작업(글꼴, 배경색, 글자색 등등)을 한번에 할 수 없나 싶어 기능을 살펴 보았다. 글꼴은 '함초롱바탕', 글자색은 '빨강', 배경색은 '검정' 을 선택하는 과정을 하나의 틀로 만들어 도장 찍듯이 하는 기능이 필요했는데, [글자 모양]대화상자에 그런 기능이 있어 팁을 남기게 되었다.
미리 원하는 서식을 선택한다. 그리고 [대화 상자 설정(/)]의 [구성]을 클릭한다.
[+]버튼을 클릭하여 앞서 만든 서식의 이름을 입력하고 저장한다.
이제 원하는 부분을 선택하고 [글자 모양]대화상자에서 [대화 상자 설정(/)]의 [사용자 지정]콤보를 클릭하여 앞서 만든 이름을 선택하면 끝
그런데 이 기능을 눈에 보이게 좀 만들면 좋을 텐데, 대화상자 끄트머리에 두었으니, 눈여겨 보지 않으면 모를 것 같다. 또 기능에 대한 이름도 직관적이지 못해 보인다. 대화상자 설정(?), 구성(?) 등등 무슨 기능인지 ...

(엑셀도감) 열린 통합문서 이동 오피스/VBA/Office.JS


(엑셀도감) 행과 열 선택하기 오피스/VBA/Office.JS


(엑셀도감) 시트이동 단축 키 오피스/VBA/Office.JS

    워크시트 이동 단축 키
  • CTRL+PgUp 왼쪽 시트로 이동
  • CTRL+PgDn 오른쪽 시트로 이동



라디안(radian)을 설명하면서... 삽질의 추억

각도와 라디안을 설명하면서 90도를 라디안으로 계산하는 과정을 보여주었다. 간단한 계산이지만, 하나의 개념을 두 가지 방식으로 사용하는 건 불편한 듯하다.
    핵심공식은
  • 원둘레=pi*원의 지름=pi*2*반지름
  • 라디안=호의 길이/반지름
이다.



(엑셀도감)날짜를 가지고 요일 표시하기 오피스/VBA/Office.JS


[활용] 날짜를 요일로 표시하기
[재료] TEXT()함수와 날짜
[설명]
TEXT(날짜, “aaa”) – 월, 화, 수, 목, 금, 토, 일
TEXT(날짜, “aaaa”) – 월요일, 화요일, 수요일, 목요일, 금요일, 토요일, 일요일


화폐의 시간가치 증권

금융 관련한 교육을 전혀 받지 못한 대학 신입생에게 재무관리수업의 시간가치, 미래가치라는 개념은 마냥 신기했다. 그리고 PV/ FV같은 간단한 공식이 단순히 해를 구하는 방정식이 아니라, 각 변수가 의미가 있는 것이라 이를 이해하는 게 나름 재미있었다.

Texas Instrument, HP의 공학/재무계산기를 이제 사용하지 않지만, 모태솔로라도 절로 즐거운 벚꽃이 흩날리는 봄에 이를 가지고 조작하다 보면 뭔가 대단한 걸 배우는 기분이 들었다. 이제는 그 계산기가 어디로 갔는 지 알 수 없고, PV/ FV는 더 이상 관심이 요즘 말로 1도 없다.

대신 파이썬에서 지원하는, 정확히는 Numpy와 Scipy같은 라이브러리가 지원하는 시간가치 관련 함수를 정리해 보고 싶었다. Scipy의 금융관련 함수는 numpy.lib.financial에서 가져 온 것이다. 금융관련 함수가 뭐가 있을 까...출석만 불러보면...
pv(),fv(),pmt(),npv(),rate(),nper(),irr(),mirr(),ipmt(),ppmt()

이어지는 내용

마지막 셀의 값을 가져오기 오피스/VBA/Office.JS

주가와 같은 시계열 데이터를 다루다 보면 데이터를 새로 업데이트 할 때, 기존 데이터 뒤에 추가하기 마련이다. 그런데 최신의 데이터를 보거나 사용하려다 보니, 매번 데이터의 위치가 달라져 최근 업데이트 한 셀을 참조하기 어려울 수 있다. 이때 사용가능한 함수가 OFFSET()인데, 이 함수가 뭐 하는 함수인가를 설명하려다 보니 '오프셋' 또는 '변위'라는 말이 쉽게 다가오지 않는다.

알고 보면 쉬운 것이지만 말로 하면 길어진다. 그래서 그림을 하나 만들어 보았는 데, 그림만 보고 빨리 이해할 수 있는 지 궁금하기도 하다.

    (업데이트) 올리고 보니 생각나는 몇 가지 문제점(자아비판, 자아성찰)
  • 번호가 없어 어디서 부터 봐야하지 모름
  • 라인과 설명이 너무 많아 복잡해 보임
  • 처음의 아이디어대로 개념만 잡는 단순한 그림으로 변경필요
그래서 아래와 같이 몇 가지 도안을 다시 만들어 보았다.





가지 말아야 할 길 자바스크립트

웹프로그래밍이 재미난 세상이라 엿보기를 하는 중인데, 웹프로그래밍에 입문해볼까 하는 사람들에게 좋은 길잡이가 있군요.
직업이 아니라서 다행인데, 이렇게 복잡할 줄 몰라네요. 기껏 아는 건 프론트엔드-백엔드 정도인데...
[URL]개발자로드맵


뜻밖의 손님 삽질의 추억


출근하자마자 PC를 켜니 처음 보는 손님이 내 바탕화면에 떡 하니 자리 잡고 앉아 있다. 얼마 전 소식을 듣긴 했는데, 우선은 이리 가가호호 방문하여 공지를 날려주는 MS님에게 감사.


그런데 OS만 오래된 것은 아니다. PC를 사용중인 인간도... 사용하는 PC사양은 처음 사용해보는 AMD CPU가 달린 조립컴(2012년 Mid, ㅎㅎ 어디서 애플 흉내를...)이다. 그래도 코어수가 많아서 아직은 사용할만 하다.


(보라~ 광활한 4G 메모리를 다스리는 저 위대하신 옥타코어님의 위엄을...)

MS가 몹쓸 물건으로 낙인 찍었지만 Win10이 나오기 전까진 그래도 가장 맘에 들어하는 OS이다.  이걸 핑계로 회사컴퓨터 좀 바꿔달라고 해야지...근데 회사가 사정이 그리 좋친 않아서

고인물같은 아주 오래된 잡기술 삽질의 추억

VBA와 달달하던 시절(여친이랑 그래야지, 고작 프로그램 따위랑 달달?)에 Userform에 차트를 보여주는 팁이 있었다. 그림이라 인터랙티브하진 않지만 거지같은 Userform에 이런 걸 보여줄 수 있다는 걸 만드는 게 웬지 뿌듯했다(그래봐야 남의 코드 베낀 거지만)

대단한 기술처럼 아끼던 잡기였지만 이제와 보니 쓸데없는 짓거리(애초에 오피스프로그래밍이 쓸데없는 짓이지만)이다. MS는 Userform을 띄워 뭔가 입력하고 보여주라고 Userform을 만들었겠지만 사용자 입장에선 거추장스러운 것이고(워크시트에서 하면 될 걸, 윈도 애플리케이션 같은 모양새 갖춘다고 그런 삽질을...) Userform과 관련 컨트롤들이 VB나 C#의 그것만큼 그닥 유용하지 않다.


근데 오늘은 이런 짓거리를 할 필요가 생겼다. 만드는 웹사이트(즉 웹프로그램)에 쬐맨한 차트를 보여주고 싶은 데, 엑셀의 스파크 라인이 탐나는 것이다. 20개 남짓한 차트를 한 눈에 볼 수 있게 보여 주기 위해 highcharts 같은 거 쓰는 건 낭비일 듯 하여 셀안에 저장한 스파크 라인을 그림파일로 만들어 보여주려는 아이디어이다.

그래서 작성한 코드가...
    Dim rng As Range
Dim pathName As String

Application.Calculation = xlCalculationManual

For Each rng In shNAV.Range(shNAV.Range("B3"), _
shNAV.Range("B3").End(xlToRight))

Set rng = rng.Offset(-1, 0)
rng.CopyPicture xlScreen, xlBitmap

With ActiveSheet.ChartObjects.Add(Left:=rng.Left, _
Top:=rng.Top, Width:=rng.Width, Height:=rng.Height)

.Name = "SparklineChartEXPORT"
.Activate
End With

''' Paste into chart area, export to file, delete chart.
pathName = "C:\apps\foo\foo\static\" & _
rng.Offset(2, 0).Value2 & ".jpg"

ActiveChart.Paste
With ActiveSheet.ChartObjects("SparklineChartEXPORT")
.Chart.Export pathName
.Delete
End With
Next
Application.Calculation = xlCalculationAutomatic
이다. 처음 돌려보니 속도가 아무래도 느리다. 그럴만 하다. 클립보드에 들어간 데이터를 차트를 만들어(그림으로 저장하기 위해 이용하는 것일 뿐) 붙여 넣고, 그림으로 추출하고 지우는 걸 반복하고 있기 때문이다. 재미있는 점은 속도를 올리기 위해 Application.ScreenUpdating 를 False로 주었더니 스파크 라인이 없는 빈 그림만 만들어 진다. 화면 렌더링을 꺼두었으니 그럴 만하다.

막상 웹페이지에 띄워보니 비트맵이라 흐릿하다. 흠 더구나 투명이미지 파일이 아니라서 테이블의 배경과도 어울리지 않는다. 원상복구를 고민한다. 근데 이 포스팅은 카테고리를 엑셀/VBA로 분류해야 하나...아님 삽질로 분류해야 하나...

[추가 속보]
검색을 하다보니 jQuery Sparklines이라 게 있다. 고민 끝이다. 일단 원상복구후 하고 싶을 때, jQuery Sparklines로 고고씽~

1 2 3 4 5 6 7 8 9 10 다음