1. 분석 기간: 2022.10.15 ~ 2022.10.26

 

2. 분석개요

  - 기업의 ESG 등급이 주가에 영향을 미침

  - ESG 등급이 책정된 기업도 있지만 아직 ESG 등급이 책정되지 않은 기업도 있음

  - 이 기업들도 ESG 등급 책정을 받게 될 것이고 그 결과에 따라 기업의 주가가 영향을 받을 것임

  - 따라서 미리 기업의 ESG 등급을 예측할 수 있다면 주가 변동에 따른 이익을 얻을 수 있을 것

  - ESG 등급이 책정된 기업의 재무정보와 그에 따른 ESG 등급을 학습시켜
    ESG 등급이 책정되지 않은 기업의 재무정보를 활용해 ESG 등급을 예측

 

3. 활용 데이터

데이터명 출처 데이터 형태 비고
ESG 등급 한국ESG기준원 웹 데이터 기업코드, ESG 등급, E 등급, S 등급, G 등급
재무정보 에프앤가이드 CSV 기업코드, 기업명, 기준월, 종가, 자산총계, 부채총계, 자본총계, 매출액, 당기순이익, 배당금, EBITDA, EBIT, EV, ROE, ROA, EPS, BPS, CPS, SPS, P/E(FY End), P/B(FY End), P/C(FY End), P/CE(FY End), P/S(FY End), EV/EBITDA, EV/EBIT, EV/Sales

  - 두 데이터를 기업 코드를 기준으로 병합

 

  - ['Symbol', 'Name', '임원보수(계)', '임원보수(등기이사)', '임원보수(사외이사)', '임원1인당평균보수(계)', '임원1인당평균보수(등기이사)', '임원1인당평균보수(사외이사)', '임원스톡옵션공정가액(계)', '임원스톡옵션공정가액(등기이사)', '임원스톡옵션공정가액(사외이사)', '신용등급 (채권)', '신용등급 (CP)', '신용등급(ESB)', '신용등급 (채권, KAP)', '신용등급 (CP, KAP)', '신용등급(ESB, KAP)', '신용등급 (채권, NICE)', '신용등급 (CP, NICE)', '신용등급(ESB, NICE)', '신용등급 (채권, KIS)', '신용등급 (CP, KIS)', '신용등급(ESB, KIS)', '최대주주등 보유주식수(보통)(주)_상장협(분기)(주)', '최대주주등 보유비율(보통)(%)_상장협(분기)(%)', '최대주주등 보유주식수(우선)(주)_상장협(분기)(주)', '최대주주등 보유비율(우선)(%)_상장협(분기)(%)', '주주수 (소액주주계)_상장협(결산)', '주권의수 (소액주주계)_상장협(결산)(주)', '지분율 (소액주주계)_상장협(결산)(%)', '직원수정규직(계)(명)', '직원수정규직(남)(명)', '직원수정규직(여)(명)', '직원수비정규직(계)(명)', '직원수비정규직(남)(명)', '직원수비정규직(여)(명)', '직원평균근속년수(계)', '직원평균근속년수(남)', '직원평균근속년수(여)', '직원연간급여총액(계)', '직원연간급여총액(남)', '직원연간급여총액(여)', '직원1인평균급여액(계)', '직원1인평균급여액(남)', '직원1인평균급여액(여)']을 포함한 데이터 병합

  - 총직원수 병합

  - 시장구분코드 병합

# 위에 병합한 데이터
# 애프앤가이드 재무재표 데이터 + esg등급
# esg = pd.read_csv('/content/esg등급 합침.csv',encoding='cp949')
esg = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/투자/esg등급 합침.csv',encoding='cp949')


# 임원보수 등 새로 받은 데이터
# data_oo=pd.read_csv('/content/data_ooo.csv',encoding='cp949')
data_oo=pd.read_csv('/content/drive/MyDrive/Colab Notebooks/투자/data_ooo.csv',encoding='cp949')


# 총직원수
# total=pd.read_csv('/content/총직원수.csv',encoding='cp949')
total = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/투자/총직원수.csv',encoding='cp949')


# 시장구분코드
# sector=pd.read_csv('/content/csv_tb_fg_cpsm_m.csv',encoding='cp949')
sector=pd.read_csv('/content/drive/MyDrive/Colab Notebooks/투자/csv_tb_fg_cpsm_m.csv',encoding='cp949')

