Statistics

Python 통계 - 비모수 통계

강의 홍보

분포에 대한 가정을 만족 못할 시의 문제점

  • 1종 오류의 값이 커지거나, 분석 결과 자체에 대한 신뢰성이 떨어짐
  • 모수 통계 분석 적용 못할 시, 비모수 통계 분석 활용

(1) 언제 적용할까?

  • 분포 가정 불만족 (예: 정규분포 아님)
  • 분석기법의 전제조건 불만족 (예: 다중공선성)
  • 표본 수 불만족 (예: 설문조사 20개)
  • 데이터 척도 단순화 (예: 명목 또는 서열 척도로만 측정)

(2) 비모수 통계분석 유형

  • 비모수 통계분석의 유형은 아래와 같다. (p. 357)

통계분석 실습 - 적합도 검정

(1) 적합도 검정: RUN 검정

  • 가정된 확률이 정해져 있는 경우, 예) 제품의 A등급(6), B등급(3), C등급(1)
  • 비모수 통계는 반대로, 표본의 배열이 무작위로 구성되어 있는지 검정
  • (교재, p. 357)
    • 마케팅 행사가 공정하게 이루어졌는지 RUN 검정 실시
  • 가설검정
    • 귀무가설: 멤버십 소지 고객과 비소지 고객의 방문은 무작위로 이루어짐
    • 연구가설: 멤버십 소지 고객과 비소지 고객의 방문은 무작위로 이루어지지 않음
from statsmodels.sandbox.stats.runs import Runs
import numpy as np

x = [1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0]
x = np.array(x)

Runs(x).runs_test()
(-1.8277470669267506, 0.06758752074917526)
  • z값의 공식은 (RUN의 개수 - RUN의 평균) + 0.5 / RUN의 표준편차 (p.358) 참조
    • 평균 및 표준편차를 구하는 방식은 모수의 방식과 다르다 (주의)
  • -1.8은 z값을 의미하고, p 값은 0.067로 도출됨으로 유의수준 0.1 수준에서 유의하다.
    • 즉, 연구가설을 채택하는데, 이 말의 함의는 공정하게 이루어지지 않았음을 의미

(2) Kolmogorov-Smirnov 검정

  • 표본의 분포가 가정한 분포와 적합한지 검정 $$D_{n} = max|F_{n}(x) - F_{0}(x)$$

Python 통계 - 확률의 정의

강의 홍보

확률기초이론

  • 이산확률분포: 베르누이분포, 이항분포, 포아송분포
  • 연속확률분포: 정규분포, 카이제곱분포, t-분포, F-분포
  • 확률이란? 경험 또는 실험의 결과로 특정한 사건(event)이나 결과가 발생할 가능성
    • 예1) 주사위 던져서 1이 나올 가능성 1/6
    • 예2) 비가 올 가능성 30%

(1) 확률의 정의

  • 사건 A의 확률 = $\frac{n(A)}{N}$
    • N = 표본공간(=sample space) = 특정 실험에서 일어날 수 있는 모든 가능성

Python 통계 - T검정 예제

강의 홍보

통계분석을 활용한 문제해결 과정

  • 비즈니스에서 통계는 그저 툴이다.
    • 통계를 몰라도 물건을 파는데 전혀 문제가 없다.
  • 통계는 객관적인 근거를 확보하여 유효한 의사결정을 내리기 위한 그저 도구 (Tool) 이다.
  • 따라서, 마케팅이나 CRM과 같은 경영이슈에서도 통계는 문제해결을 이한 체계적인 절차를 제공한다.
    • 문제정의
    • 가설수립 및 분석방법 설정
    • 유의수준 및 임계치 설정
    • 분석 및 검정 통계량 산출
    • 결과 해석 및 가설 검증

예제를 활용한 통계분석 예제

  • 데이터 분석에서 가장 자주 사용되는 통계 기법 중의 하나는 t-검정이다.
  • 처음 t-검정을 배울 때는 비슷한 용어들이 많아서 혼동이 오기도 했다.
    • z-검정, t-검정, 분산분석
    • 이 중 2개 이하의 집단에서 평균을 비교하는 것은 z-검정, t-검정은 사실 동일한 분석방법이다.
    • 그러나, 실무에서는 t-검정을 자주 사용한다 (모집단의 분산을 알 수 있는 방법이 없다, 이는 자세히 한번 얘기하도록 하겠다)

(1) 문제 정의

  • 이제 부터 상상의 나래를 펼쳐보자.
    • 이제 온라인 쇼핑몰을 운영하는 사장이다.
    • 마케팅 부서에서는 콜센터를 통해 접수된 클레임 고객에 대한 타겟마케팅을 기획한다.
    • 클레임 고객은 상대적으로 매장을 찾는 횟수가 적어져 이탈위험도가 높을 것이라고 예상되기 때문이다.

(2) 가설설정 및 분석방법

  • 이제 가설 설정을 한다.
  • t검정을 실시할 때는 보통의 경우 평균의 차이는 없는 것으로 정한다.
    • $H_{0}$(귀무가설) = A쇼핑 클레임 고객들과 비클레임 고객들의 방문 횟수 차이는 없다.
    • $H_{1}$(연구가설) = A쇼핑 클레임 고객들과 비클레임 고객들의 방문횟수 차이는 있다.
  • 즉, 두 그룹간의 평균 비교이다.

(3) 데이터 수집 및 분석방법

  • 독립표본 t-검정을 수행하기 위해서는 평균과 등분산 여부, 그리고 t-value(검정 통계량)p-value(유의확률)을 출력한다.
    • 가장 중요한 것은 두 그룹간의 분산이 동일한지 확인할 필요가 있다.
  • 먼저 데이터를 불러온다.
# Mount Google Drive
from google.colab import drive # import drive from google colab

ROOT = "/content/drive"     # default location for the drive
print(ROOT)                 # print content of ROOT (Optional)
drive.mount(ROOT)           # we mount the google drive at /content/drive
/content/drive
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
# import join used to join ROOT path and MY_GOOGLE_DRIVE_PATH
from os.path import join  

# path to your project on Google Drive
MY_GOOGLE_DRIVE_PATH = 'My Drive/Colab Notebooks/inflearn/Python/Kaggle_Edu/05_statistics'

