Python과 Oracle 연동

개요

  • 파이참에서 가상환경을 만들어 오라클 연동 예제를 작성한다.
  • 아나콘다, 파이참, 그리고 오라클 설치는 생략한다.

1. 가상환경 활성화

  • cmd 창에서 가상 환경을 세팅 하도록 한다. (권장: 관리자 실행)
  • 바탕화면에 필자는 python_oracle 폴더를 생성했다.
  • 현재 경로는 아래와 같다.
C:\Users\1\Desktop\python_oracle> 
  • 먼저 가상환경을 만든다.
conda create --name your_env_name python=3.8
.
.
done
#
# To activate this environment, use
#
#     $ conda activate python_oracle
#
# To deactivate an active environment, use
#
#     $ conda deactivate
  • your_env_name 대신 다른 이름으로 설정해도 된다.
  • 가상 환경에 접속한다.

C:\Users\1\Desktop\python_oracle>conda activate python_oracle
(python_oracle) C:\Users\1\Desktop\python_oracle>

2. 필수 라이브러리 설치

  • ML을 위한 필수 라이브러리를 설치한다.
  • pycaret & oracle
(python_oracle) C:\Users\1\Desktop\python_oracle>pip install pycaret
.
.
.
... wordcloud-1.8.1 yellowbrick-1.3.post1
(python_oracle) C:\Users\1\Desktop\python_oracle>pip install cx_Oracle
Collecting cx_Oracle
  Downloading cx_Oracle-8.2.1-cp38-cp38-win_amd64.whl (219 kB)
     |████████████████████████████████| 219 kB 2.2 MB/s
Installing collected packages: cx-Oracle
Successfully installed cx-Oracle-8.2.1
(python_oracle) C:\Users\1\Desktop\python_oracle> deactivate
  • deactivate 한 뒤, lsnrctl status 명령어를 통해 확인한다.
C:\Users\1\Desktop\python_oracle>lsnrctl status
LSNRCTL for 64-bit Windows: Version 19.0.0.0.0 - Production on 16-7월 -2021 10:28:24

Copyright (c) 1991, 2019, Oracle.  All rights reserved.

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))에 연결되었습니다
리스너의 상태
------------------------
별칭                     LISTENER
버전                     TNSLSNR for 64-bit Windows: Version 19.0.0.0.0 - Production
시작 날짜                 13-7월 -2021 17:21:03
업타임                   217 시간. 7 분. 25트레이스 수준            off
보안                     ON: Local OS Authentication
SNMP                     OFF리스너 매개변수 파일   C:\ORACLE\WINDOWS.X64_193000_db_home\network\admin\listener.ora
리스너 로그 파일         C:\ORACLE\diag\tnslsnr\DESKTOP-F7LRGM5\listener\alert\log.xml
끝점 요약 청취 중...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=127.0.0.1)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(PIPENAME=\\.\pipe\EXTPROC1521ipc)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=DESKTOP-F7LRGM5)(PORT=5500))(Security=(my_wallet_directory=C:\ORACLE\admin\orcl\xdb_wallet))(Presentation=HTTP)(Session=RAW))
서비스 요약...
"CLRExtProc" 서비스는 1개의 인스턴스를 가집니다.
  "CLRExtProc" 인스턴스(UNKNOWN 상태)는 이 서비스에 대해 1 처리기를 가집니다.
"orcl" 서비스는 1개의 인스턴스를 가집니다.
  "orcl" 인스턴스(READY 상태)는 이 서비스에 대해 1 처리기를 가집니다.
"orclXDB" 서비스는 1개의 인스턴스를 가집니다.
  "orcl" 인스턴스(READY 상태)는 이 서비스에 대해 1 처리기를 가집니다.
명령이 성공적으로 수행되었습니다
  • (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))에 연결되었습니다

3. 연동코드 작성

  • 필수 정보를 확인한다.
    • IP주소: localhost
    • Port번호: 1521
    • 서비스이름: orcl
  • JupyterLab을 연 후 코드를 작성한다. (관리자 살행)
    • 가상환경 python_oracle 으로 연결이 되어 있는지 확인한다.

In ML, Data Leakage - 2

머신러닝 전처리 자주하는 안 좋은 습관들 모음

Sample 데이터

  • 먼저 가상의 데이터를 하나 생성합니다.
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

random_state = 42
X, y = make_regression(random_state = random_state, n_features = 1, noise = 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.4, random_state = random_state)

Inconsistent preprocessing

  • 모델을 학습시킬 때 이러한 데이터 변환을 사용하는 경우 테스트 데이터든 프로덕션 시스템의 데이터든 후속 데이터셋에도 사용해야 합니다. 그렇지 않으면 피쳐 공간이 변경되고 모델이 효과적으로 수행되지 않습니다.