# 데이터 합치기
DATA=esg.join(data_oo.set_index('Symbol').iloc[:,2:],on='Code')
DATA=DATA.join(total.set_index('Code')['Annual'],on='Code')
DATA=DATA.join(sector.set_index('기업코드')['시장구분코드'],on='Code')

 

  - 분석에 사용하지 않을 열 삭제(금융을 공부한 팀원의 판단 하에 진행)

# 분석에 사용하지 않을 열 삭제
DATA = DATA.drop(['매출원가', 'Fiscal Month', '임원스톡옵션공정가액(계)', '임원스톡옵션공정가액(등기이사)',
                  '임원스톡옵션공정가액(사외이사)', '신용등급 (채권)', '신용등급 (CP)', '신용등급(ESB)', '신용등급 (채권, KAP)',
                  '신용등급 (CP, KAP)', '신용등급(ESB, KAP)', '신용등급 (채권, NICE)', '신용등급 (CP, NICE)', '신용등급(ESB, NICE)',
                  '신용등급 (채권, KIS)', '신용등급 (CP, KIS)', '신용등급(ESB, KIS)','임원1인당평균보수(계)','임원1인당평균보수(등기이사)',
                  '임원1인당평균보수(사외이사)','최대주주등 보유주식수(우선)(주)_상장협(분기)(주)','최대주주등 보유비율(우선)(%)_상장협(분기)(%)',
                  '주주수 (소액주주계)_상장협(결산)','직원연간급여총액(계)','직원연간급여총액(남)','직원연간급여총액(여)'], axis = 1)

 

4. 데이터 정제

  - 결측값, 이상값 제거

# 종가 결측값 있는 행 제거
DATA.dropna(subset=['종가'],how='any',inplace=True)

# 매출액 결측값 있는 행 제거
DATA.dropna(subset=['매출액'],how='any',inplace=True)

# EV 결측값 있는 행 제거
DATA.dropna(subset=['EV'],how='any',inplace=True)

# 인덱스 초기화
DATA.reset_index(drop=True,inplace=True)

# ROE, ROA 결측값 채우기
DATA['ROE'].fillna((DATA['당기순이익']/DATA['자본총계'])*100,inplace=True)
DATA['ROA'].fillna((DATA['당기순이익']/DATA['자산총계'])*100,inplace=True)

# 배당금 결측값 있는 행 제거
DATA.dropna(subset=['배당금'],how='any',inplace=True)

# P/CE 결측값 있는 행 제거
DATA.dropna(subset=['P/CE(FY End)'],how='any',inplace=True)

# 이상치 제거
q1 = DATA['매출액'].quantile(0.03)
q3 = DATA['매출액'].quantile(0.97)
DATA=DATA[(DATA['매출액'] < q3) & (DATA['매출액'] > q1)]

# 등기이사, 사외이사
DATA.dropna(subset=['임원보수(등기이사)'],how='any',inplace=True)
DATA['임원보수(사외이사)']=DATA['임원보수(사외이사)'].fillna(0)

# 그외 결측치 처리
DATA.dropna(subset=['직원수정규직(계)(명)'],how='any',inplace=True)
DATA.dropna(subset=['직원수정규직(남)(명)'],how='any',inplace=True)
DATA.dropna(subset=['직원수정규직(여)(명)'],how='any',inplace=True)

DATA.dropna(subset=['주권의수 (소액주주계)_상장협(결산)(주)'],how='any',inplace=True)
DATA.dropna(subset=['지분율 (소액주주계)_상장협(결산)(%)'],how='any',inplace=True)

DATA.dropna(subset=['직원평균근속년수(계)'],how='any',inplace=True)
DATA.dropna(subset=['직원평균근속년수(남)'],how='any',inplace=True)
DATA.dropna(subset=['직원평균근속년수(여)'],how='any',inplace=True)

DATA.dropna(subset=['직원1인평균급여액(계)'],how='any',inplace=True)
DATA.dropna(subset=['직원1인평균급여액(남)'],how='any',inplace=True)
DATA.dropna(subset=['직원1인평균급여액(여)'],how='any',inplace=True)

 

  - 재무제표 상에 다른 변수들로 계산된 파생변수들은 삭제

# 파생변수
# 근속년수 남녀차이
DATA['근속년수 남녀차이']=abs(DATA['직원평균근속년수(남)']-DATA['직원평균근속년수(여)'])

# 평균 급여액 남녀차이
DATA['평균급여액 남녀차이']=abs(DATA['직원1인평균급여액(남)']-DATA['직원1인평균급여액(여)'])