PROJECT_PATH = join(ROOT, MY_GOOGLE_DRIVE_PATH)
print(PROJECT_PATH)
/content/drive/My Drive/Colab Notebooks/inflearn/Python/Kaggle_Edu/05_statistics
%cd "{PROJECT_PATH}"
/content/drive/My Drive/Colab Notebooks/inflearn/Python/Kaggle_Edu/05_statistics
import pandas as pd
data = pd.read_csv('python_stat/Ashopping.csv', sep=",", encoding='CP949')
data.head()
고객ID이탈여부총_매출액방문빈도1회_평균매출액할인권_사용 횟수총_할인_금액고객등급구매유형클레임접수여부구매_카테고리_수거주지역성별고객_나이대거래기간할인민감여부멤버쉽_프로그램_가입전_만족도멤버쉽_프로그램_가입후_만족도RecencyFrequencyMonetary상품_만족도매장_만족도서비스_만족도상품_품질상품_다양성가격_적절성상품_진열_위치상품_설명_표시매장_청결성공간_편의성시야_확보성음향_적절성안내_표지판_설명친절성신속성책임성정확성전문성
01040070801723571115445140661410790577346567767.06.06766666666
1213168400142263142235099524044115370232332546766.0NaN7766653666
2302680780181489326186045141661610800667324676767.0NaN6666677667
34059466001734980015195141551610190357353556665.06.06656666656
45013745950731883019246350120660610860567675665665.06.05666556656
  • 데이터를 확인했다면, 이제, 클레임 접수여부에 따라 클레임이 없는 (0)고객과, 클레임이 있는 고객(1) 객체에 저장후 두 그룹의 방문빈도를 추출한다.
  • 우선 클레임이 없는 고객을 뽑자.
import numpy as np
no_claim = data[data.클레임접수여부 == 0]
no_claim_array = np.array(no_claim.방문빈도)
no_claim_array
array([ 17,  14,  73,  26,   6,  17,  19,  88,  39,  12,  27,  21,  56,
        16,  21,  28,  17,  15,  48,  42,  33,   9,  32,  15,  23,  24,
        18,  18,  38,  15,  16,  36,   8,  33,  41,  34,  12,  56,  60,
        27,  10,  39,  48,  24,   8,   7,  25,  19,  33,  22,  30,   9,
        80,  18,  15,  50,  71,  15,  66,  41,  18,   5,  78,  30,  14,
        10,  54,  21,  43,  33,  24,  21,  13,  25,  37,  25,  47,  60,
        21,  23,  18,  26,  28,  31,  58,  88,  19,  38,  37,  20,  33,
        18,  15,   7,  29,  30,   6,  16,  10,  23,  10,  14,  18,  11,
        15,  14,  90,   9,   9,   5,  15,  11,  33,   9,  20,   6,  42,
        17,  78,   9,  20,  37,  14,  17,  25,  52,  19,   9,  26,  16,
        49,  32,  24,  40,  44,  13,  16,  25,  16,  47,  27,   9,  15,
         5,  26,  34,  39,  18,  28,  16,  32,  81,  15,  41,   9,  10,
         9,   8,  56,  12,  65,  10,  45,  60,  22,  52,  15,  61,  18,
        12,  23,  93,  28,  12,  39, 103,  11,  28,   6,  35,   6,  86,
        17, 185,  16,  37,  21,  22,  50,  37,  14,  15,  28,  14,  11,
        31,  31,  59,  26,  20,  29,  23,  11,  29,  11, 108,   6,  37,
        29,  12,  11,  10,  18,  36,  73,  18,  22,  14,  22,  13,  31,
        15,  31,  25,  52,  10,  35,   9,   9,   5,  27,  12,  79,  21,
         8,  11,  64,  22,  60,  31,  15,  48,  18,   8,  31,  14,  46,
       102,  10,  34,   4,  23,  43,  45,   9,  18,  26,  12,   8,  81,
        51,  14,  28,  18,  24,  28,  15,  29,   8,   5,  17,  16,  28,
        36,  27,  11,  10,  20,  13,  54,  23,  14,  27,  13,  38,  38,
        79,  27,  97,   8,  10,  41,   6,  19,  16,  21,  46,  23,  39,
        38,  19,   7,   6,  33,  61,  15,  10, 114,  71,  33,  25,  79,
        13,  29,  34,  30,  19,  23,  40,  15,  17,   8,   3,   7,  21,
         9,  40,  46,  24,  73,  38,  56,  13,  13,  30,  46,   6,  30,
        19,   5,  20,  23,   7,  20,  26,  15,  58,  15,  11,  31,  17,
        10,  14,  20,  10,  50,  21,  37,  30,   6,  16,  23,  21, 102,
        26,  43,   8,  15,  10,  14,  71,  60,  45,  25,  49,  50,   9,
        18,  23,  29, 106,  35,  22,  12, 203,  12,  17,  14,  39,  11,
        19,  29,  22,  21,   9,  22,  11,  21,  58,  10,   5,  16,  39,
        13,  33,  13,  14,  13,  18,  42,  11,  29,  28,  35,   9,  21,
        26,  17,  24,   5,  23,  71,  22,  20,  20,   7,  14,  12,  10,
        16,  18,  30,  25,  22,  15,  18,  43,  33,  46,  14,  12,  24,
        23,  18,  23,   9,  13,  17,  22,   7,  18,  15,  39,  22,  22,
        22,   9,  15,  36,  24,  32,  38, 109,  28,  23,  20,  76,  43,
        25,   5,  46,  10,  22,  18,  30,  75,  34,  11,  17,  43,  39,
        84,  42,  41,  26,  32,  31,  37,  15,  50,  22,  19,   6,  19,
        11,   7,  25,  63,  21,  16,  67,  27,   5,  32,  31, 114,  20,
        21,  14,  80,  19,  14,  32,   4,  15,  37,  24,  14,  11,  10,
        20,  30,  10,  19,   6,  26,  26,   9,   4,  66,  16,  24,  29,
        33,  20,  19,  20,  49,  10,  15,  23])
  • 두번째, 클레임이 있는 고객을 뽑아본다.
