티스토리 뷰

Table of Contents

  1. Introduction
  2. 환경 준비
  3. TabPy와 Tableau 연결
  4. Tableau에서 Python을 사용한 수요 예측
  5. Conclusion
  6. References

Introduction

Business Intelligence 대시보드를 구축하기 전 단계인 환경 설정부터, SARIMAX 모델을 Tableau에서 사용하여 수요 예측을 하는 단계까지의 과정과 방법을 담았다. 이 글을 보면 다른 자료를 찾아다니지 않아도 수행 가능하도록, 태블로에서 TabPy를 사용하여 모델을 구동하는 과정을 모두 정리하였다.

 

환경 준비

ⓐ파이썬 설치 -> ⓑ파이썬 가상환경 준비 -> ⓒTabPy 설치 -> ⓓTabPy와 파이썬 가상환경 연결, 순서로 Python과 TabPy를 사용할 수 있는 환경을 만들어 준다. 이러한 고전적 방법에서 벗어나서 조금 더 편리한 환경을 준비하기 위해서 'Anaconda'를 사용할 수 있다.

 

파이썬 패키지들이 포함된 '아나콘다(Anaconda)'를 설치한다. (아나콘다 설치 방법 여기를 참고.) 아나콘다의 단점은 용량이 크다는 것이다. 내가 설치하면서 확인하니 3GB의 용량이 필요하다. 또한, 유료화가 되어 개인 외에는 사용 시 비용을 지불해야 한다. 만약, 기존에 파이썬을 설치해두었다면 Uninstall을 먼저 하여 완전히 삭제한 후 Anaconda를 설치한다. (파이썬 삭제 방법 여기를 참고.)

 

아나콘다를 설치하는 과정에서 다음과 같은 메시지가 뜬다면, 설치 경로를 재설정해주어 해결한다. 메시지 내용: 'anaconda destination folder contains 1 space. this can cause problems with several conda packages. please consider removing the space.'

 

명령 프롬프트(cmd)에서 아나콘다 가상환경을 생성한 후, TabPy를 설치한다. TabPy 설치 전, pip를 설치하고 업데이트해야 한다. 그런 다음, TabPy를 install 하면 환경설정은 끝난다.

 

아나콘다 가상환경 설정 명령어

conda create --name my-tabpy-env

pip update 명령어

python -m pip install --upgrade pip

TabPy install 명령어

pip install tabpy

 

TabPy와 Tableau 연결

http://localhost:9004로 접속해서 TabPy가 잘 설치되었는지 확인한다. Tableau Desktop을 실행해서 Analytics 확장 프로그램으로 TabPy를 연결한다. 호스트는 localhost, 포트는 9004를 입력하고, 연결테스트를 통해 연결한다. 그러면, 태블로에서 Python 코드를 사용한 Model로 Demand forecasting을 할 수 있는 준비가 완료된다.

 

Tableau에서 Python을 사용한 수요 예측

1. 데이터 준비
2. 매개변수 생성
3. 계산된 필드 생성

 

매개변수(Parameter)는 필요에 따라 생성 여부를 선택하면 된다. 중요한 건 계산된 필드(Caculated Field)이다.

처음에는 왜 이렇게 계산된 필드를 만들어야 하는지 모를 수 있다. 일단 끝까지 완주하면 왜 이렇게 계산된 필드를 만들어야 하는지 이해하게 된다. 계산된 필드에 사용된 함수들은 태블로에서 사용되는 함수이다. SQL이랑 비슷해서 어렵지 않지만, 의미를 정확히 알려면 Tableau 함수이름 형식으로 구글링하면 태블로 공식 문서가 나오니 읽어보면 된다.

 