# 더미변수 만들기
DATA['사외이사유무']=np.where(DATA['임원보수(사외이사)'] !=0,1,0)

# 직원수비정규직 결측값 계산(총직원수-직원수정규직)
DATA['직원수비정규직(계)(명)']=DATA['직원수비정규직(계)(명)'].fillna(DATA['Annual']-DATA['직원수정규직(계)(명)'])
DATA['직원수비정규직(남)(명)']=DATA['직원수비정규직(남)(명)'].fillna(DATA['Annual']-DATA['직원수정규직(남)(명)'])
DATA['직원수비정규직(여)(명)']=DATA['직원수비정규직(여)(명)'].fillna(DATA['Annual']-DATA['직원수정규직(여)(명)'])

 

5. 데이터 분석

  - ESG 등급이 책정된 기업의 재무정보를 독립변수, ESG등급(ESG 등급, E 등급, S 등급, G 등급)을 종속변수로 분석

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
import re
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
import hyperopt
from hyperopt import fmin, tpe, hp, STATUS_OK, Trials
from xgboost import XGBClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import f1_score
from sklearn.model_selection import cross_val_predict
import warnings
warnings.filterwarnings('ignore')

# 데이터 전처리 및 데이터셋 분리
def preprocess(DATA,drop_list,pred,split):
    # ESG등급 수치화하기
    if split==1:
        ESG_CLASS={'D':0,'C':0,'B':0,'B+':1,'A':1,'A+':1}
    elif split==2:
        ESG_CLASS={'D':0,'C':1,'B':2,'B+':3,'A':4,'A+':5}
    elif split==3:
        ESG_CLASS={'D':0,'C':1,'B':2,'B+':3,'A':4,'A+':5}

    DATA['ESG등급']=DATA['ESG등급'].replace(ESG_CLASS)
    DATA['E등급']=DATA['E등급'].replace(ESG_CLASS)
    DATA['S등급']=DATA['S등급'].replace(ESG_CLASS)
    DATA['G등급']=DATA['G등급'].replace(ESG_CLASS)


    # 독립변수(X), 종속변수(y) 구분
    X=DATA.drop(drop_list,axis=1)
    y=DATA[[pred]]


    # 교차검증 위해 훈련데이터, 검증데이터 분류
    x_train,x_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=42)

    return x_train,x_test,y_train,y_test

# 하이퍼파라미터 서치
def search(x_train,y_train):
# adaboost, xgboost 그리드서치
    abc=AdaBoostClassifier()
    xgb=XGBClassifier(eval_metric='merror')
    lr=LogisticRegression()

    # xgboost, adaboost 파라미터 각각 서치
    # n_estimators    : 100 또는 500
    # learning_rate   : 0.01~0.5
    # algorithm       : SAMME 또는 SAMME.R
    param={'n_estimators':[100,500],'learning_rate': [(x / 100) for x in range(1, 51)]}
    grid=GridSearchCV(abc,param_grid=param,cv=3,verbose=0,n_jobs=-1)
    grid.fit(x_train,y_train)
    print('adaboost 최적 하이퍼 파라미터:',grid.best_params_)
    print('adaboost 정확도:', grid.best_score_)

    print('\n')
    # n_estimators    : 100 또는 500
    # learning_rate   : 0.01~0.5
    # max_depth       : 1~10
    param={'n_estimators':[100,500],'learning_rate': [(x / 100) for x in range(1, 51)],'max_depth':list(range(1,11))}
    grid=GridSearchCV(xgb,param_grid=param,cv=3,verbose=0,n_jobs=-1)
    grid.fit(x_train,y_train)
    print('xgboost 최적 하이퍼 파라미터:',grid.best_params_)
    print('xgboost 정확도:', grid.best_score_)

    print('\n')
    # n_estimators    : 100 또는 500
    # learning_rate   : 0.01~0.5
    # max_depth       : 1~10
    param={'C':np.logspace(-3,3,7), 'penalty':['l1', 'l2']}
    grid=GridSearchCV(lr,param_grid=param,cv=3,verbose=0,n_jobs=-1)
    grid.fit(x_train,y_train)
    print('Logistic Regression 최적 하이퍼 파라미터:',grid.best_params_)
    print('Logistic Regression 정확도:', grid.best_score_)

 

  - ESG 등급이 책정된 기업과 ESG 등급이 책정되지 않은 기업 분류 및 정규화