claim = data[data.클레임접수여부 == 1]
claim_array = np.array(claim.방문빈도)
claim_array
array([ 18,  17, 109,  15,  21,   9,  12,  28,   5,  12,  12,  13,   8,
        18,  27,  34,  23,  19,  29,  10,  19,  28,  23,  30,  14,  20,
         7,  14,  32,  32,  18,  17,  10,  23,  12,   9,  43,  42,   7,
        12,  73,  26,  27,  25,  29,  37,  32,  45,  34,   7,  29,  26,
        27,  33,  27,  28,   8,  45,  66,  14,  73,  24,  13,  54,  24,
        17,  29,  29,  57,  18,  17,  27,  15,  23,  11,   4,  15,  31,
        21,  21,  11,  19,  34,  41,  18,  45,  10,  72,  18,  82,  10,
        26,  17,  37,  17,   8,  26,  11,  28,  17,  12,  23,  37,  19,
         7,  20,   9,  14,  13,  36,  26,  23,  23,  16,  30,  13,  45,
        30,   6,  44,  32,  19,  20,  24,   7,  14,   7,  65,  31,   6,
        37,  91,  17,  12,  23,  61, 162,  23,  21,  12,  14,  10,  18,
        14,   4,   6,  26,  19,  27,  14,   7,  32,  11,  11,  20,   7,
         7,   7,  27,  16,  26,  10,  12,   8,  12,  25,  14,  18,  30,
        33,  86,  20,  22,  10,  34,  36,   9,  68,  28,  14,  61,   9,
        17,   6,  30,  14,  25,  32,  19,  34,  26,  17,  24,  18,  30,
        15,  15,  96,  17,  18,  19,  24,  16,   6,  27,  31,  15,  38,
        11,   7,  65,  15,   7,  23,   7,  15,  34,  17,  20,  19,  10,
        14,  19,  69,   4,  21,  13,  20,  45,  50,  58,   6,  15,  10,
        10,  19,  32,   6,  38,  36,   6,  39,  16,  20,  48,  26,  21,
        22,   7,   8,  28,   8,  31,  13,  46,  20,   8,  49,   9,  48,
        20,  25,  54,  21,   6,  30,  40,  11,  12,  28,  15,  24,  90,
        22,  15,  14,   7,  77,  39,  11,  18,  16,  55,  15,  12,  17,
        23,  15,  33,  15,  18,  28,   7,  17,  34,  27,  44,  35,  67,
        12,  54,  18,  10,  21,  28,  67,   9, 126,  23,  10,  41,  15,
        21,  21,  42,  18,  31,  13,  20,  19,  39,  26,  11,  22,  64,
         4,  27,  21,  14,  30,  25,  18,  11,  10,  70,  24,  18,  19,
        30,  30,  19, 104,  39,  92,  52,  48,  30,  79,  15,  24,  23,
        14,   8,   9,  21,  18,  11,   7,   8,  13,  21,  23,   2,  12,
        12,  52,  22,  20,   6,  22,   6,  24,  12,  18,  20,  11,  12,
        33,   8,  24,  79,  34,   8,  36,  13,  19,   5,  12,  25,  31,
        27,  17,  11,  65,  29,  18,  10,  28,  22,  12,  18,  20,  27,
        17,  20,  17,   8,  38,  18,  25,  10,   7,  18,  11,  55,   5,
        20,  11,  41,  12,  11,  26,  55,  25,   6,  35,  38,  32,  27,
        11,  10,  11,  55,  22,  12,  18,  10,  15,  32,  13,  29,   8,
        17,  83,  15,   7,   8,  11,  27,  21,  18,  15,  19,   8,  16,
        35,  15,  40,   8])
  • 그 후, stats.bartlett() 함수를 이용하여 등분산 검정을 실시한다.
  • 이 때, 주의해야 하는 것이 있다.
  • 등분산 검정의 귀무가설과 대립가설을 다음과 같다.
    • H0 : 등분산이다.
    • H1 : 이분산이다(등분산이 아니다).
  • 즉, 등분산 가정의 귀무가설을 채택하려면 유의확률인 0.05 > p 나와야 한다.
from scipy import stats
stats.bartlett(no_claim_array, claim_array)
BartlettResult(statistic=13.626177910965525, pvalue=0.00022305349806448475)
  • 여기에서 두 고객 그룹간의 등분산 검정 결과 F값은 13.626, 유의확률은 0.05미만으로 귀무가설이 기각된다.
    • 즉, 두 집단의 분산은 동일하지 않은 것으로 나타났다.
  • 등분산성이 나와야 하는데, 나오지 않아서 입문자들이 조금 당혹스러워 할 수 있다.
    • 굳이 당황할 필요는 없다. 분산이 동일하지 않으면 동일하지 않다고 표시만 해두면 된다. (check: equal_var)
  • 이제 ttest_ind를 활용해서 구하도록 하자.
print(stats.ttest_ind(no_claim_array, claim_array, equal_var=False))
Ttest_indResult(statistic=2.595726838875684, pvalue=0.009577734932789503)
  • 독립표본 t-value2.59이며, p-value 0.0095로 나왔다.
    • 이 의미는 두 그룹간의 평균 방문 빈도에 차이가 있음을 의미한다.
  • 조금 더 구체적으로 구해보자.

(4) 시각화

  • 실제 두 그룹간의 차이를 matplotlib을 활용하여 시각화로 구현해본다.
  • 이 때, 각 그룹의 평균(Mean)표준편차(Standard Deviation)를 구한다.
# 평균 계산하기
no_claim_mean = np.mean(no_claim_array)
claim_mean = np.mean(claim_array)
print("클레임이 없는 고객의 평균 방문빈도:", no_claim_mean)
print("클레임이 있는 고객의 평균 방문빈도:", claim_mean)

# 표준편차 구하기
no_claim_std = np.std(no_claim_array)
claim_std = np.std(claim_array)
print("클레임이 없는 고객의 표준편차:", no_claim_std)
print("클레임이 있는 고객의 표준편차:", claim_std)

# 라벨 정리
viz_labels = ['No Claim', 'Claim']
x_pos = np.arange(len(viz_labels))
avg = (no_claim_mean, claim_mean)
error = [no_claim_std, claim_std]
클레임이 없는 고객의 평균 방문빈도: 28.184842883548985
클레임이 있는 고객의 평균 방문빈도: 24.736383442265794
클레임이 없는 고객의 표준편차: 22.7348095052013
클레임이 있는 고객의 표준편차: 19.234427104778828
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.bar(x_pos, avg,
       yerr = error,
       align='center',
       alpha=0.5,
       ecolor='black',
       capsize=10)
ax.set_ylabel('Avg. Customer Visitation')
ax.set_xticks(x_pos)
ax.set_xticklabels(viz_labels)
ax.set_title('The Customer difference between No Claim and Claim')
ax.yaxis.grid(True)

plt.tight_layout()
plt.show()

png

삼성카드 대회 Track-2 - 포지셔닝 분석(2)

대회 소개

  • 삼성카드 데이터분석 공모전이 시행되고 있다.
    • 대회에 처음 참여하는 아시아경제-수강생들을 위해 일종의 가이드라인으로 제안하고자 한다.
  • 본 포스트에서는 기본적인 내용만 전달하고자 함을 밝힌다.
    • Track2 과정은 마케팅 전략 제안이 중요하다!

포지셔닝 분석 개요

  • 마케팅에서 자주 보는 분석 방법중의 하나는 포지셔닝(Positioning) 기법이다.
  • 포지셔닝 분석은 마케팅 통계분석 기법중의 하나로, 기업이나, 상품, 브랜드 같은 개체들의 포지셔닝을 수행하는 다차원 척도법(MDS: Multi-Dimensional Scaling)과 상응분석(Correspondence Analysis)이 있다.
  • 위 두가지 분석 방법 중 무엇을 사용해야 할까?
    • 만약 데이터셋이 주로 등간척도, 비율척도와 같이 구성되어 있다면 다차원 척도법
    • 만약 데이터셋이 주로 명목척도, 서열척도와 같이 구성되어 있다면 상응분석
  • 현재 삼성카드 대회의 주 데이터셋은 명목척도 및 서열척도로 구성되어 있기 때문에 상응분석으로 시작하면 된다.