Wrong

  • 먼저, 잘못된 방식을 소개합니다.
  • train 데이터에는 scaler가 적용되었지만, 테스트 데이터에는 적용되지 않았습니다. 따라서, 이러한 경우 모델 성능이 예상보다 떨어질 수 있습니다.
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_transformed = scaler.fit_transform(X_train)
model = LinearRegression().fit(X_train_transformed, y_train)
mean_squared_error(y_test, model.predict(X_test))
62.80867119249524
  • Non-Transformed X_test 데이터를 예측값으로 넣으려면 X_train과 마찬가지로 동일하게 transform을 적용해야 한다.
scaler = StandardScaler()
X_train_transformed = scaler.fit_transform(X_train)
X_test_transformed = scaler.transform(X_test)
model = LinearRegression().fit(X_train_transformed, y_train)
mean_squared_error(y_test, model.predict(X_test_transformed))
0.9027975466369481
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline

random_state = 42
X, y = make_regression(random_state = random_state, n_features = 1, noise = 1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.4, random_state = random_state)

model = make_pipeline(StandardScaler(), LinearRegression())
model.fit(X_train, y_train)
mean_squared_error(y_test, model.predict(X_test))
0.9027975466369481

Data Leakage

  • 모델을 구축할 때 예측 시점에 사용할 수 없는 정보가 사용될 때 데이터 누출이 발생함.
  • 이로 인해 교차 검증 시, 매우 낙관적인 성능 추정치가 발생하기도 하며, 실제 새로운 데이터와 만날 때는 성능이 매우 크게 저하 되기도 함.
  • 훈련 및 테스트 데이터 하위 집합 모두 이전 섹션에서 설명한 것과 동일한 전처리 변환을 받아야 하지만,
  • 이러한 변환은 훈련 데이터에서만 학습되는 것이 중요하다. 예를 들어 평균값으로 나누는 정규화 단계가 있는 경우 평균은 모든 데이터의 평균이 아니라 훈련 데이터 하위 집합의 평균이어야 합니다. 테스트 하위 집합이 평균 계산에 포함되는 경우 테스트 하위 집합의 정보가 모델에 영향을 줍니다.
  • Data Leakage가 발생하는 몇가지 상황을 살펴본다.

Data Leakage During Pre-Processing

  • 우선 가상의 데이터를 만듭니다.
import numpy as np 
n_samples, n_features, n_classes = 200, 100000, 2
rng = np.random.RandomState(42)
X = rng.standard_normal((n_samples, n_features))
y = rng.choice(n_classes, n_samples)

print(X.shape, y.shape)
(200, 100000) (200,)

Wrong

  • 이제 transformation부터 머신러닝 학습, 그리고 평가까지 진행한다.
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score

# 여기 부분이 잘못 되었다. 
X_selected = SelectKBest(k=25).fit_transform(X, y)

X_train, X_test, y_train, y_test = train_test_split(X_selected, y, random_state=42)
gbc = GradientBoostingClassifier(random_state=1)
gbc.fit(X_train, y_train)

y_pred = gbc.predict(X_test)
accuracy_score(y_test, y_pred)
0.72

Right

  • Data Leakage를 예방하기 위해 먼저 train 데이터와 test 데이터를 분리한다.
  • fit이나 fit_transform은 train 데이터에만 적용한다.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 42)
select = SelectKBest(k=25)

X_train_selected = select.fit_transform(X_train, y_train)
gbc = GradientBoostingClassifier(random_state = 1)
gbc.fit(X_train_selected, y_train)
GradientBoostingClassifier(ccp_alpha=0.0, criterion='friedman_mse', init=None,
                           learning_rate=0.1, loss='deviance', max_depth=3,
                           max_features=None, max_leaf_nodes=None,
                           min_impurity_decrease=0.0, min_impurity_split=None,
                           min_samples_leaf=1, min_samples_split=2,
                           min_weight_fraction_leaf=0.0, n_estimators=100,
                           n_iter_no_change=None, presort='deprecated',
                           random_state=1, subsample=1.0, tol=0.0001,
                           validation_fraction=0.1, verbose=0,
                           warm_start=False)
X_test_selected = select.transform(X_test)
y_pred = gbc.predict(X_test_selected)
accuracy_score(y_test, y_pred)
0.5
  • 이번에는 Pipeline을 통해 구성하도록 한다.
from sklearn.pipeline import make_pipeline

X_train, X_test, y_train, y_test = train_test_split(
    X, y, random_state=42)

pipeline = make_pipeline(SelectKBest(k=25), 
                         GradientBoostingClassifier(random_state=1))

