ic


여러 개의 시계열을 일자에 맞춰 데이터프레임으로 만들기 PYTHON


분석을 할 때 클렌징작업을 먼저 해야 하는데, 여러 개의 시계열 데이터를 하나의 데이터프레임으로 만드는 경우 휴장일을 처리해야 한다. 특히 여러 국가의 종가를 분석한다면 휴일처리를 어떻게 하느냐를 정해야 한다. 각국마다 휴일이 다르므로 공통된 영업일만 뽑아서 데이터를 만들어 두는 것도 방법이다.

Date, Open, High, Low, Close, Adj Close, Volume 컬럼으로 구성된 시계열데이터가 있는 여러개의 csv 파일(파일 하나가 종목)을 읽어 들여 하나의 데이터프레임으로 만드는 작업을 다음과 같이 하였다.
import pandas as pd

dfList=[]
symbols=['^AXJO','^FCHI','^GDAXI','^HSI','^IXIC','^N225','^GSPC']
path='D:\\Anaconda64\\'
for symbol in symbols:
df=pd.read_csv(path+symbol+'.csv', header=0, usecols=[0, 5], names=['Date','AdjClose'+symbol])
dfList.append(df)

pandas의 read_csv()함수를 사용하여 처리하는 데, 첫 번째 매개변수인 path+symbol+'.csv' 는 경로+파일명으로 읽어들이 파일을 지정한 것이다. header=0은 첫 번째 행이 컬럼의 타이틀, usecols=[0, 5]은 1번째와 6번째 컬럼(날짜와 수정주가), names=['Date','AdjClose'+symbol]은 데이터프레임 컬럼의 이름을 Date와 AdjClose+종목명으로 만들기 위한 것이다.

이렇게 읽어 들인 결과는 데이터프레임으로 돌려받으며, dfList라는 리스트에 생성된 df를 추가하여 모아둔다(dfList.append(df))

그런데 3줄 짜리 for루프가 다분히 python이 아닌 vb스러운 것이라 맘에 들진 않아 다음과 같이 고쳐 보았다(싱글라인 또는 인라인 for 루프를 만드느라 머리 CPU 점유율이 상승...)
import pandas as pd

dfList=[]
symbols=['^AXJO','^FCHI','^GDAXI','^HSI','^IXIC','^N225','^GSPC']
path='D:\\Anaconda64\\'
[dfList.append(pd.read_csv(path+symbol+'.csv', header=0, usecols=[0, 5], names=['Date','AdjClose'+symbol])) for symbol in symbols]

이번에는 리스트에 담긴 df를 하나 하나 꺼내서 Date컬럼을 기준으로 공통된 일자에 마추어 정리할 차례이다.
merged=dfList[0]
for df in dfList[1:]:
merged=pd.merge(merged, df, how='inner', on='Date')

일단 merged에 1번째 df를 담아두고서 pandas의 merge()함수를 이용하여 다음 번 df와 merged를 Date컬럼을 기준으로 이너조인하면 공통된 일자의 주가데이터를 갖게 된다. 이것 역시 for루프를 사용하지 않고 reduce()함수를 사용하여 간결하게 처리한다. 그런데 reduce()함수는 예전과 달리 functools 라이브러리로 분리된 관계로 따라 임포트해야 한다.
from functools import reduce

merged=reduce(lambda x, y: pd.merge(x, y, how='inner', on = 'Date'), dfList)

이제 Date를 인덱스로 지정하고, S&P500을 벤치마크지수로 삼기 위해 따로 떼어놓았다.
merged=merged.set_index('Date')
sp500=merged[['AdjClose^GSPC']]





VBA가 루프없이 연산하는 썰 EXCEL/VBA


얼마 전 Stackoverflow에 VBA: Is there a way to apply a single formula to a column without looping through each cell라는 질문이 올라왔는데, 심심하면 VBA의 한계를 건들려보던 차라 이 질문을 모른 척하고 지나갈 수 없었다.

I'm quite new in VBA and was looking for ways on how to apply the same formula to all cells in a column. I have 5000 rows and I would simply like to multiply row values in Column 1 with row values in Column 2 and show the results of the same row in Column 3.

I have tried looping through each of the cells:

For i = 1 to 5000

Next i

but the calculation was slow and was wondering if there is another way to calculate all 5000 rows quicker.

I actually have 60 columns with different formulas and conditional statements which slows down the calculation process. I am actually looking for a simpler way to 'BULK' apply a certain formula to the whole column.

VBA초보인데, 5000개의 행에 곱셈연산을 하는 수식을 넣고 싶은데, For 루프를 돌리려니 너무 느려 반복문없이 한번에 통으로 수식을 적용하고 싶다는 글이다.

VBA초보라서 Application.ScreenUpdating이나 Application.Calculation을 건드려볼 생각은 못한 듯... 아마 그거라도 해놓으면 다소나마 처리가 빨라졌을 지도...

간단한 곱셈을 하는 예를 들어 보자. A1:A5000과 B1:B5000 셀 영역에 값이 들어가 있고 C1:C5000에 곱셈연산을 한다면 다음과 같이 루프를 돌리지 않고 간단하게 해결할 수 있다.
Sheet1.Range("C1:C5000").Formula = "=RC[-2]*RC[-1]"


C컬럼을 기준으로 RC[-2]은 오른쪽으로 2칸 떨어진 A열을 의미하고 RC[-1]은 1칸 떨어진 B열을 의미한다. 물론 R은 같은 행을 말한다. 그런데, 이것 역시 수식이 5000개 붙은 거라 이후에 자동재계산의 부담이 따른다. 그래서 곱셈의 결과만 돌려주는 걸로 바꾸었다.
Sheet1.Range("C1:C5000") = Application.Evaluate("(A1:A5000)*(B1:B5000)")