상응분석

(1) 기본 개념

  • 상응분석을 사용하려면 빈도교차표를 만들어야 한다.
  • 요약하면, 상응분석은 범주형 변수의 빈도를 나타내고 있는 빈도교차표의 행과 열(명목변수의 범주 값들)을 그래프상의 자극점 형태로 표시하는 방법.
  • 이 때, 단순 상응분석은 2개의 변수, 다중 상응분석은 3개 이상의 변수 활용한다.
  • 이 때, 상응분석은 카이제곱 검정과 같이 범주형 변수간의 상호연관성을 바탕으로 진행된다.
    • 따라서, 두 개의 범주형 변수가 서로 연관성을 가지고 있다는 전제하에서 진행된다.

(2) 데이터 불러오기

  • 먼저 필요한 데이터를 불러온다.
  • 필자는 구글 코랩에서 데이터를 불러오기 때문에
%config InlineBackend.figure_format = 'retina'
!sudo apt-get -qq -y install fonts-nanum
The following package was automatically installed and is no longer required:
  libnvidia-common-440
Use 'apt autoremove' to remove it.
The following NEW packages will be installed:
  fonts-nanum
0 upgraded, 1 newly installed, 0 to remove and 39 not upgraded.
Need to get 9,604 kB of archives.
After this operation, 29.5 MB of additional disk space will be used.
Selecting previously unselected package fonts-nanum.
(Reading database ... 144579 files and directories currently installed.)
Preparing to unpack .../fonts-nanum_20170925-1_all.deb ...
Unpacking fonts-nanum (20170925-1) ...
Setting up fonts-nanum (20170925-1) ...
Processing triggers for fontconfig (2.12.6-0ubuntu2) ...
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.font_manager as fm
/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
  import pandas.util.testing as tm
for font in fm.fontManager.ttflist:
    if 'Nanum' in font.name:
        print(font.name, font.fname)
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothic.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundR.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareR.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundB.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothicBold.ttf
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjo.ttf
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjoBold.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareB.ttf
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothicBold.ttf
fontpath = '/usr/share/fonts/truetype/nanum/NanumGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumGothic') 
plt.rcParams["figure.figsize"] = (20, 10)
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.color'] = 'r'
plt.rcParams['axes.grid'] = True 
mpl.font_manager._rebuild()
fm._rebuild()
  • 한글 텍스트가 잘 나오는지 확인해본다.
font = {'family' : 'NanumGothic',
        'weight' : 'bold',
        'size'   : 22}

plt.rc('font', **font)
plt.text(0.3, 0.3, '한글', size=100)
Text(0.3, 0.3, '한글')

png

삼성카드 대회 Track-2 - 포지셔닝 분석(1)

대회 소개

  • 삼성카드 데이터분석 공모전이 시행되고 있다.
    • 대회에 처음 참여하는 아시아경제-수강생들을 위해 일종의 가이드라인으로 제안하고자 한다.
  • 본 포스트에서는 기본적인 내용만 전달하고자 함을 밝힌다.
    • Track2 과정은 마케팅 전략 제안이 중요하다!

포지셔닝 분석 개요

  • 마케팅에서 자주 보는 분석 방법중의 하나는 포지셔닝(Positioning) 기법이다.
  • 포지셔닝 분석은 마케팅 통계분석 기법중의 하나로, 기업이나, 상품, 브랜드 같은 개체들의 포지셔닝을 수행하는 다차원 척도법(MDS: Multi-Dimensional Scaling)과 상응분석(Correspondence Analysis)이 있다.
  • 위 두가지 분석 방법 중 무엇을 사용해야 할까?
    • 만약 데이터셋이 주로 등간척도, 비율척도와 같이 구성되어 있다면 다차원 척도법
    • 만약 데이터셋이 주로 명목척도, 서열척도와 같이 구성되어 있다면 상응분석
  • 현재 삼성카드 대회의 주 데이터셋은 명목척도 및 서열척도로 구성되어 있기 때문에 상응분석으로 시작하면 된다.

상응분석

  • Correspondence Analysis는 범주형 변수(수준)들 간의 연관성을 분석한 후, 그 결과를 시각적 해석이 용이하도록 그래프화 하는 것임

(1) 기본 개념

  • 상응분석을 사용하려면 빈도교차표를 만들어야 한다.
  • 요약하면, 상응분석은 범주형 변수의 빈도를 나타내고 있는 빈도교차표의 행과 열(명목변수의 범주 값들)을 그래프상의 자극점 형태로 표시하는 방법.
  • 이 때, 단순 상응분석은 2개의 변수, 다중 상응분석은 3개 이상의 변수 활용한다.
  • 이 때, 상응분석은 카이제곱 검정과 같이 범주형 변수간의 상호연관성을 바탕으로 진행된다.
    • 따라서, 두 개의 범주형 변수가 서로 연관성을 가지고 있다는 전제하에서 진행된다.

(2) 데이터 불러오기

  • 먼저 필요한 데이터를 불러온다.
  • 필자는 구글 코랩에서 데이터를 불러오기 때문에
%config InlineBackend.figure_format = 'retina'
!sudo apt-get -qq -y install fonts-nanum
The following package was automatically installed and is no longer required:
  libnvidia-common-440
Use 'apt autoremove' to remove it.
The following NEW packages will be installed:
  fonts-nanum
0 upgraded, 1 newly installed, 0 to remove and 39 not upgraded.
Need to get 9,604 kB of archives.
After this operation, 29.5 MB of additional disk space will be used.
Selecting previously unselected package fonts-nanum.
(Reading database ... 144579 files and directories currently installed.)
Preparing to unpack .../fonts-nanum_20170925-1_all.deb ...
Unpacking fonts-nanum (20170925-1) ...
Setting up fonts-nanum (20170925-1) ...
Processing triggers for fontconfig (2.12.6-0ubuntu2) ...
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.font_manager as fm
/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
  import pandas.util.testing as tm
for font in fm.fontManager.ttflist:
    if 'Nanum' in font.name:
        print(font.name, font.fname)
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothicBold.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothicBold.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareB.ttf
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjoBold.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundB.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareR.ttf
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjo.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundR.ttf
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothic.ttf
fontpath = '/usr/share/fonts/truetype/nanum/NanumGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumGothic') 
plt.rcParams["figure.figsize"] = (20, 10)
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.color'] = 'r'
plt.rcParams['axes.grid'] = True 
mpl.font_manager._rebuild()
fm._rebuild()
  • 한글 텍스트가 잘 나오는지 확인해본다.
font = {'family' : 'NanumGothic',
        'weight' : 'bold',
        'size'   : 22}