pipeline.fit(X_train, y_train)
Pipeline(memory=None,
         steps=[('selectkbest',
                 SelectKBest(k=25,
                             score_func=<function f_classif at 0x7f56a7c7f5f0>)),
                ('gradientboostingclassifier',
                 GradientBoostingClassifier(ccp_alpha=0.0,
                                            criterion='friedman_mse', init=None,
                                            learning_rate=0.1, loss='deviance',
                                            max_depth=3, max_features=None,
                                            max_leaf_nodes=None,
                                            min_impurity_decrease=0.0,
                                            min_impurity_split=None,
                                            min_samples_leaf=1,
                                            min_samples_split=2,
                                            min_weight_fraction_leaf=0.0,
                                            n_estimators=100,
                                            n_iter_no_change=None,
                                            presort='deprecated',
                                            random_state=1, subsample=1.0,
                                            tol=0.0001, validation_fraction=0.1,
                                            verbose=0, warm_start=False))],
         verbose=False)
  • 테스트 데이터는 예측을 할 때만 사용하도록 한다.
y_pred = pipeline.predict(X_test)
accuracy_score(y_test, y_pred)
0.5
  • Pipeline은 cross_val_score에 직접 사용할 수도 있다.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(pipeline, X, y)
print(f"Mean accuracy: {scores.mean():.2f}+/-{scores.std():.2f}")
Mean accuracy: 0.52+/-0.04

In ML, Data Leakage - 1

Data Leakage

  • 모형 평가를 하기 전에 전체 데이터셋을 가공 및 변환함.
  • 이를 평가에 반영하면 새로운 데이터를 예측할 때 부정확한 결과를 도출 할 수 있음.
  • 이를 방지 하기 위해서는 training 데이터만 데이터 전처리를 수행하는 것이 바람직함.
  • Data Leakage를 피하기 위해서는 scikit-learn modeling pipeline을 설계해햐 함.

데이터 준비

  • 가상의 데이터를 준비한다.
  • 데이터는 모두 수치형 데이터로 준비했다.
from sklearn.datasets import make_classification
X, y = make_classification(n_samples = 1000, n_features = 20, n_informative = 15, n_redundant = 5, random_state = 7)

# summarize the dataset
print(X.shape, y.shape)
(1000, 20) (1000,)

일반적인 방법의 데이터 전처리

  • 수치형 데이터이기 때문에, MinMaxScaler 클래스를 활용한다.
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
X = scaler.fit_transform(X)
  • 이번에는 데이터셋을 분리하도록 한다.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state = 7)
  • 이번에는 로지스틱 회귀분석을 시행한다.
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
model.fit(X_train, y_train)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=100,
                   multi_class='auto', n_jobs=None, penalty='l2',
                   random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
                   warm_start=False)
  • 이제 모형을 평가하도록 합니다.
from sklearn.metrics import accuracy_score

yhat = model.predict(X_test)
accuracy = accuracy_score(y_test, yhat)

print('Accuracy: %.3f' % (accuracy * 100))
Accuracy: 84.848
  • 이것이 일반적인 방법론이다. 그러나 엄밀히 말하면 Data Leakage 현상이 나타났다고 볼 수 있다.

Data Leakage 피하는 방법

  • 이번에는 먼저 데이터 셋을 분리하도록 합니다.
  • Train 데이터에만 scaler를 적용하도록 합니다.
from sklearn.utils.validation import check_random_state

X, y = make_classification(n_samples = 2000, n_features = 20, n_informative = 15, n_redundant = 5, random_state = 7)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state = 1)
  • 그 후, X_train과 X_test에만 scaler를 적용한다.
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
  • 이제 모형을 만든 후, 결괏값을 적용합니다.
model = LogisticRegression()
model.fit(X_train, y_train)
yhat = model.predict(X_test)
accuracy = accuracy_score(y_test, yhat)

print('Accuracy: %.3f' % (accuracy * 100))
Accuracy: 88.333
  • 결과를 보면 알겠지만, 모형의 성능에도 좋지 않음을 올 수 있다.

Reference

Jason Brownlee. 2020. How to Avoid Data Leakage When Performing Data Preparation. Retrieved from https://machinelearningmastery.com/data-preparation-without-data-leakage/

엑셀 데이터 가공하기 변환

강의 홍보

개요

  • 정리되지 못한 엑셀 파일을 불러와서 하나의 테이블을 만드는 과정을 진행해본다.

  • 위 데이터를 원본 그대로 받아서 pandas 데이터 프레임에 추가한다.
  • A3 셀에 있는 [시·도지사선거][서울특별시][강남구] 분리하여 각 column에 추가한다.

라이브러리 불러오기

  • 3개의 라이브러리를 불러온다.