ESG있는거=DATA.drop(DATA.loc[DATA['ESG등급'].apply(lambda x: pd.isna(x))].index,axis=0)
ESG없는거=DATA.drop(DATA.loc[~DATA['ESG등급'].apply(lambda x: pd.isna(x))].index,axis=0).drop(['ESG등급', 'E등급', 'S등급', 'G등급'], axis=1)

# 정규화(ESG있는거에 피팅하여 ESG있는거, ESG없는거에 각각 적용)
ESG있는거_ESG=ESG있는거[['ESG등급','E등급','S등급','G등급']].reset_index()
ESG있는거=ESG있는거.drop(['ESG등급','E등급','S등급','G등급','Code','Name'],axis=1)
scaler=MinMaxScaler()
scaler.fit(ESG있는거)
ESG있는거=pd.DataFrame(scaler.transform(ESG있는거),columns=ESG있는거.columns)
ESG있는거=pd.concat([ESG있는거,ESG있는거_ESG],axis=1).drop(['index'],axis=1)

ESG없는거_code_name=ESG없는거[['Code','Name']].reset_index()
ESG없는거=ESG없는거.drop(['Code','Name'],axis=1)
ESG없는거=pd.DataFrame(scaler.transform(ESG없는거),columns=ESG없는거.columns)
ESG없는거[['Code','Name']]=ESG없는거_code_name[['Code','Name']]

 

  - 각 등급은 C, C+, B, B+, A, A+ 총 6개의 등급을 가지며 다변량 회귀분석을 진행하려 했으나,
     정확도가 0.5내외로 너무 낮은 문제 발생

  - 이에, 그룹 1(C, C+, B), 그룹2(B+, A, A+)로 나누어 로지스틱 회귀분석을 진행하고
     그룹 내에서 (C, C+)과 (B), (B+)과 (A, A+)을 다시 분류
     마지막으로 (C)와 (C+), (A)와 (A+)을 분류하여 정확도를 0.8이상으로 향상시킴

# 각각 0과 1로 구분
S_1_o=ESG있는거[(ESG있는거['S등급']=='B+') | (ESG있는거['S등급']=='A') | (ESG있는거['S등급']=='A+')]
S_0_o=ESG있는거[(ESG있는거['S등급']=='D') | (ESG있는거['S등급']=='C') | (ESG있는거['S등급']=='B')]

ESG_1_o=ESG있는거[(ESG있는거['ESG등급']=='B+') | (ESG있는거['ESG등급']=='A') | (ESG있는거['ESG등급']=='A+')]
ESG_0_o=ESG있는거[(ESG있는거['ESG등급']=='D') | (ESG있는거['ESG등급']=='C') | (ESG있는거['ESG등급']=='B')]

E_1_o=ESG있는거[(ESG있는거['E등급']=='B+') | (ESG있는거['E등급']=='A') | (ESG있는거['E등급']=='A+')]
E_0_o=ESG있는거[(ESG있는거['E등급']=='D') | (ESG있는거['E등급']=='C') | (ESG있는거['E등급']=='B')]

G_1_o=ESG있는거[(ESG있는거['G등급']=='B+') | (ESG있는거['G등급']=='A') | (ESG있는거['G등급']=='A+')]
G_0_o=ESG있는거[(ESG있는거['G등급']=='D') | (ESG있는거['G등급']=='C') | (ESG있는거['G등급']=='B')]

 

  - ESG, E, S, G 등급 서로 간의 상관을 계산
      → 다른 등급들과 관련도가 가장 높은 S 등급을 먼저 예측하여 독립변수로 두고
       기존 독립변수에 S등급까지 추가하여 ESG 등급을 예측하여 독립변수에 추가
       나머지 E, G 등급도 하나씩 예측하고 추가하며 모든 등급의 예측을 진행

  - 이때 진행한 로지스틱 회귀분석은 xgboost, randomforest, lgbm 세 알고리즘을 모두 이용한 뒤,
     각 분류 과정에서 정확도가 가장 높은 알고리즘으로 채택

# 1-1. S등급 예측(0, 1)

x_train,x_test,y_train,y_test=preprocess(ESG있는거,['ESG등급', 'E등급', 'S등급', 'G등급'],'S등급',1)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.17, 'n_estimators': 100}
adaboost 정확도: 0.804263565891473


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.33, 'max_depth': 10, 'n_estimators': 100}
xgboost 정확도: 0.8023255813953488