plt.rc('font', **font)
plt.text(0.3, 0.3, '한글', size=100)
Text(0.3, 0.3, '한글')

png

Python 통계 - 포지셔닝 분석(2)

강의 홍보

포지셔닝 분석 개요

  • 마케팅에서 자주 보는 분석 방법중의 하나는 포지셔닝(Positioning) 기법이다.
  • 포지셔닝 분석은 마케팅 통계분석 기법중의 하나로, 기업이나, 상품, 브랜드 같은 개체들의 포지셔닝을 수행하는 다차원 척도법(MDS: Multi-Dimensional Scaling)과 상응분석(Correspondence Analysis)이 있다.
  • 위 두가지 분석 방법 중 무엇을 사용해야 할까?
    • 만약 데이터셋이 주로 등간척도, 비율척도와 같이 구성되어 있다면 다차원 척도법
    • 만약 데이터셋이 주로 명목척도, 서열척도와 같이 구성되어 있다면 상응분석
  • 현재 삼성카드 대회의 주 데이터셋은 명목척도 및 서열척도로 구성되어 있기 때문에 상응분석으로 시작하면 된다.

상응분석

  • Correspondence Analysis는 범주형 변수(수준)들 간의 연관성을 분석한 후, 그 결과를 시각적 해석이 용이하도록 그래프화 하는 것임

(1) 기본 개념

  • 상응분석을 사용하려면 빈도교차표를 만들어야 한다.
  • 요약하면, 상응분석은 범주형 변수의 빈도를 나타내고 있는 빈도교차표의 행과 열(명목변수의 범주 값들)을 그래프상의 자극점 형태로 표시하는 방법.
  • 이 때, 단순 상응분석은 2개의 변수, 다중 상응분석은 3개 이상의 변수 활용한다.
  • 이 때, 상응분석은 카이제곱 검정과 같이 범주형 변수간의 상호연관성을 바탕으로 진행된다.
    • 따라서, 두 개의 범주형 변수가 서로 연관성을 가지고 있다는 전제하에서 진행된다.

(2) 데이터 불러오기

  • 먼저 필요한 데이터를 불러온다.
  • 필자는 구글 코랩에서 데이터를 불러오기 때문에
%config InlineBackend.figure_format = 'retina'
!apt -qq -y install fonts-nanum
fonts-nanum is already the newest version (20170925-1).
The following package was automatically installed and is no longer required:
  libnvidia-common-440
Use 'apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 39 not upgraded.
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.font_manager as fm
/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
  import pandas.util.testing as tm
for font in fm.fontManager.ttflist:
    if 'Nanum' in font.name:
        print(font.name, font.fname)
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjo.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareR.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareB.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothicBold.ttf
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjoBold.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundR.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundB.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothic.ttf
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothicBold.ttf
fontpath = '/usr/share/fonts/truetype/nanum/NanumGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumGothic') 
plt.rcParams["figure.figsize"] = (20, 10)
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.color'] = 'r'
plt.rcParams['axes.grid'] = True 
mpl.font_manager._rebuild()
fm._rebuild()
font = {'family' : 'NanumGothic',
        'weight' : 'bold',
        'size'   : 22}

plt.rc('font', **font)
plt.text(0.3, 0.3, '한글', size=100)
Text(0.3, 0.3, '한글')

png

Python 통계 - 포지셔닝 분석(1)

강의 홍보

포지셔닝 분석 개요

  • 마케팅에서 자주 보는 분석 방법중의 하나는 포지셔닝(Positioning) 기법이다.
  • 포지셔닝 분석은 마케팅 통계분석 기법중의 하나로, 기업이나, 상품, 브랜드 같은 개체들의 포지셔닝을 수행하는 다차원 척도법(MDS: Multi-Dimensional Scaling)과 상응분석(Correspondence Analysis)이 있다.
  • 위 두가지 분석 방법 중 무엇을 사용해야 할까?
    • 만약 데이터셋이 주로 등간척도, 비율척도와 같이 구성되어 있다면 다차원 척도법
    • 만약 데이터셋이 주로 명목척도, 서열척도와 같이 구성되어 있다면 상응분석
  • 현재 삼성카드 대회의 주 데이터셋은 명목척도 및 서열척도로 구성되어 있기 때문에 상응분석으로 시작하면 된다.

상응분석

  • Correspondence Analysis는 범주형 변수(수준)들 간의 연관성을 분석한 후, 그 결과를 시각적 해석이 용이하도록 그래프화 하는 것임

(1) 기본 개념

  • 상응분석을 사용하려면 빈도교차표를 만들어야 한다.
  • 요약하면, 상응분석은 범주형 변수의 빈도를 나타내고 있는 빈도교차표의 행과 열(명목변수의 범주 값들)을 그래프상의 자극점 형태로 표시하는 방법.
  • 이 때, 단순 상응분석은 2개의 변수, 다중 상응분석은 3개 이상의 변수 활용한다.
  • 이 때, 상응분석은 카이제곱 검정과 같이 범주형 변수간의 상호연관성을 바탕으로 진행된다.
    • 따라서, 두 개의 범주형 변수가 서로 연관성을 가지고 있다는 전제하에서 진행된다.

(2) 데이터 불러오기

  • 먼저 필요한 데이터를 불러온다.
  • 필자는 구글 코랩에서 데이터를 불러오기 때문에
%config InlineBackend.figure_format = 'retina'
!apt -qq -y install fonts-nanum
fonts-nanum is already the newest version (20170925-1).
The following package was automatically installed and is no longer required:
  libnvidia-common-440
Use 'apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 39 not upgraded.
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.font_manager as fm
/usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
  import pandas.util.testing as tm
for font in fm.fontManager.ttflist:
    if 'Nanum' in font.name:
        print(font.name, font.fname)
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjoBold.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundR.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareB.ttf
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothicBold.ttf
NanumMyeongjo /usr/share/fonts/truetype/nanum/NanumMyeongjo.ttf
NanumGothic /usr/share/fonts/truetype/nanum/NanumGothic.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothicBold.ttf
NanumSquareRound /usr/share/fonts/truetype/nanum/NanumSquareRoundB.ttf
NanumBarunGothic /usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf
NanumSquare /usr/share/fonts/truetype/nanum/NanumSquareR.ttf
fontpath = '/usr/share/fonts/truetype/nanum/NanumGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumGothic') 
plt.rcParams["figure.figsize"] = (20, 10)
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.color'] = 'r'
plt.rcParams['axes.grid'] = True 
mpl.font_manager._rebuild()
fm._rebuild()
font = {'family' : 'NanumGothic',
        'weight' : 'bold',
        'size'   : 22}

plt.rc('font', **font)
plt.text(0.3, 0.3, '한글', size=100)
Text(0.3, 0.3, '한글')