import pandas as pd
import openpyxl
import os

파일 확인

  • data 폴더 내 데이터를 확인한다.
  • 추후, 엑셀 데이터만 추려서 반복문을 활용하여 동일하게 처리할 수 있도록 상상을 한다.
print(os.listdir('data'))
['1 강남구-[2021년_재·보궐선거]_개표단위별_개표결과.xlsx', '.DS_Store', '~$1 강남구-[2021년_재·보궐선거]_개표단위별_개표결과.xlsx']

openpyxl 라이브러리 할용

  • openpyxl 라이브러리는 A Python library to read/write Excel 2010 xlsx/xlsm files을 가지고 있다.
  • 먼저 A3 셀에 있는 [시·도지사선거][서울특별시][강남구] 데이터를 가져오도록 한다.
  • 이 때, openpyxl 라이브리를 활용하면 각 셀에 접근해서 개별적으로 데이터를 가져올 수 있다.
DATA_PATH = "data"
FILE_PATH = os.listdir(DATA_PATH)[0]
wb_obt= openpyxl.load_workbook("data/" + FILE_PATH) 
sheet = wb_obt.active
values = sheet["A3"].value
values
'[시·도지사선거][서울특별시][강남구]'

문자열 전처리

  • 먼저 하나의 셀로 연결되어 있는 것을 각각 분리하도록 하는 코드를 작성한다.
  • strip(‘pattern’)는 특정 문자를 제거하는 것이고, split(‘pattern’)는 문자열을 특수문자로 분리하는 것이다.
city_list = values.strip("[]").split("][")
city_list
['시·도지사선거', '서울특별시', '강남구']

데이터 수집 및 전처리

  • 이 때 중요한 parameters는 skiprows, header이다.
  • 먼저 skiprows는 특정 행은 건너 뛴다는 의미를 가지고 있다. 즉, 데이터프레임에 접근하기 전까지의 행은 건너 뛴다는 의미다.
  • header는 엑셀의 열에 해당하는데, 본 데이터에서는 multiple headers가 있다. 따라서, 이를 리스트 처리하면 해당 열은 모두 가져올 수 있다.
df = pd.read_excel("data/1 강남구-[2021년_재·보궐선거]_개표단위별_개표결과.xlsx", skiprows=3,  header=[0, 1], )
df.drop(columns=df.columns[-1], axis=1, inplace=True) # 마지막 column은 NAN라 삭제.  
print(df.head())
                읍면동명               투표구명               선거인수                투표수  \
  Unnamed: 0_level_1 Unnamed: 1_level_1 Unnamed: 2_level_1 Unnamed: 3_level_1   
0                 합계                              452344.0           276485.0   
1               거소투표                                3062.0             2877.0   
2             관외사전투표                               12957.0            12955.0   
3                신사동                 소계            13922.0             8672.0   
4                                관내사전투표             2667.0             2667.0   

     후보자별 득표수                                                               \
  더불어민주당\n박영선 국민의힘\n오세훈 기본소득당\n신지혜 국가혁명당\n허경영 미래당\n오태양 민생당\n이수봉 민생당\n이수봉.1   
0     66907.0  202320.0      909.0     2005.0    229.0    424.0        NaN   
1       595.0    1995.0       14.0       97.0     11.0     24.0        NaN   
2      4393.0    8171.0       48.0      100.0     18.0     18.0        NaN   
3      1581.0    6910.0       20.0       45.0      6.0     15.0        NaN   
4       632.0    1977.0        6.0       12.0      3.0      6.0        NaN   

                                                                        \
  신자유민주연합\n배영규 여성의당\n김진아 진보당\n송명숙 무소속\n정동희 무소속\n이도엽 무소속\n신지예         계   
0         20.0    1212.0    274.0     82.0     47.0    655.0  275084.0   
1          3.0       2.0      6.0      8.0      2.0      8.0    2765.0   
2          0.0      67.0     23.0      6.0      2.0     39.0   12885.0   
3          1.0      36.0      5.0      3.0      1.0     20.0    8643.0   
4          0.0       8.0      3.0      1.0      1.0      5.0    2654.0   

              무효\n투표수                 기권수  
  Unnamed: 18_level_1 Unnamed: 19_level_1  
0              1401.0            175859.0  
1               112.0               185.0  
2                70.0                 2.0  
3                29.0              5250.0  
4                13.0                 0.0  
  • header[0]값은 읍면동명, 투표구명, 선거인수, 투표수 등으로 정리가 되어 있다.
  • header[1]값은 각 후보들의 값이 나타난 것을 확인할 수 있다.
  • 여기에서 후보자별 득표수만 지우기만 하면 된다. 다만, 각각 가져와야 하는 값이 서로 다르다.
    • 이 때, MultiIndex에 대응하기 위해 get_level_values() 함수를 사용한다.