Logistic Regression 최적 하이퍼 파라미터: {'C': 100.0, 'penalty': 'l2'}
Logistic Regression 정확도: 0.7596899224806202
# 3개의 분류기 중 가장 정확도가 높은 adaboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

abc=AdaBoostClassifier(n_estimators=100,learning_rate=0.17)
model=abc.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.8042635658914729
# S등급이 없는 기업의 데이터를 분류기에 넣어 S등급 예측
ESG없는거_code_name=ESG없는거[['Code','Name']].reset_index()
S등급=model.predict(ESG없는거.drop(['Code','Name'],axis=1))
ESG없는거['S등급']=S등급
ESG없는거[['Code','Name']]=ESG없는거_code_name[['Code','Name']]

S_1=ESG없는거[ESG없는거['S등급']==1].drop(['S등급'],axis=1).reset_index(drop=True)
S_0=ESG없는거[ESG없는거['S등급']==0].drop(['S등급'],axis=1).reset_index(drop=True)
S_1_code_name=S_1[['Code','Name']].reset_index()
S_0_code_name=S_0[['Code','Name']].reset_index()

 

# 1-2. S등급 중 1로 예측된 것(B+, A, A+)을 다시 세 개로 각각 분류

x_train,x_test,y_train,y_test=preprocess(S_1_o,['ESG등급', 'E등급', 'S등급', 'G등급'],'S등급',2)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.48, 'n_estimators': 500}
adaboost 정확도: 0.5569416498993963


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.03, 'max_depth': 1, 'n_estimators': 100}
xgboost 정확도: 0.5519114688128773


Logistic Regression 최적 하이퍼 파라미터: {'C': 1.0, 'penalty': 'l2'}
Logistic Regression 정확도: 0.5425217974513749
# 3개의 분류기 중 가장 정확도가 높은 adaboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

abc=AdaBoostClassifier(n_estimators=500,learning_rate=0.48)
model=abc.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.5566037735849056
S등급=model.predict(S_1.drop(['Code','Name'],axis=1))
S_1['S등급']=S등급
S_1[['Code','Name']]=S_1_code_name[['Code','Name']]

 

# 1-3. S등급 중 0으로 예측된 것(D, C, B)을 다시 세 개로 각각 분류

x_train,x_test,y_train,y_test=preprocess(S_0_o,['ESG등급', 'E등급', 'S등급', 'G등급'],'S등급',3)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.01, 'n_estimators': 100}
adaboost 정확도: 0.6105610561056105


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.03, 'max_depth': 1, 'n_estimators': 100}
xgboost 정확도: 0.6204620462046204


Logistic Regression 최적 하이퍼 파라미터: {'C': 100.0, 'penalty': 'l2'}
Logistic Regression 정확도: 0.5907590759075907
# 3개의 분류기 중 가장 정확도가 높은 xgboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

xgb=XGBClassifier(n_estimators=100,learning_rate=0.03,max_depth=1,eval_metric='merror')
model=xgb.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.6204620462046204
S등급=model.predict(S_0.drop(['Code','Name'],axis=1))
S_0['S등급']=S등급
S_0[['Code','Name']]=S_0_code_name[['Code','Name']]
ESG없는거=pd.concat([S_1,S_0])

 

# 2-1. S등급과 가장 상관관계가 높았던 ESG등급 예측

x_train,x_test,y_train,y_test=preprocess(ESG있는거,['ESG등급', 'E등급', 'G등급'],'ESG등급',1)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.02, 'n_estimators': 100}
adaboost 정확도: 0.8953488372093025


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.03, 'max_depth': 1, 'n_estimators': 100}
xgboost 정확도: 0.8934108527131782


Logistic Regression 최적 하이퍼 파라미터: {'C': 0.1, 'penalty': 'l2'}
Logistic Regression 정확도: 0.8953488372093025
# 3개의 분류기 중 가장 정확도가 높은 adaboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

abc=AdaBoostClassifier(n_estimators=100,learning_rate=0.02)
model=abc.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.8953488372093024
# ESG등급이 없는 기업의 데이터를 분류기에 넣어 ESG등급 예측

ESG없는거_code_name=ESG없는거[['Code','Name']].reset_index()
ESG등급=model.predict(ESG없는거.drop(['Code','Name'],axis=1))
ESG없는거['ESG등급']=ESG등급
ESG없는거[['Code','Name']]=ESG없는거_code_name[['Code','Name']]
ESG_1=ESG없는거[ESG없는거['ESG등급']==1].drop(['ESG등급'],axis=1).reset_index(drop=True)
ESG_0=ESG없는거[ESG없는거['ESG등급']==0].drop(['ESG등급'],axis=1).reset_index(drop=True)
ESG_1_code_name=ESG_1[['Code','Name']].reset_index()
ESG_0_code_name=ESG_0[['Code','Name']].reset_index()

 