png

ch 13 - Reliability

Intro

  • PLS-SEM의 분석과정에서 척도(측정변수와 잠재변수)의 신뢰도와 타당도를 확보하는 것은 매우 중요하며, 신뢰도와 타당도가 확보되지 않으면 모델 추정 결과가 의미가 없기 때문임
  • 즉, 구조모델의 추정을 실행하려면 사전에 반드시 측정모델에 대한 평가과정을 통해 신뢰도와 타당도 확보 필요

I. 주요 개념

(1) 신뢰도

  • 잠재변수의 측정에 있어서 얼마나 일관성이 있는가의 정도 의미
    • 검사도구의 일관성을 말하며, 일관성이란 잠재변수를 여러 번에 걸쳐 측정했을 때 매번 같은 결과를 도출할 수 있는 정도.
    • 내적 일관성 신뢰(Internal Consistency Reliability)로 평가

(2) 타당도

  • 타당도의 기본 정의는 실제 측정하고자 하는 잠재변수를 정확하게 측정하고 있는 정도
    • PLS-SEM에서는 집중타당도(Convergent Validity)와 판별타당도(Discriminant Validity)를 사용한다.
    • 전자는 하나의 잠재변수를 측정하기 위해 사용되는 척도의 구성항목들 간에 상관관계가 높아야 집중타당도가 있다고 볼 수 있고, 후자는 하나의 잠재변수와 다른 잠재변수간 상관관계가 낮을수록 판별 타당도가 높다고 판단함.

(3) PLS-SEM 분석 결과의 쳬계적인 평가 단계

  • 반영적 측정모델: 내적 일관성 신뢰도, 집중타당도, 판별타당도
  • 형성적 측정모델: 집중타당도, 다중공선성, 외부가중치와 외부적재치의 유의성과 적합성
  • 구조모델의 평가기준: 다중공선성, 결정계수 $R^2$, 효과크기 $f^2$, 예측적 적합성 $Q^2$, 경로계수의 유의성과 적합성
  • PLS-SEM의 평가 단계: 제 1단계는 측정모델(Outer Model)을 평가하는 것이며, 제 2단계는 구조모델(Inner Model)을 평가하는 것이다.

II. 설문조사 데이터 분석

  • 이제 설문지를 분석해본다.
  • 필수 패키지를 확인한다.
library(readr) 
library(dplyr)
library(kableExtra) 
library(psy) # 신뢰도
library(corrplot) # 상관계수
library(psychometric) # 타당도 

(1) 데이터 수집

  • 먼저 수집된 설문조사 데이터를 확인한다.
data <- read_csv('data/thesis_mater.csv') %>% 
  distinct() %>% # 중복데이터 제거
  rename(Position = founder_employee, # 출력을 위한 변수명 정리
         Age = age_of_respondent, 
         Education = Education_Level) %>% 
  slice(-c(1:10)) %>% 
  dplyr::select(-c(Firm_Age:Business_Area))

data %>% 
  head() %>% 
  kable() %>% 
  kable_styling("striped") %>% 
  scroll_box(width = "100%")
EI_1EI_2EI_3EP_1EP_2EP_3ER_1ER_2ER_3SS_1SS_2SS_3SC_1SC_2SC_3SR_1SR_2SR_3F1F2F3NF1NF2NF3Firm_AgeFirm_SizeWE1WE2WE3genderfounder_employeeage_of_respondentEducation_LevelBusiness_Area
2343343241133332212233135 years aboveAbove 15 membersNo, I don't have experienceYesYesFemaleEmployee30-39Undergraduate SchoolOthers
552353444222222222222322Less than 2 yearsLess than 5 membersNo, I don't have experienceNoYesMaleEmployeeYounger than 30Undergraduate SchoolMedia and Entertainment
1221121212211221212111115 years aboveLess than 5 membersAs founder or employee, I have startup experiences more than 3 timesNoYesFemaleFounder of CompanyYounger than 30Undergraduate SchoolOthers
332121213213111233332322Less than 2 yearsLess than 5 membersNo, I don't have experienceYesYesMaleEmployeeYounger than 30Undergraduate SchoolOthers
5352544444545555554544553-4 yearsLess than 5 membersAs founder or employee, I have startup experiences more than 3 timesNoYesMaleFounder of Company30-39Undergraduate SchoolOthers
1331332314123312211231315 years above5-9 membersAs founder or employee, I have startup experience, one timeNoNoFemaleEmployeeYounger than 30Undergraduate SchoolOthers

(2) 상관관계 확인

  • 각 척도(Item)에서의 상관관계를 확인해본다.
M <- cor(data)

corrplot(M, type="upper", order="hclust", 
         col=RColorBrewer::brewer.pal(n=8, name="RdBu"))

ch 12 - Demographic of Respondent in R

Intro

  • 지난 시간에 설문조사 전처리에 대해 배웠다면 이번에는 경영/사회과학 논문에서 필수적으로 기재해야 하는 표본의 특성을 간단한 프로그램으로 요약하는 것을 코딩한다.

(1) 주요 패키지

  • 이번 포스트부터 gt 패키지를 사용하려고 한다.
    • gt: ggplot2와 같이 Table를 문법으로 컨트롤 할 수 있도록 구현된 패키지이다.
    • kableExtra: HTML로 출력할 수 있도록 도와주는 패키지이다.
library(readr)
library(dplyr)
library(gt)
library(gtsummary)

I. 데이터 가져오기

  • 우선 데이터를 불러온다.
data <- read_csv('data/thesis_mater.csv') %>% 
  distinct() %>% # 중복데이터 제거
  rename(Position = founder_employee, # 출력을 위한 변수명 정리
         Age = age_of_respondent, 
         Education = Education_Level)
glimpse(data %>% select(Firm_Age:Business_Area))
  • 전체 34개의 변수 중에서, 문자열 관련 데이터만 추출하였다.
  • 어떤 데이터를 표본의 특성으로 삼아야 할까?
    • 위 10개의 데이터에는 통제변수1가 들어가 있다.
    • 통제변수는 표본의 특징이 아니기 때문에 통제변인을 제외한 나머지 변수들을 추출한다.
## Rows: 103
## Columns: 10
## $ Firm_Age      <chr> "5 years above", "Less than 2 years", "5 years above", …
## $ Firm_Size     <chr> "Above 15 members", "Less than 5 members", "Less than 5…
## $ WE1           <chr> "No, I don't have experience", "No, I don't have experi…
## $ WE2           <chr> "Yes", "No", "No", "Yes", "No", "No", "No", "No", "No",…
## $ WE3           <chr> "Yes", "Yes", "Yes", "Yes", "Yes", "No", "Yes", "No", "…
## $ gender        <chr> "Female", "Male", "Female", "Male", "Male", "Female", "…
## $ Position      <chr> "Employee", "Employee", "Founder of Company", "Employee…
## $ Age           <chr> "30-39", "Younger than 30", "Younger than 30", "Younger…
## $ Education     <chr> "Undergraduate School", "Undergraduate School", "Underg…
## $ Business_Area <chr> "Others", "Media and Entertainment", "Others", "Others"…
  • 표본의 특성을 기술하는 데이터는 아래와 같이 추출한다.
    • gender, founder_employee, age_of_respondent, educational_level, business_area