df.columns
MultiIndex([(    '읍면동명',  'Unnamed: 0_level_1'),
            (    '투표구명',  'Unnamed: 1_level_1'),
            (    '선거인수',  'Unnamed: 2_level_1'),
            (     '투표수',  'Unnamed: 3_level_1'),
            ('후보자별 득표수',         '더불어민주당\n박영선'),
            ('후보자별 득표수',           '국민의힘\n오세훈'),
            ('후보자별 득표수',          '기본소득당\n신지혜'),
            ('후보자별 득표수',          '국가혁명당\n허경영'),
            ('후보자별 득표수',            '미래당\n오태양'),
            ('후보자별 득표수',            '민생당\n이수봉'),
            ('후보자별 득표수',          '민생당\n이수봉.1'),
            ('후보자별 득표수',        '신자유민주연합\n배영규'),
            ('후보자별 득표수',           '여성의당\n김진아'),
            ('후보자별 득표수',            '진보당\n송명숙'),
            ('후보자별 득표수',            '무소속\n정동희'),
            ('후보자별 득표수',            '무소속\n이도엽'),
            ('후보자별 득표수',            '무소속\n신지예'),
            ('후보자별 득표수',                   '계'),
            ( '무효\n투표수', 'Unnamed: 18_level_1'),
            (     '기권수', 'Unnamed: 19_level_1')],
           )
df.columns.get_level_values(0)
Index(['읍면동명', '투표구명', '선거인수', '투표수', '후보자별 득표수', '후보자별 득표수', '후보자별 득표수',
       '후보자별 득표수', '후보자별 득표수', '후보자별 득표수', '후보자별 득표수', '후보자별 득표수', '후보자별 득표수',
       '후보자별 득표수', '후보자별 득표수', '후보자별 득표수', '후보자별 득표수', '후보자별 득표수', '무효\n투표수',
       '기권수'],
      dtype='object')
df.columns.get_level_values(1)
Index(['Unnamed: 0_level_1', 'Unnamed: 1_level_1', 'Unnamed: 2_level_1',
       'Unnamed: 3_level_1', '더불어민주당\n박영선', '국민의힘\n오세훈', '기본소득당\n신지혜',
       '국가혁명당\n허경영', '미래당\n오태양', '민생당\n이수봉', '민생당\n이수봉.1', '신자유민주연합\n배영규',
       '여성의당\n김진아', '진보당\n송명숙', '무소속\n정동희', '무소속\n이도엽', '무소속\n신지예', '계',
       'Unnamed: 18_level_1', 'Unnamed: 19_level_1'],
      dtype='object')
  • 이제, 각각의 index를 list로 변환후 하나의 column으로 합치는 과정을 진행한다.
  • 총 20개의 column이 정렬된 것을 확인할 수 있다.
col_1 = df.columns.get_level_values(0)[0:4].tolist()
col_2 = df.columns.get_level_values(1)[4:-2].tolist()
col_3 = df.columns.get_level_values(0)[-3:-1].tolist()
cols = col_1 + col_2 + col_3
cols
['읍면동명',
 '투표구명',
 '선거인수',
 '투표수',
 '더불어민주당\n박영선',
 '국민의힘\n오세훈',
 '기본소득당\n신지혜',
 '국가혁명당\n허경영',
 '미래당\n오태양',
 '민생당\n이수봉',
 '민생당\n이수봉.1',
 '신자유민주연합\n배영규',
 '여성의당\n김진아',
 '진보당\n송명숙',
 '무소속\n정동희',
 '무소속\n이도엽',
 '무소속\n신지예',
 '계',
 '후보자별 득표수',
 '무효\n투표수']
df.columns = cols
df.columns
Index(['읍면동명', '투표구명', '선거인수', '투표수', '더불어민주당\n박영선', '국민의힘\n오세훈', '기본소득당\n신지혜',
       '국가혁명당\n허경영', '미래당\n오태양', '민생당\n이수봉', '민생당\n이수봉.1', '신자유민주연합\n배영규',
       '여성의당\n김진아', '진보당\n송명숙', '무소속\n정동희', '무소속\n이도엽', '무소속\n신지예', '계',
       '후보자별 득표수', '무효\n투표수'],
      dtype='object')
  • 이제 시도와 시군구를 각각 추가한다.
df['시도'] = city_list[1]
df['시군구'] = city_list[2]
print(df.head(10))
     읍면동명    투표구명      선거인수       투표수  더불어민주당\n박영선  국민의힘\n오세훈  기본소득당\n신지혜  \