SCRIPT_REAL(
"
import pandas as pd
from pandas.tseries.offsets import DateOffset
from statsmodels.tsa.statespace.sarimax import SARIMAX

dates = _arg1
sales = _arg2
customers = _arg3
wind = _arg4
sunshine = _arg5
tem = _arg6
holiday = _arg7
rain = _arg8
order_ar = min(_arg9)
order_i = min(_arg10)
order_ma = min(_arg11)
months_forecast = min(_arg12)
seasonal_ar = min(_arg13)
seasonal_i = min(_arg14)
seasonal_ma = min(_arg15)
period = min(_arg16)

data = pd.DataFrame({'Dates':dates, 'Sales(Won)':sales, 'Customers':customers, 'Wind_mean(m/s)':wind, 'Sunshine_mean':sunshine, 'Temperature_mean(°C)':tem, 'Is_holiday':holiday, 'Rain_sum(log)':rain})
data['Dates']=pd.to_datetime(data['Dates'])
data = data.set_index('Dates')

train_set = data.iloc[0:53, 0:]
forecast_set = data.iloc[53:, 0:]

endog = train_set.iloc[:, :1]
exog = train_set.iloc[:, 1:]

model = SARIMAX(endog = endog, order=(order_ar, order_i, order_ma), seasonal_order=(seasonal_ar, seasonal_i, seasonal_ma, period), exog = exog)

results = model.fit()

observed_pred_data = endog
observed_pred_exog = exog
forecasting_data = pd.DataFrame(forecast_set.iloc[:, :1])
forecasting_exog = forecast_set.iloc[:, 1:]

pred = results.get_prediction(start=pd.to_datetime('2017-01-01'), end=pd.to_datetime('2021-05-01'), exog=observed_pred_exog, dynamic=False)
forecasted = results.predict(start=pd.to_datetime('2021-06-01'), end=pd.to_datetime('2021-08-01'), exog=forecasting_exog, dynamic=False)

pred_value_data = list(pred.predicted_mean)
pred_value_data.extend(forecasted)

return pred_value_data
"
,
ATTR([Dates]),
ATTR([Sales(Won)]),
ATTR([Customers]),
ATTR([Wind mean(m/s)]),
ATTR([Sunshine mean]),
ATTR([Temperature mean(°C)]),
ATTR([Is holiday]),
ATTR([Rain sum(log)]),
MIN([AR (Time lag)]),
MIN([I (Seasonal Difference)]),
MIN([MA (Moving Average)]),
MIN([Months Forecast]),
MIN([Seasonal AR (Time Lag)]),
MIN([Seasonal I (Seasonal Difference)]),
MIN([Seasonal MA (Moving Average)]),
MIN([Period])
)
SCRIPT_REAL(
"
import pandas as pd
from statsmodels.tsa.statespace.sarimax import SARIMAX

#데이터에서 받아올 값 설정 
dates = _arg1
sales = _arg2
order_ar = min(_arg3)
order_i = min(_arg4)
order_ma = min(_arg5)
months_forecast = min(_arg6)
seasonal_ar = min(_arg7)
seasonal_i = min(_arg8)
seasonal_ma = min(_arg9)
period = min(_arg10)

#모델 생성 및 훈련
endog = pd.Series(data=sales, index=dates)

model = SARIMAX(endog = endog, order=(order_ar, order_i, order_ma), seasonal_order=(seasonal_ar, seasonal_i, seasonal_ma, period))

results = model.fit()

#기간 내 및 기간 외 예측
pred = results.get_prediction(start=(pd.to_datetime('2017-01-01')) + pd.DateOffset(months=months_forecast), dynamic=False)
pred_uc = results.get_forecast(steps=months_forecast)

data = list(pred.predicted_mean)
data.extend(pred_uc.predicted_mean)

return data
"
,
ATTR([Dates]),
ATTR([Sales(Won)]),
MIN([AR (Time lag)]),
MIN([I (Seasonal Difference)]),
MIN([MA (Moving Average)]),
MIN([Months Forecast]),
MIN([Seasonal AR (Time Lag)]),
MIN([Seasonal I (Seasonal Difference)]),
MIN([Seasonal MA (Moving Average)]),
MIN([Period])
)

차례대로 SARIMAX, SARIMA를 태블로에서 구현한 코드이다. start, end 값은 날짜를 직접 입력하는 대신 인덱스로 지정해주어도 된다. 결과만 보면 간단해 보이는데, 과정은 결코 간단하지 않았다. 결과적으로, Colab에서 구현한 예측 결과와 Tableau에서 구현한 예측 결과가 같게 나오는 결과물을 만들었다.

 

Conclusion

태블로에서 모델이 작동하는 구조를 이해하는데 시간이 꽤 들었고, 모델이 태블로에서 예측을 수행하도록 구현하는데도 시간이 많이 걸렸다. 왜냐하면, 공식 지침이 있더라도 응용문제는 안 알려주기 때문에 알아서 방법을 찾아나가야 하고, Tableau에서 SARIMAX를 구현하는 방법에 대한 자료가 없었기 때문이다. References에서 참고한 SARIMA, ARIMA 예시를 그대로 따라 한다고 구현되지 않는다. 이걸 바탕으로 알아서 공부하고 응용해야 한다. 또한, 오류가 나도 태블로는 어느 부분이 문제가 되는지까지 친절히 알려주지 않기 때문에, 감과 직관을 발휘해서 해결해야 한다.

 

References

https://github.com/tableau/TabPy/blob/master/docs/server-install.md
https://github.com/tableau/TabPy/blob/master/docs/tabpy-virtualenv.md
https://youtu.be/oX1UM87-Oyk
https://towardsdatascience.com/forecasting-with-python-and-tableau-dd37a218a1e5

https://towardsdatascience.com/tableau-your-time-series-forecast-with-tabpy-5c09c151477f

https://www.clearpeaks.com/tableau-python/

https://www.blastanalytics.com/blog/tableau-python-forecasting-improve-your-accuracy

댓글
최근에 올라온 글
페이지 이동 안내

보던 글 목록 : 브라우저 뒤로 가기 메인 화면 : 좌측 상단 아이콘
🍍 The GOAL: AI expert에 가까워지는 중

🍍 I am becoming AI expert who can develop cool things by coding.