# 2-2. ESG등급 중 1로 예측된 것(B+, A, A+)을 다시 세 개로 각각 분류

x_train,x_test,y_train,y_test=preprocess(ESG_1_o,['ESG등급', 'E등급', 'G등급'],'ESG등급',2)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.14, 'n_estimators': 100}
adaboost 정확도: 0.7388888888888889


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.06, 'max_depth': 1, 'n_estimators': 100}
xgboost 정확도: 0.8277777777777778


Logistic Regression 최적 하이퍼 파라미터: {'C': 0.001, 'penalty': 'l2'}
Logistic Regression 정확도: 0.8166666666666668
# 3개의 분류기 중 가장 정확도가 높은 xgboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

xgb=XGBClassifier(n_estimators=100,learning_rate=0.06, max_depth=1, eval_metric='merror')
model=xgb.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.8277777777777777
ESG등급=model.predict(ESG_1.drop(['Code','Name'],axis=1))
ESG_1['ESG등급']=ESG등급
ESG_1[['Code','Name']]=ESG_1_code_name[['Code','Name']]

 

# 2-3. ESG등급 중 0으로 예측된 것(D, C, B)을 다시 세 개로 각각 분류

x_train,x_test,y_train,y_test=preprocess(ESG_0_o,['ESG등급', 'E등급', 'G등급'],'ESG등급',3)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.49, 'n_estimators': 500}
adaboost 정확도: 0.6160714285714285


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.01, 'max_depth': 1, 'n_estimators': 500}
xgboost 정확도: 0.7142857142857143


Logistic Regression 최적 하이퍼 파라미터: {'C': 0.01, 'penalty': 'l2'}
Logistic Regression 정확도: 0.7113095238095238
# 3개의 분류기 중 가장 정확도가 높은 xgboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

xgb=XGBClassifier(n_estimators=500,learning_rate=0.01, max_depth=1, eval_metric='merror')
model=xgb.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.7142857142857143
ESG등급=model.predict(ESG_0.drop(['Code','Name'],axis=1))
ESG_0['ESG등급']=ESG등급
ESG_0[['Code','Name']]=ESG_0_code_name[['Code','Name']]
ESG없는거=pd.concat([ESG_1,ESG_0])

 

# 3-1. ESG등급과 S등급을 제외하고 가장 상관관계 높았던 E등급 예측

x_train,x_test,y_train,y_test=preprocess(ESG있는거,['E등급', 'G등급'],'E등급',1)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.01, 'n_estimators': 500}
adaboost 정확도: 0.8643410852713179


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.26, 'max_depth': 4, 'n_estimators': 100}
xgboost 정확도: 0.8740310077519379


Logistic Regression 최적 하이퍼 파라미터: {'C': 1.0, 'penalty': 'l2'}
Logistic Regression 정확도: 0.881782945736434
# 3개의 분류기 중 가장 정확도가 높은 Logistic Regression에 최적 하이퍼 파라미터를 넣어 분류기 학습

lr=LogisticRegression(C=1,penalty='l2')
model=lr.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.8817829457364341
# E등급이 없는 기업의 데이터를 분류기에 넣어 E등급 예측

ESG없는거_code_name=ESG없는거[['Code','Name']].reset_index()
E등급=model.predict(ESG없는거.drop(['Code','Name'],axis=1))
ESG없는거['E등급']=E등급
ESG없는거[['Code','Name']]=ESG없는거_code_name[['Code','Name']]
E_1=ESG없는거[ESG없는거['E등급']==1].drop(['E등급'],axis=1).reset_index(drop=True)
E_0=ESG없는거[ESG없는거['E등급']==0].drop(['E등급'],axis=1).reset_index(drop=True)
E_1_code_name=E_1[['Code','Name']].reset_index()
E_0_code_name=E_0[['Code','Name']].reset_index()

 

# 3-2. E등급 중 1로 예측된 것(B+, A, A+)을 다시 세 개로 각각 분류