0      합계          452344.0  276485.0      66907.0   202320.0       909.0   
1    거소투표            3062.0    2877.0        595.0     1995.0        14.0   
2  관외사전투표           12957.0   12955.0       4393.0     8171.0        48.0   
3     신사동      소계   13922.0    8672.0       1581.0     6910.0        20.0   
4          관내사전투표    2667.0    2667.0        632.0     1977.0         6.0   
5          신사동제1투    2313.0    1052.0        205.0      827.0         1.0   
6          신사동제2투    1740.0     733.0        220.0      492.0         3.0   
7          신사동제3투    1896.0     813.0        261.0      508.0         6.0   
8          신사동제4투    2812.0    1736.0        112.0     1611.0         0.0   
9          신사동제5투    2494.0    1671.0        151.0     1495.0         4.0   

   국가혁명당\n허경영  미래당\n오태양  민생당\n이수봉  ...  여성의당\n김진아  진보당\n송명숙  무소속\n정동희  \
0      2005.0     229.0     424.0  ...     1212.0     274.0      82.0   
1        97.0      11.0      24.0  ...        2.0       6.0       8.0   
2       100.0      18.0      18.0  ...       67.0      23.0       6.0   
3        45.0       6.0      15.0  ...       36.0       5.0       3.0   
4        12.0       3.0       6.0  ...        8.0       3.0       1.0   
5         8.0       1.0       1.0  ...        4.0       0.0       1.0   
6        10.0       0.0       2.0  ...        5.0       0.0       0.0   
7         8.0       0.0       3.0  ...       14.0       2.0       0.0   
8         2.0       1.0       2.0  ...        2.0       0.0       1.0   
9         5.0       1.0       1.0  ...        3.0       0.0       0.0   

   무소속\n이도엽  무소속\n신지예         계  후보자별 득표수   무효\n투표수     시도  시군구  
0      47.0     655.0  275084.0    1401.0  175859.0  서울특별시  강남구  
1       2.0       8.0    2765.0     112.0     185.0  서울특별시  강남구  
2       2.0      39.0   12885.0      70.0       2.0  서울특별시  강남구  
3       1.0      20.0    8643.0      29.0    5250.0  서울특별시  강남구  
4       1.0       5.0    2654.0      13.0       0.0  서울특별시  강남구  
5       0.0       2.0    1050.0       2.0    1261.0  서울특별시  강남구  
6       0.0       1.0     733.0       0.0    1007.0  서울특별시  강남구  
7       0.0       6.0     809.0       4.0    1083.0  서울특별시  강남구  
8       0.0       1.0    1732.0       4.0    1076.0  서울특별시  강남구  
9       0.0       5.0    1665.0       6.0     823.0  서울특별시  강남구  

[10 rows x 22 columns]
  • 어느정도 정리가 된 것으로 보인다.

AirFlow ch01. 개요

인프런 강의

공지

  • Airflow 2.0 원서 나온 것을 공부용으로 활용합니다.

Airflow Project

Airflow%20Project%20ad0ddb927b43444a9837279ad7ea27fe/book_cover.png

  • 이 책에 나온 내용을 Chapter별로 요약하여 정리하려고 한다.
  • 원서 구매 페이지는 아래와 같다.
  • 구매 페이지: Data Pipelines with Apache Airflow

Chapter 1. Apache Airflow Introduction

Airflow%20Project%20ad0ddb927b43444a9837279ad7ea27fe/figure_1-1.png

AirFlow 설치 및 실행 with M1

인프런 강의

미니 프로젝트 개요

  • 목적: Airflow와 빅쿼리를 활용하여 ETL 및 대시보드를 만들어보는 과정을 설계
  • 환경: MacOS M1

Part I. Docker and Airflow

  • Docker와 Airflow를 설치 및 실행한다.

  • 필자는 가상환경을 선정하고, 그 위에 도커를 추가로 설치하였다.

PostgreSQL 기초 1

개요

  • psql shell 명령어를 간단히 배우도록 한다.
  • Database, Schema, Table를 생성하도록 한다.
  • 데이터타입에 대해 배우도록 한다.

psql Shell 명령어

명령어설명
\qpsql을 종료한다.
\l데이터베이스를 조회한다.
\c입력한 DB로 이동한다.
\e외부편집기로 sql 쿼리 입력 가능
\dt현재 DB에서 테이블을 확인할 수 있음.
  • 자주 사용하는 명령어이기 때문에 확인한다.

DB 및 Table 다루기

  • 콘솔창에서 book 이름의 DB를 생성한다.
evan=# CREATE DATABASE book;
CREATE DATABASE
  • 그 후, book에 접속한다.
evan=# \c book
You are now connected to database "book" as user "evan".
book=#
  • 이번에는 DROP DATABASE 구문을 통해 book 삭제한다.