data2 <- data %>% 
  select(gender, Position, Age, Education, Business_Area)

glimpse(data2)
## Rows: 103
## Columns: 5
## $ gender        <chr> "Female", "Male", "Female", "Male", "Male", "Female", "…
## $ Position      <chr> "Employee", "Employee", "Founder of Company", "Employee…
## $ Age           <chr> "30-39", "Younger than 30", "Younger than 30", "Younger…
## $ Education     <chr> "Undergraduate School", "Undergraduate School", "Underg…
## $ Business_Area <chr> "Others", "Media and Entertainment", "Others", "Others"…

II. 표본 특성 표 출력

  • 보통 논문에 들어가는 표본의 특징은 Category, Frequency, and Percentage(%) 정도만 필요하다.
  • 이 때, Table을 가공해줄 수 있는 gtsummary 패키지를 활용한다.
set_gtsummary_theme(theme_gtsummary_journal(journal = "jama"))

data2 %>% 
  tbl_summary(by = gender) %>% 
  add_overall() %>% 
  add_n() %>% 
  modify_header(label = "**Variable**") %>% # update the column header
  bold_labels()
VariableNOverall, N = 103Female, N = 621Male, N = 411
Position103
Employee68 (66)35 (56)33 (80)
Founder of Company35 (34)27 (44)8 (20)
Age103
30-3937 (36)19 (31)18 (44)
40-498 (7.8)4 (6.5)4 (9.8)
50 or above2 (1.9)2 (3.2)0 (0)
Younger than 3056 (54)37 (60)19 (46)
Education103
Graduate School25 (24)15 (24)10 (24)
High School7 (6.8)6 (9.7)1 (2.4)
Undergraduate School71 (69)41 (66)30 (73)
Business_Area103
E-Commerce16 (16)11 (18)5 (12)
Education4 (3.9)2 (3.2)2 (4.9)
Energy1 (1.0)0 (0)1 (2.4)
Enterprise Services4 (3.9)2 (3.2)2 (4.9)
Fintech9 (8.7)6 (9.7)3 (7.3)
Logistics5 (4.9)1 (1.6)4 (9.8)
Manufacturing3 (2.9)2 (3.2)1 (2.4)
Media and Entertainment7 (6.8)4 (6.5)3 (7.3)
Medical and Healthcare1 (1.0)1 (1.6)0 (0)
Online to Offline Commerce2 (1.9)1 (1.6)1 (2.4)
Others45 (44)31 (50)14 (34)
Real Estate and Household1 (1.0)0 (0)1 (2.4)
Transportation/Automotive4 (3.9)0 (0)4 (9.8)
Travel1 (1.0)1 (1.6)0 (0)

1 Statistics presented: n (%)

ch 11 - Data Import & Label Encoding in R

Intro

  • 설문조사가 끝났으면 이제 정리를 해야 한다.
  • 일련의 과정은 보통 코딩이라 부른다.

(1) 주요 패키지

  • 이번 포스트부터 gt 패키지를 사용하려고 한다.
    • gt: ggplot2와 같이 Table를 문법으로 컨트롤 할 수 있도록 구현된 패키지이다.
    • kableExtra: HTML로 출력할 수 있도록 도와주는 패키지이다.

문제점

  • SmartPLS 프로그램을 쓴다 하더라도 기본적으로 모든 데이터의 entry는 수치형으로 일단 바뀌어 있어야 한다.
  • 우선 데이터를 불러와서 확인해보자.
library(tidyverse)
library(gt)
library(kableExtra)


# 데이터 불러오기
data <- read_csv("data/thesis_mater.csv")

data %>% 
  head() %>% 
  kable() %>% 
  kable_styling("striped") %>% 
  scroll_box(width = "100%")
EI_1EI_2EI_3EP_1EP_2EP_3ER_1ER_2ER_3SS_1SS_2SS_3SC_1SC_2SC_3SR_1SR_2SR_3F1F2F3NF1NF2NF3Firm_AgeFirm_SizeWE1WE2WE3genderfounder_employeeage_of_respondentEducation_LevelBusiness_Area
2343343241133332212233135 years aboveAbove 15 membersNo, I don't have experienceYesYesFemaleEmployee30-39Undergraduate SchoolOthers
552353444222222222222322Less than 2 yearsLess than 5 membersNo, I don't have experienceNoYesMaleEmployeeYounger than 30Undergraduate SchoolMedia and Entertainment
1221121212211221212111115 years aboveLess than 5 membersAs founder or employee, I have startup experiences more than 3 timesNoYesFemaleFounder of CompanyYounger than 30Undergraduate SchoolOthers
332121213213111233332322Less than 2 yearsLess than 5 membersNo, I don't have experienceYesYesMaleEmployeeYounger than 30Undergraduate SchoolOthers
5352544444545555554544553-4 yearsLess than 5 membersAs founder or employee, I have startup experiences more than 3 timesNoYesMaleFounder of Company30-39Undergraduate SchoolOthers
1331332314123312211231315 years above5-9 membersAs founder or employee, I have startup experience, one timeNoNoFemaleEmployeeYounger than 30Undergraduate SchoolOthers
  • 위 데이터에서 보면 알 수 있듯이, WE1 ~ Business_Area 까지의 데이터는 모두 문자로 되어 있다.
  • Python에서는 LabelEncoder라는 것이 있다.
  • R에서는 기본 문법인 factor만 있어도 가능하다.

Factor의 활용

  • 이제 본격적으로 코딩을 시작한다.
  • 데이터 전처리에서 쉬운 방법은 없다.

(1) 기본

  • 가상의 데이터를 만든 후 factor를 활용하자.
temp <- data.frame(x = c(1, 1, 2), 
                   gender = c("Female", "Male", "Male"))
temp
##   x gender
## 1 1 Female
## 2 1   Male
## 3 2   Male
  • 이제 gender를 변환하자.
temp$gender <- as.numeric(factor(temp$gender))
temp
##   x gender
## 1 1      1
## 2 1      2
## 3 2      2
  • factor로 변환한 뒤, as.numeric으로 형 변환을 하면 쉽게 바꿀수는 있다.
  • 위와 같이 형변환을 하면 1이 무엇을 의미하는지, 2는 무엇을 의미하는지 알 수 없게 된다. (즉, 정보의 손실이 올 수 있다.)