x_train,x_test,y_train,y_test=preprocess(E_1_o,['E등급', 'G등급'],'E등급',2)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.35, 'n_estimators': 500}
adaboost 정확도: 0.626984126984127


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.42, 'max_depth': 5, 'n_estimators': 500}
xgboost 정확도: 0.7142857142857143


Logistic Regression 최적 하이퍼 파라미터: {'C': 0.1, 'penalty': 'l2'}
Logistic Regression 정확도: 0.746031746031746
# 3개의 분류기 중 가장 정확도가 높은 Logistic Regression에 최적 하이퍼 파라미터를 넣어 분류기 학습

lr=LogisticRegression(C=0.1,penalty='l2')
model=lr.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.746031746031746
E등급=model.predict(E_1.drop(['Code','Name'],axis=1))
E_1['E등급']=E등급
E_1[['Code','Name']]=E_1_code_name[['Code','Name']]

 

# 3-3. E등급 중 0으로 예측된 것(D, C, B)을 다시 세 개로 각각 분류

x_train,x_test,y_train,y_test=preprocess(E_0_o,['E등급', 'G등급'],'E등급',3)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.04, 'n_estimators': 100}
adaboost 정확도: 0.6118067978533095


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.15, 'max_depth': 9, 'n_estimators': 100}
xgboost 정확도: 0.6143907771814748


Logistic Regression 최적 하이퍼 파라미터: {'C': 10.0, 'penalty': 'l2'}
Logistic Regression 정확도: 0.6068177300735439
# 3개의 분류기 중 가장 정확도가 높은 xgboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

xgb=XGBClassifier(n_estimators=100,learning_rate=0.15, max_depth=9, eval_metric='merror')
model=xgb.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.6143958868894601
E등급=model.predict(E_0[x_train.columns])
E_0['E등급']=E등급
E_0[['Code','Name']]=E_0_code_name[['Code','Name']]
ESG없는거=pd.concat([E_1,E_0])

 

# 4-1. 마지막 남은 G등급 예측

x_train,x_test,y_train,y_test=preprocess(ESG있는거,['G등급'],'G등급',1)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.01, 'n_estimators': 500}
adaboost 정확도: 0.686046511627907


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.36, 'max_depth': 5, 'n_estimators': 100}
xgboost 정확도: 0.7073643410852712


Logistic Regression 최적 하이퍼 파라미터: {'C': 1.0, 'penalty': 'l2'}
Logistic Regression 정확도: 0.6976744186046512
# 3개의 분류기 중 가장 정확도가 높은 xgboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

xgb=XGBClassifier(n_estimators=100,learning_rate=0.36,max_depth=5,eval_metric='merror')
model=xgb.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.7073643410852714
# G등급이 없는 기업의 데이터를 분류기에 넣어 G등급 예측

ESG없는거_code_name=ESG없는거[['Code','Name']].reset_index()
G등급=model.predict(ESG없는거[x_train.columns])
ESG없는거['G등급']=G등급
ESG없는거[['Code','Name']]=ESG없는거_code_name[['Code','Name']]
G_1=ESG없는거[ESG없는거['G등급']==1].drop(['G등급'],axis=1).reset_index(drop=True)
G_0=ESG없는거[ESG없는거['G등급']==0].drop(['G등급'],axis=1).reset_index(drop=True)
G_1_code_name=G_1[['Code','Name']].reset_index()
G_0_code_name=G_0[['Code','Name']].reset_index()

 

# 4-2. G등급 중 1로 예측된 것(B+, A, A+)을 다시 세 개로 분류

x_train,x_test,y_train,y_test=preprocess(G_1_o,['G등급'],'G등급',2)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.01, 'n_estimators': 100}
adaboost 정확도: 0.8184981684981686


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.01, 'max_depth': 1, 'n_estimators': 100}
xgboost 정확도: 0.8886752136752136


Logistic Regression 최적 하이퍼 파라미터: {'C': 0.1, 'penalty': 'l2'}
Logistic Regression 정확도: 0.8791514041514041
# 3개의 분류기 중 가장 정확도가 높은 xgboost에 최적 하이퍼 파라미터를 넣어 분류기 학습

xgb=XGBClassifier(n_estimators=100,learning_rate=0.01,max_depth=1,eval_metric='merror')
model=xgb.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.8885350318471338
G등급=model.predict(G_1[x_train.columns])
G_1['G등급']=G등급
G_1[['Code','Name']]=G_1_code_name[['Code','Name']]

 

# 4-3. G등급 중 0으로 예측된 것(D, C, B)을 다시 세 개로 각각 분류