질문자는 간단한 설명을 위해 아니면 업무내용을 보이기 싫어 단순한 곱셈질문을 하였지만 실제 적용하는 데 애를 먹고 있었다. 실제 사용하는 수식은 M6=(B6-B5)*L5 + M5 같은 식이다. M6 연산에는 이전 연산의 결과인 M5를 참조하고 있다. 엑셀에선 배열수식으로 처리가능하지만 아래와 같은 VBA의 처리결과는 달랐다.
.Range(M6:M5004) = Application.Evaluate("(B6:B5004-B5:B5003)*(L5:L5003)+(M5:M50‌​03)")

Application.Evaluate는 문자열로 된 수식을 연산하는 것이고 어느 정도 배열수식도 적용가능하다. 수식에서 +(M5:M50‌​03)을 빼고 돌려본 결과는 엑셀의 결과와 같은 걸 보니 문제는 +(M5:M50‌​03)인 듯하다. Application.Evaluate의 연산방식을 알 순 없지만 짐작이 가는 것은 결과를 출력하는 .Range(M6:M5004)과 셀 영역이 겹치고 순환참조와 같은 게 발생하는 듯하다. 엑섹의 배열수식은 순차적으로 루프처럼 수식을 계산하는 반면 Application.Evaluate는 한번에 연산하는 관계로 미처 M열의 이전 셀값이 0인 상태에서 연산을 하기 때문에 배열수식과는 미묘하게 다를 수 있다는 썰을 풀어본다.

현재로서 그나마 대안은 배열수식으로 처리하고 수식을 값복사하여 마무리하는 걸로...

Sheet2.Range("M6:M5004").FormulaArray = "=((B6:B5003)-(B5:B5003))*(L5:L5003)+(M5:M5003)"
Sheet2.Range("M6:M5004").Copy
Sheet2.Range("M6:M5004").PasteSpecial xlPasteValues
Application.CutCopyMode = False


다음 번에 Application.Evaluate와 관련된 썰을 해볼 까 한다.






살벌한 파이썬 수강생들 PYTHON

Life is short, You are too long~




오늘의 삽질은... 삽질


주가 시계열 정보가 있는 CSV 파일을 읽어서 예측하는 걸 만드는 중인데, 이상하게 '9'라는 컬럼이 NaN, NaN, NaN,...하면 눈에 거슬린다. 어 이상하다~ 이런 컬럼이 왜 생겼지? 지난 번엔 안보였는데... 데이터프레임을 만들면서 컬럼이름을 변경하는 부분이 있는 데, 혹시 거기서...

결론은 CSV파일중 하나에 1행에서 9라는 값을 입력하고 저장했는데 이런 이상한 일을 만든 것이다. 아무래도 엑셀에서 뭔가 작업을 하다가 저장한 듯...다시 코드 원상복구하고...

numpy의 matrix slicing PYTHON

numpy는 그 자체도 훌륭하지만 scipy나 pandas와 같은 훌륭한 라이브러리가 탄생할 수 있는 배경이 되어 더욱 값진 존재이다. 그런데 numpy의 matrix를 다룰 때, 더 정확히 sub matrix를 다룰 때 주의할 점이 하나 있다. 그냥 아래의 코드를 보면 뭘 주의해야 하는 지 알 수 있다.
import numpy as np
mat = np.array([[11,12,13],[21,22,23],[31,32,33]])
print("Original matrix")
print(mat)

mat_slice = mat[:2,:2] # Simple indexing
print ("\nSliced matrix")
print(mat_slice)

print ("\nChange the sliced matrix")
mat_slice[0,0] = 1000
print (mat_slice)

print("\nBut the original matrix? WHOA! It got changed too!")
print(mat)


다음은 위의 코드 실행결과이다

Original matrix
[[11 12 13]
[21 22 23]
[31 32 33]]

Sliced matrix
[[11 12]
[21 22]]

Change the sliced matrix
[[1000 12]
[ 21 22]]

But the original matrix? WHOA! It got changed too!
[[1000 12 13]
[ 21 22 23]
[ 31 32 33]]


위와 같은 결과는 c/c++의 포인터나 vb/vba의 참조에 의한 전달처럼 필요한 경우도 있어 이를 굳이 부작용이나 권장하지 않는다라고 말할 필요는 없다. 그러나 위의 결과가 원래 의도한 것이 아니라 sub matrix와 original matrix가 각각 별개로 하려면 array함수를 사용하여 새 걸로 만들어줘야 한다.
# Little different way to create a copy of the sliced matrix
print ("\nDoing it again little differently now...\n")
mat = np.array([[11,12,13],[21,22,23],[31,32,33]])
print("Original matrix")
print(mat)

mat_slice = np.array(mat[:2,:2]) # Notice the np.array method
print ("\nSliced matrix")
print(mat_slice)

print ("\nChange the sliced matrix")
mat_slice[0,0] = 1000
print (mat_slice)

print("\nBut the original matrix? NO CHANGE this time:)")
print(mat)


다음은 위의 코드 실행결과이다.
Doing it again little differently now...

Original matrix
[[11 12 13]
[21 22 23]
[31 32 33]]

Sliced matrix
[[11 12]
[21 22]]

Change the sliced matrix
[[1000 12]
[ 21 22]]

But the original matrix? NO CHANGE this time:)
[[11 12 13]
[21 22 23]
[31 32 33]]



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