(2) 응용

  • 이제 factor를 조금 더 활용해 본다.
  • 같은 가상의 데이터를 사용한다.
temp <- data.frame(x = c(1, 1, 2), 
                   gender = c("Female", "Male", "Male"))

temp$gender <- as.numeric(factor(temp$gender), 
                          levels = c("Female", "Male"), 
                          labels = c(1, 2))

temp
##   x gender
## 1 1      1
## 2 1      2
## 3 2      2
  • 결과는 똑같다. 그러나, 각 label에 대한 해석이 보다 명확해지기 때문에 추후 분석결과보고서를 작성할 때 보다 쉽게 작성할 수 있다.

(3) 적용

  • 이제 내 데이터에 적용해보자.
  • 적용해야 할 변수는 모두 Firm_Age ~ Business_Area 까지이다.
  • 여기에서 하나의 Rule을 만들어야 한다.
    • 각 범주마다 하나씩 맞추는 노가다는 지양해야 한다.
    • 따라서, 범주의 값은 모두 알파벳순으로 정렬한다.
    • 이를 프로그래밍으로 해결한다.
temp <- data.frame(x = c(1, 1, 2), 
                   gender = c("Female", "Male", "Male"),
                   grade = c("A", "B", "C"))

temp
##   x gender grade
## 1 1 Female     A
## 2 1   Male     B
## 3 2   Male     C
  • 데이터가 하나 더 생겼다. 다음과 같은 함수를 만든다.
factor2numeric <- function(x) {
  # input 변수가 문자형인지 확인하여 다음 코드를 실행한다. 
  # 만약 문자가 아니면 `else` 코드로 넘어간다. 
  if(is.character(x) == TRUE) { 
      # levels 함수를 사용하면 알파벳으로 자동 정렬해준다.
      char_levels <- levels(factor(x)) 
      
      # 변환되기 전 factor의 `level`를 확인한다.
      print("----변환 시작 전----")
      print(char_levels)   
      
      # factor형으로 변환했다. 
      x <- factor(x, 
                  levels = char_levels, 
                  labels = c(1:length(char_levels))) # 이 코드는 labels 숫자로 정의한다. 
     
       # 변환되기 전 factor의 `level`를 확인한다.
      print(levels(x)) 
      print("----변환 종료----")
  } else {
    # 에러 메시지를 출력한다
    print("This is not character!!")
  } 
  return(x)
}

# 전체 데이터에서 character인 데이터를 사용자 정의 함수를 적용하였다. 
data2 <- data %>% 
  mutate_if(is.character, factor2numeric)
## [1] "----변환 시작 전----"
## [1] "3-4 years"         "5 years above"     "Less than 2 years"
## [1] "1" "2" "3"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "10-14 members"       "5-9 members"         "Above 15 members"   
## [4] "Less than 5 members"
## [1] "1" "2" "3" "4"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "As founder or employee,  I have startup experience, one time"        
## [2] "As founder or employee, I have startup experiences more than 3 times"
## [3] "As founder or employee, I have startup experiences, two times"       
## [4] "No, I don't have experience"                                         
## [1] "1" "2" "3" "4"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "No"  "Yes"
## [1] "1" "2"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "No"  "Yes"
## [1] "1" "2"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "Female" "Male"  
## [1] "1" "2"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "Employee"           "Founder of Company"
## [1] "1" "2"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "30-39"           "40-49"           "50 or above"     "Younger than 30"
## [1] "1" "2" "3" "4"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
## [1] "Graduate School"      "High School"          "Undergraduate School"
## [1] "1" "2" "3"
## [1] "----변환 종료----"
## [1] "----변환 시작 전----"
##  [1] "E-Commerce"                 "Education"                 
##  [3] "Energy"                     "Enterprise Services"       
##  [5] "Fintech"                    "Logistics"                 
##  [7] "Manufacturing"              "Media and Entertainment"   
##  [9] "Medical and Healthcare"     "Online to Offline Commerce"
## [11] "Others"                     "Real Estate and Household" 
## [13] "Transportation/Automotive"  "Travel"                    
##  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12" "13" "14"
## [1] "----변환 종료----"

(4) 중복치와 결측치 확인

  • 모든 것을 온라인으로 받다보니, 중복치와 결측치가 발생할 수 있다.
  • 따라서 해당 내용이 있는지 확인한다.
sum(duplicated(data2))
## [1] 5
  • 중복치가 5개 인것으로 확인이 된다.
  • 중복치를 제거하는 것은 간단하다.
data3 <- data2 %>% distinct()
  • 이번에는 결측치를 확인한다.
colSums(is.na(data3))
##              EI_1              EI_2              EI_3              EP_1 
##                 0                 0                 0                 0 
##              EP_2              EP_3              ER_1              ER_2 
##                 0                 0                 0                 0 
##              ER_3              SS_1              SS_2              SS_3 
##                 0                 0                 0                 0 
##              SC_1              SC_2              SC_3              SR_1 
##                 0                 0                 0                 0 
##              SR_2              SR_3                F1                F2 
##                 0                 0                 0                 0 
##                F3               NF1               NF2               NF3 
##                 0                 0                 0                 0 
##          Firm_Age         Firm_Size               WE1               WE2 
##                 0                 0                 0                 0 
##               WE3            gender  founder_employee age_of_respondent 
##                 0                 0                 0                 0 
##   Education_Level     Business_Area 
##                 0                 0
  • column마다 결측치를 확인한 결과 모두 0인 것을 확인할 수 있다.

(5) 결과 확인

  • 이제 변환된 결과를 확인한다.
# 결과값을 확인한다. 
data3 %>% 
  head() %>% 
  kable() %>% 
  kable_styling("striped") %>% 
  scroll_box(width = "100%")
EI_1EI_2EI_3EP_1EP_2EP_3ER_1ER_2ER_3SS_1SS_2SS_3SC_1SC_2SC_3SR_1SR_2SR_3F1F2F3NF1NF2NF3Firm_AgeFirm_SizeWE1WE2WE3genderfounder_employeeage_of_respondentEducation_LevelBusiness_Area
23433432411333322122331323422111311
5523534442222222222223223441221438
12211212122112212121111124212124311
33212121321311123333232234422214311
53525444445455555545445514212221311
13313323141233122112313122111114311

파일 내보내기

  • 이제 SmartPLS에서 사용할 수 있도록 csv 파일 형태로 내보낸다.
write_csv(data3, "~/Desktop/thesis_master2.csv")

소결론

  • 데이터 전처리는 중요하다. 그러나, 시간이 조금 걸린다.
  • 설문조사에서 특히 문제가 되는 부분은 문자열 데이터를 수치형 데이터로 변환해주는 문제가 있다.
    • 이를 프로그래밍으로 해결하면 보다 쉽게 접근할 수 있다.
  • 이제 본격적으로 분석을 해보자.