x_train,x_test,y_train,y_test=preprocess(G_0_o,['G등급'],'G등급',3)
search(x_train,y_train)

# 출력 결과
adaboost 최적 하이퍼 파라미터: {'learning_rate': 0.07, 'n_estimators': 100}
adaboost 정확도: 0.8159203980099502


xgboost 최적 하이퍼 파라미터: {'learning_rate': 0.02, 'max_depth': 5, 'n_estimators': 100}
xgboost 정확도: 0.8258706467661692


Logistic Regression 최적 하이퍼 파라미터: {'C': 1.0, 'penalty': 'l2'}
Logistic Regression 정확도: 0.8308457711442786
# 3개의 분류기 중 가장 정확도가 높은 Logistic Regression에 최적 하이퍼 파라미터를 넣어 분류기 학습

lr=LogisticRegression(C=1,penalty='l2')
model=lr.fit(x_train,y_train)
y_cv_pred=cross_val_predict(model,x_train,y_train,cv=3)
print('accuracy=',accuracy_score(y_train,y_cv_pred))

# 출력 결과
accuracy= 0.8308457711442786
G등급=model.predict(G_0.drop(['Code','Name'],axis=1))
G_0['G등급']=G등급
G_0[['Code','Name']]=G_0_code_name[['Code','Name']]
ESG없는거=pd.concat([G_1,G_0])

 

# 5. 결과 저장

ESG_CLASS={0:'D',1:'C',2:'B',3:'B+',4:'A',5:'A+'}
ESG없는거['ESG등급']=ESG없는거['ESG등급'].replace(ESG_CLASS)
ESG없는거['E등급']=ESG없는거['E등급'].replace(ESG_CLASS)
ESG없는거['S등급']=ESG없는거['S등급'].replace(ESG_CLASS)
ESG없는거['G등급']=ESG없는거['G등급'].replace(ESG_CLASS)

ESG없는거=ESG없는거[['Code', 'Name', '종가', '자산총계', '부채총계', '자본총계', '매출액', '당기순이익', '배당금', 'EBITDA', 'EBIT',
                    'EV', 'ROE', 'ROA', 'EPS', 'BPS', 'CPS', 'SPS', 'P/E(FY End)', 'P/B(FY End)', 'P/C(FY End)', 'P/CE(FY End)', 'P/S(FY End)',
                    'EV/EBITDA', 'EV/EBIT', 'EV/Sales', '임원보수(등기이사)', '임원보수(사외이사)', '최대주주등 보유주식수(보통)(주)_상장협(분기)(주)',
                    '최대주주등 보유비율(보통)(%)_상장협(분기)(%)', '주권의수 (소액주주계)_상장협(결산)(주)', '지분율 (소액주주계)_상장협(결산)(%)',
                    '직원수정규직(계)(명)', '직원수정규직(남)(명)', '직원수정규직(여)(명)', '직원수비정규직(계)(명)', '직원수비정규직(남)(명)',
                    '직원수비정규직(여)(명)', '직원평균근속년수(계)', '직원평균근속년수(남)', '직원평균근속년수(여)', '직원1인평균급여액(계)',
                    '직원1인평균급여액(남)', '직원1인평균급여액(여)', 'Annual', '시장구분코드', '근속년수 남녀차이', '평균급여액 남녀차이',
                    '사외이사유무', 'ESG등급', 'E등급', 'S등급', 'G등급']]

ESG없는거.to_csv('결과.csv',encoding='cp949',index=False)

 

6. 분석 결과

  - ESG 등급이 책정된 기업들을 train data와 test data로 분리하여 train data로 학습을 진행한 뒤 test data에 적용한 결과,
     정확도가 0.8 이상인 알고리즘을 ESG 등급이 책정되지 않은 기업의 ESG 등급을 책정하는데 사용

 

7. 피드백 및 한계점

  - ESG 등급 자체는 재무정보와 아무 관련이 없어 재무정보를 통해 ESG 등급을 예측하는 것은 의미가 없음

  - 하지만, 그 사이에 연관 관계를 알고리즘을 통해 찾으려 했고 정확도를 0.8 이상으로 올리기는 하였지만, 그 결과가 유의미 할 지는 실제 ESG 등급이 나오기 까지는 알 수 없음

  - 기존 논문들은 ESG 등급과 주가 간의 상관관계만을 얘기했지만 이번 분석에서 재무정보를 ESG 등급 예측에 이용했다는 의의가 있음

 

+ Recent posts