evan=# DROP DATABASE book;
DROP DATABASE

SCHEMA 생성

postgres=# CREATE SCHEMA ann_simmons;
CREATE SCHEMA

postgres=# CREATE SCHEMA ty_beck;
CREATE SCHEMA

postgres=# CREATE SCHEMA production;
CREATE SCHEMA

Two Table 생성

  • 두개의 테이블을 생성한다.
CREATE TABLE customers ();
CREATE TABLE orders ();
  • 커밋을 항상 진행한다.
  • psql 터미널에서 \dt를 실행하여 출력값이 잘 나오는지 확인한다.
postgres=# \dt
         List of relations
 Schema |   Name    | Type  | Owner 
--------+-----------+-------+-------
 public | customers | table | evan
 public | orders    | table | evan
(2 rows)

Primary Key 생성

  • 이번에는 Primary Key 생성하는 것을 준비한다.
  • 이제 이 두개의 Table를 생성하도록 합니다.
CREATE TABLE business_type (
	id serial PRIMARY KEY,
  	description TEXT NOT NULL
);

CREATE TABLE applicant (
	id serial PRIMARY KEY,
  	name TEXT NOT NULL,
  	zip_code CHAR(5) NOT NULL,
  	business_type_id INTEGER references business_type(id)
);

CREATE TABLE users (
  id serial PRIMARY KEY,
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  email TEXT NOT NULL,
  hashed_password CHAR(72) NOT NULL
);

schema.table 생성

  • temp schema를 생성한 후, temp.users table를 작성한다.
CREATE TABLE temp.users (
  id serial PRIMARY KEY,
  first_name TEXT NOT NULL,
  last_name TEXT NOT NULL,
  email TEXT NOT NULL,
  hashed_password CHAR(72) NOT NULL
);

Data Types

  • 크게 Text, NUMERIC, BOOLEAN 형태로 구성이 됩니다.
-- Create the project table
CREATE TABLE project (
	-- Primary Key
	id SERIAL PRIMARY KEY,
    -- franchise 기회
	is_franchise BOOLEAN DEFAULT FALSE,
	-- Franchise 이름
    franchise_name TEXT DEFAULT NULL,
    -- Project 시도
    project_state TEXT,
    -- Project 시군
    project_county TEXT,
    -- Project로 발생한 Job 수
    jobs_supported NUMERIC
);

다양한 Text Data Types

CREATE TABLE book (
  isbn CHAR(13) NOT NULL, 
  author_first_name VARCHAR(50) NOT NULL, 
  author_last_name VARCHAR(50) NOT NULL, 
  content TEXT NOT NULL
);
  • Text data 타입은: TEXT, VARCHAR(N), CHAR(N) 크게 3가지 형태로 구성이 된다.
  • TEXT
    • 길이를 알 수 없는 텍스트 데이터에 적합
  • VARCHAR(N)
    • N은 최대 길이가 N자인 문자열만 저장하도록 열을 제한함.
    • N보다 글자수가 큰 값이 입력이 되면 error가 발생이 됨
    • 만약 N을 지정하지 않으면 TEXT와 동일하게 됨
  • CHAR(N)
    • 정확하게 N 숫자만큼 글자만 들어가게 됨
    • isbn은 주로 출판사에서 볼 수 있는 문자열임

Numeric Data

CREATE TABLE employee (
  id SERIAL PRIMARY KEY, 
  first_name VARCHAR(10) NOT NULL, 
  last_name VARCHAR(10) NOT NULL, 
  num_sales INTEGER
)

-- Create the client table
CREATE TABLE client (
  id SERIAL PRIMARY KEY,
  name VARCHAR(50),
  site_url VARCHAR(50),
  num_employees SMALLINT,
  num_customers INTEGER
);

-- Create the campaign table
CREATE TABLE campaign (
  id SERIAL PRIMARY KEY,
  name VARCHAR(50),
  budget NUMERIC(7, 2),
  num_days SMALLINT DEFAULT 30,
  goal_amount INTEGER DEFAULT 100,
  num_applications INTEGER DEFAULT 0
);
  • Integer Types

(Python-Plotly) Plotly 그래프 깃헙 블로그에 올리기

강의 홍보

개요

  • 깃헙 브로그에 동적 시각화를 올리는 방법에 대해 기술한다.
  • 현재까지 찾아낸 것은 이게 최선입니다! 더 나은 것이 있다면 공유 부탁드립니다. (꾸벅)

필수 라이브러리 설치

$ pip install plotly
$ pip install chart_studio
  • plotly의 역할 그래프를 작성하는 기본 도구이며, chart_studio의 역할은 그래프를 plotly 홈페이지 업로드 할 수 있도록 도와주고, 또한 iframe output으로 변환하는 데 도움을 주는 코드이다.

step 01. 그래프 작성

  • 그래프를 작성합니다.
import plotly.express as px
import chart_studio

gapminder = px.data.gapminder()
fig = px.scatter(gapminder.query("year==2007"), x="gdpPercap", y="lifeExp", size="pop", color="continent",
           hover_name="country", log_x=True, size_max=60)
fig.show()
  • 위 출력물은 실제로는 동적 시각화로 구현이 됩니다만, 캡쳐하여 올려 놓습니다.

File Download VIA SSH Terminal

1줄 요약

  • CURL 명령어는 진심 매우 좋더라.

동기부여

  • SQL 강의를 해야 하는데, 그에 맞는 데이터를 찾는 중이었다. SQL 예제와 함께 있는 데이터를 찾던 중, URL로 적힌 CSV 파일을 확인하였다. 이를 직접 Download로 쉽게 받을 수 있을 까 하는 생각에 구글링 몇개 해보였다.

참고자료

-o, --output <file>
          Write  output to <file> instead of stdout.
-O, --remote-name
          Write output to a local file named like the remote file we get. (Only the file part of the remote file is used, the path is cut off.)
  • 예시 코드는 다음과 같다.
$ curl -O https://data.cityofchicago.org/api/views/ijzp-q8t2/rows.csv?accessType=DOWNLOAD > Chicago.csv
  • OR
$ curl https://data.cityofchicago.org/api/views/ijzp-q8t2/rows.csv?accessType=DOWNLOAD > Chicago.csv

적용

  • 필자 역시 적용해 보았다.
$ curl -O "https://assets/your_url/actsin.csv" > temp.csv
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2078  100  2078    0     0   7556      0 --:--:-- --:--:-- --:--:--  7528
$ ls
actsin.csv
  • 정상적으로 다운로드 되 것을 확인할 수 있었다. 는

SQL 데이터로 불러오기

  • 필자는 postgreSQL 강의를 준비하고 있어서, 해당 데이터를 pgAdmin4로 활용하여 불러보았다.
  • 먼저 테이블을 생성한다.
DROP TABLE IF EXISTS "actsin";
CREATE TABLE actsin
(
    actsin_id integer PRIMARY KEY,
    movie_id integer,
    actor_id integer
);
  • 그리고 파일을 불러온 후 쿼리로 잘 불러오는지 확인합니다.
    • 중간 내용은 생략이 되었습니다. 추후 파일 불러오는 블로그 작성 시 공유 합니다.
SELECT * FROM actsin LIMIT 5;
 actsin_id | movie_id | actor_id 
-----------+----------+----------
         1 |       37 |        1
         2 |       56 |        2
         3 |       10 |        3
         4 |       14 |        3
         5 |       29 |        3
(5 rows)
  • 정상적으로 데이터가 조회되는 것을 확인할 수 있습니다.

PostgreSQL 테이블 생성 예제

테이블 생성 및 수정 삭제

  • pgAdmin4을 활용한 테이블 수정 삭제
  • Schemas에서 public-Table 마우스 오른쪽 버튼을 누른 뒤 Query Tool을 선택합니다.

  • developers 테이블을 별도로 생성합니다.
CREATE TABLE developers (
	book_id INTEGER, 
	date DATE,
	name VARCHAR(80)
)
CREATE TABLE
Query returned successfully in 65 msec.
  • 이번에는 값을 입력하도록 합니다.
INSERT INTO developers VALUES(1, '2019-12-17', '"자바"')
  • 그런데, 작은 따옴표(’)를 넣고 싶을 때는 큰 따옴표(")로 깜사면, 에러가 발생이 됩니다.
INSERT INTO developers VALUES(2, '2019-12-17', "'자바'")
ERROR: 오류:  "'자바'" 이름의 칼럼은 없습니다
LINE 1: INSERT INTO developers VALUES(1, '2019-12-17', "'자바'")
                                                       ^
SQL state: 42703
Character: 48
  • 이런 경우에는 작은 따옴표를 두번 입혀서 깜사도록 합니다.
INSERT INTO developers VALUES(2, '2019-12-17', '''자바''')
INSERT 0 1

Query returned successfully in 38 msec.
  • 이번에는 Python’s Programming을 입력하도록 합니다.
  • 입력하고자 하는 ‘주위로 각각 두번 ’’ 입력하도록 합니다.
INSERT INTO developers VALUES(3, '2019-12-17', 'Python''s Programming');
INSERT 0 1

Query returned successfully in 32 msec.

테이블 조회

  • 일단 먼저 잘 조회가 되는지 확인 하도록 합니다.
SELECT * FROM developers;