Data Transformation

텍스트 마이닝 - Bag of Words

공지

  • 해당 포스트는 취업 준비반 대상 강의 교재로 파이썬 머신러닝 완벽가이드를 축약한 내용입니다.
    • 매우 좋은 책이니 가급적 구매하시기를 바랍니다.

I. 개요

  • 문서가 가지는 모든 단어(Words)를 문맥이나 순서를 무시하고 일괄적으로 단어에 대해 빈도 값을 부여하여 피처 값을 추출하는 모델을 말한다.
  • 아래와 같은 세 개의 문장이 있다고 가정해본다.
    • Doc 1: I love dogs.
    • Doc 2: I hate dogs and knitting.
    • Doc 3: Knitting is my hobby and passion.
  • 위 문장을 각각의 행렬로 표현하면 아래와 같다.
  • BOW 모델의 장점은 쉽고 빠른 구축에 있기 때문에, 활용도는 높은 편이지만, BOW 기반의 NLP 연구는 잘 되지 않는다.
    • 문맥 의미 부족
    • 희소 행렬 문제, 위 그림에서 공백은 0을 의미하며, 이는 문장이 많으면 많을 수록 0의 값도 계속 늘어나는데, 이를 해결하기 위해 COO(Coordinate) 또는 CSR(Compressed Sparse Row)형식의 기법을 활용한다.

II. BOW 피처 벡터화

  • 피처 벡터화는 간단하게 말하면 문서 내 텍스트를 단어의 횟수나 정규화된 빈도 값으로 데이터 세트 모델로 변경하는 것을 말한다.
  • 보통 문서를 M이라고 하고, 단어를 N이라고 한다면, 행렬은 전체 문서의 개수 (M) X 전체 단어의 개수(N)으로 구성한다.
  • 일반적으로 BOW의 피처 벡터화는 두 가지 방식이 존재한다.
    • 카운트 기반의 벡터화
    • TF-IDF(Term Frequency - Inverse Document Prequency) 기반의 벡터화

(1) 카운트 기반의 벡터화

  • 단어 피처에 값을 부여하는 경우를 말한다. 간단한 예시를 활용한다.
from collections import Counter
import nltk
from nltk import word_tokenize
nltk.download('punkt')

# 텍스트
text = """Yesterday I went fishing. I don't fish that often, 
so I didn't catch any fish. I was told I'd enjoy myself, 
but it didn't really seem that fun."""

# 토큰화
tokens = word_tokenize(text)

# 모든 단어를 소문자화
lower_tokens = [t.lower() for t in tokens]

# Counter화
bow_simple = Counter(lower_tokens)

# 상위 10개의 단어 추출
print(bow_simple.most_common(10))
[nltk_data] Downloading package punkt to /root/nltk_data...
[nltk_data]   Unzipping tokenizers/punkt.zip.
[('i', 5), ('.', 3), ("n't", 3), ('fish', 2), ('that', 2), (',', 2), ('did', 2), ('yesterday', 1), ('went', 1), ('fishing', 1)]
  • 단어 피처에 값을 부여할 때 각 문서에서 해당 언어가 나타나는 횟수, 즉 Count를 부여하는 경우를 카운트 벡터화라고 한다.

텍스트 마이닝 - 텍스트 전처리

I. 개요

  • NLP(Natural Language Processing): 기계가 인간의 언어를 이해하고 해석하는 데 중점
    • 활용예제: 기계 번역, 챗봇, 질의응답 시스템 (딥러닝)
  • Text Analysis: 비정형 텍스트에서 의미 있는 정보를 추출하는 것에 중점
    • 활용예제: 비즈니스 인텔리전스, 예측분석 (머신러닝)
  • 텍스트 분석의 예
    • 텍스트 분류: 문서가 특정 분류 또는 카테고리에 속하는 것을 예측하는 기법
    • 감성 분석: 텍스트에서 나타나는 감정/판단/믿음/의견 등의 주관적인 요소 분석하는 기법
    • 텍스트 요약: 텍스트 내에서의 중요한 주제나 중심 사상 추출(Topic Modeling)
    • 텍스트 군집화(Clustering)와 유사도 측정: 비슷한 유형의 문서에 대해 군집화를 수행하는 기법. 텍스트 분류를 비지도학습으로 수행하는 방법

II. 텍스트 분석 개요

  • 텍스트를 의미있는 숫자로 표현하는 것이 핵심
  • 영어 키워드: Feature Vectorization 또는 Feature Extraction.
  • 텍스트를 Feature Vectorization에는 BOW(Bag of Words)와 Word2Vec 두가지 방법이 존재.
  • 머신러닝을 수행하기 전에 반드시 선행되어야 함.

(1) 텍스트 분석 수행 방법

  • 1단계: 데이터 전처리 수행. 클렌징, 대/소문자 변경, 특수문자 삭제. 단어 등의 토큰화 작업, 의미 없는 단어(Stop word) 제거 작업, 어근 추출(Stemming/Lemmdatization)등의 텍스트 정규화 작업 필요
  • 2단계: 피처 벡터화/추출: 가공된 텍스트에서 피처 추출 및 벡터 값 할당.
    • Bag of Words: Count 기반 or TF-IDF 기반 벡터화
  • 3단계: ML 모델 수립 및 학습/예측/평가를 수행.

(2) 파이썬 기반의 NLP, 텍스트 분석 패키지

  • NTLK: 파이썬의 가장 대표적인 NLP 패키지. 방대한 데이터 세트와 서브 모듈 보유. 그러나, 속도가 느리다는 단점 존재
  • ‘Gensim’: 토픽 모델링 분야에서 주로 사용되는 패키지. Word2Vec 구현도 가능
  • SpaCY: 최근 가장 주목을 받는 NLP 패키지.

III. 텍스트 전처리 - 정규화

  • 텍스트 자체를 바로 피처로 만들 수는 없다. 텍스트를 가공하기 위한 클렌징, 토큰화, 어근화 등이 필요.
  • 정규화 작업의 종류는 다음과 같음
    • 클렌징: 불필요한 문자,기호 등을 사전제거 (정규표현식 주로 활용)
    • 토큰화
    • 필터링/스톱 워드 제거/철자 수정
    • Stemming
    • Lemmatization

(1) 문장 토큰화

  • 문장 토큰화(sentence tokenization)는 문장의 마침표, 개행문자(\n) 등 문장의 마지막을 뜻하는 기호에 따라 분리하는 것이 일반적임
  • 아래 샘플코드는 문장 토큰화에 관한 것임
  • punkt는 마침표, 개행 문자 등의 데이터 세트를 다운로드 받는다.
from nltk import sent_tokenize
import nltk

nltk.download("punkt")
[nltk_data] Downloading package punkt to /root/nltk_data...
[nltk_data]   Unzipping tokenizers/punkt.zip.





True
text_sample = "The Matrix is everywhere its all around us, here even in this wroom. \
               You can see it out your window or on your television. \
               You feel it when you go to work, or go to church or pay your taxes."

sentences = sent_tokenize(text = text_sample)
print(type(sentences), len(sentences))
print(sentences)
<class 'list'> 3
['The Matrix is everywhere its all around us, here even in this wroom.', 'You can see it out your window or on your television.', 'You feel it when you go to work, or go to church or pay your taxes.']
  • 위 코드에서 확인할 수 있는 것은 sent_tokenize가 반환하는 것은 각각의 문장으로 구성된 list 객체이며, 이 객체는 3개의 문장으로 된 문자열을 가지고 있음을 알 수 있다.

(2) 단어 토큰화

  • 단어 토큰화(Word Tokenization)는 문장을 단어로 토큰화하는 것을 말하며, 기본적으로 공백, 콤마(,), 마침표(.), 개행문자 등으로 단어를 분리하지만, 정규 표현식을 이용해 다양한 유형으로 토큰화를 수행할 수 있다.
  • 단어의 순서가 중요하지 않은 경우에는 Bag of Word를 사용해도 된다.
  • 이제 코드를 구현해본다.
from nltk import word_tokenize

sentence = "The Matrix is everywhere its all around us, here even in this room."
words = word_tokenize(sentence)
print(type(words), len(words))
print(words)
<class 'list'> 15
['The', 'Matrix', 'is', 'everywhere', 'its', 'all', 'around', 'us', ',', 'here', 'even', 'in', 'this', 'room', '.']
  • 이번에는 문장 및 단어 토큰화를 함수로 구현해보도록 한다.
    • 우선, 문장별로 토큰을 분리한 후
    • 분리된 문장별 단어를 토큰화로 진행하는 코드를 구현한다 (for loop 활용)
from nltk import word_tokenize, sent_tokenize

# 여러 개의 문장으로 된 입력 데이터를 문장별로 단어 토큰화하게 만드는 함수
def tokenize_text(text):

  # 문장별로 분리 토큰
  sentences = sent_tokenize(text)

  # 분리된 문장별 단어 토큰화
  word_tokens = [word_tokenize(sentence) for sentence in sentences]
  return word_tokens

# 여러 문장에 대해 문장별 단어 토큰화 수행
word_tokens = tokenize_text(text_sample)
print(type(word_tokens), len(word_tokens))
print(word_tokens)
<class 'list'> 3
[['The', 'Matrix', 'is', 'everywhere', 'its', 'all', 'around', 'us', ',', 'here', 'even', 'in', 'this', 'wroom', '.'], ['You', 'can', 'see', 'it', 'out', 'your', 'window', 'or', 'on', 'your', 'television', '.'], ['You', 'feel', 'it', 'when', 'you', 'go', 'to', 'work', ',', 'or', 'go', 'to', 'church', 'or', 'pay', 'your', 'taxes', '.']]
  • 각각의 개별 리스트는 해당 문장에 대한 토큰화된 단어를 요소로 가진다.
  • 문장을 단어별로 하나씩 토큰화 할 경우 문맥적인 의미는 무시될 수 밖에 없는데.. 이러한 문제를 해결하기 위해 도입된 개념이 n-gram이다.
  • N-gram은 연속된 N개의 단어를 하나의 토큰화 단위로 분리해 내는 것.
    • 예시) I Love You
    • (I, Love), (Love, You)

IV. 텍스트 전처리 - 스톱 워드(불용어) 제거

  • 의미가 없는 be동사 등을 제거 할 때 사용함
    • 이런 단어들은 매우 자주 나타나는 특징이 있음
  • NTLK의 스톱 워드에 기본적인 세팅이 저장되어 있음
import nltk
nltk.download("stopwords")
[nltk_data] Downloading package stopwords to /root/nltk_data...
[nltk_data]   Unzipping corpora/stopwords.zip.





True
  • 총 몇개의 stopwords가 있는지 알아보고, 그중 20개만 확인해본다.
print("영어 stop words 개수:", len(nltk.corpus.stopwords.words("english")))
print(nltk.corpus.stopwords.words("english")[:20])
영어 stop words 개수: 179
['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', "you're", "you've", "you'll", "you'd", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his']
  • 이번에는 stopwords를 필터링으로 제거하여 분석을 위한 의미 있는 단어만 추출하도록 함.
import nltk
stopwords = nltk.corpus.stopwords.words("english")
all_tokens = []

# 위 예제에서 3개의 문장별로 얻은 word_tokens list에 대해 불용어 제거하는 반복문 작성
for sentence in word_tokens:
  filtered_words = [] # 빈 리스트 생성

  # 개별 문장별로 토큰화된 문장 list에 대해 스톱 워드 제거
  for word in sentence:

    # 소문자로 모두 변환
    word = word.lower()

    # 토큰화된 개별 단어가 스톱 워드의 단어에 포함되지 않으면 word_tokens에 추가
    if word not in stopwords:
      filtered_words.append(word)
  all_tokens.append(filtered_words)
  
print(all_tokens)
[['matrix', 'everywhere', 'around', 'us', ',', 'even', 'wroom', '.'], ['see', 'window', 'television', '.'], ['feel', 'go', 'work', ',', 'go', 'church', 'pay', 'taxes', '.']]
  • is, this와 같은 불용어가 처리된 것 확인됨

V. 텍스트 전처리 - 어간(Stemming) 및 표제어(Lemmatization)

  • 동사의 변화
    • 예) Love, Loved, Loving
  • 어근 및 표제어는 단어의 원형을 찾는 것.
  • 그런데, 표제어 추출(Lemmatization)이 어근(Stemming)보다는 보다 더 의미론적인 기반에서 단어의 원형을 찾는다.

(1) 어간(Stemming)

  • Stemming은 원형 단어로 변환 시, 어미를 제거하는 방식을 사용한다.
    • 예) worked에서 ed를 제거하는 방식을 사용
  • Stemming기법에는 크게 Porter, Lancaster, Snowball Stemmer가 있음.
  • 소스코드 예시는 아래와 같음
from nltk.stem import PorterStemmer
from nltk.stem import LancasterStemmer
porter = PorterStemmer()
lancaster = LancasterStemmer()

word_list = ["friend", "friendship", "friends", "friendships","stabil","destabilize","misunderstanding","railroad","moonlight","football"]
print("{0:20}{1:20}{2:20}".format("Word","Porter Stemmer","lancaster Stemmer"))
for word in word_list:
    print("{0:20}{1:20}{2:20}".format(word,porter.stem(word),lancaster.stem(word)))
Word                Porter Stemmer      lancaster Stemmer   
friend              friend              friend              
friendship          friendship          friend              
friends             friend              friend              
friendships         friendship          friend              
stabil              stabil              stabl               
destabilize         destabil            dest                
misunderstanding    misunderstand       misunderstand       
railroad            railroad            railroad            
moonlight           moonlight           moonlight           
football            footbal             footbal             
  • LancasterStemmer 간단하지만, 가끔 지나치게 over-stemming을 하는 경향이 있다. 이는 문맥적으로는 큰 의미가 없을수도 있기 때문에 주의를 요망한다.
print("For Lancaster:", lancaster.stem("destabilized"))
print("For Porter:", porter.stem("destabilized"))
For Lancaster: dest
For Porter: destabil
  • 위와 같이 destabilized(불안정한) 뜻을 가진 단어가 destabil(불안정)이 아닌 dest(목적지)로 변환되기도 한다.

(2) 표제어 추출(Lemmatization)

  • 표제어 추출은 품사와 같은 문법적인 요소와 더 의미적인 부분을 감안하여 정확한 철자로 된 어근 단어를 찾아준다.
  • 어근을 보통 Lemma라고 부르며, 이 때의 어근은 Canoical Form, Dictionary Form, Citation Form 이라고 부른다.
  • 간단하게 예를 들면, loves, loving, loved는 모두 love에서 파생된 것이며, 이 때 loveLemma라고 부른다.
from nltk.stem import WordNetLemmatizer
import nltk
nltk.download('wordnet')
[nltk_data] Downloading package wordnet to /root/nltk_data...
[nltk_data]   Package wordnet is already up-to-date!





True
  • 간단하게 단어들을 확인해본다.
lemma = WordNetLemmatizer()
print(lemma.lemmatize('amusing', 'v'), lemma.lemmatize('amuses', 'v'), lemma.lemmatize('amused', 'v'))
print(lemma.lemmatize('happier', 'v'), lemma.lemmatize('happiest', 'v'))
print(lemma.lemmatize('fancier', 'a'), lemma.lemmatize('fanciest', 'a'))
amuse amuse amuse
happier happiest
fancy fancy
  • 이번에는 조금 긴 문장을 활용하여 작성하도록 한다.
import nltk
from nltk.stem import WordNetLemmatizer
wordnet_lemmatizer = WordNetLemmatizer()

sentence = "He was running and eating at same time. He has bad habit of swimming after playing long hours in the Sun."
punctuations="?:!.,;" # 해당되는 부호는 제외하는 코드를 만든다. 
sentence_words = nltk.word_tokenize(sentence)
for word in sentence_words:
    if word in punctuations:
        sentence_words.remove(word)

sentence_words
print("{0:20}{1:20}".format("Word","Lemma"))
for word in sentence_words:
    print ("{0:20}{1:20}".format(word,wordnet_lemmatizer.lemmatize(word)))
Word                Lemma               
He                  He                  
was                 wa                  
running             running             
and                 and                 
eating              eating              
at                  at                  
same                same                
time                time                
He                  He                  
has                 ha                  
bad                 bad                 
habit               habit               
of                  of                  
swimming            swimming            
after               after               
playing             playing             
long                long                
hours               hour                
in                  in                  
the                 the                 
Sun                 Sun                 
  • 지금까지 진행한 것은 텍스트 전처리의 일환으로 활용한 것이다. 각각의 정규화, 불용어, 어간 및 표제어 등은 각각 함수로 작성하는 것을 권한다.

VI. Reference

KDX Competition Guideline

개요

  • 본 수업을 듣는 수강생들을 위해 간단한 튜토리얼을 만들었다.
  • 대회는 다음과 같다.

/img/programming/2020/10/blog_kdx_guideline/img

1단계 패키지 불러오기

  • 데이터 가공 및 시각화 위주의 패키지를 불러온다.
library(tidyverse) # 데이터 가공 및 시각화
library(readxl) # 엑셀파일 불러오기 패키지 

2단계 데이터 불러오기

  • 데이터가 많아서 순차적으로 진행하도록 한다.
  • 각 데이터에 대한 설명은활용데이터설명(PDF)을 참조한다.

  • 먼저 제 개발환경은 아래와 같다.
    • Note: 윈도우와 Mac은 다를 수 있음을 명심하자.
sessionInfo()
## R version 4.0.2 (2020-06-22)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Catalina 10.15.6
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] readxl_1.3.1    forcats_0.5.0   stringr_1.4.0   dplyr_1.0.0    
##  [5] purrr_0.3.4     readr_1.3.1     tidyr_1.1.0     tibble_3.0.3   
##  [9] ggplot2_3.3.2   tidyverse_1.3.0
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.5       cellranger_1.1.0 pillar_1.4.6     compiler_4.0.2  
##  [5] dbplyr_1.4.4     tools_4.0.2      digest_0.6.25    lubridate_1.7.9 
##  [9] jsonlite_1.7.0   evaluate_0.14    lifecycle_0.2.0  gtable_0.3.0    
## [13] pkgconfig_2.0.3  rlang_0.4.7      reprex_0.3.0     cli_2.0.2       
## [17] rstudioapi_0.11  DBI_1.1.0        yaml_2.2.1       haven_2.3.1     
## [21] xfun_0.16        withr_2.3.0      xml2_1.3.2       httr_1.4.2      
## [25] knitr_1.29       fs_1.5.0         hms_0.5.3        generics_0.0.2  
## [29] vctrs_0.3.2      grid_4.0.2       tidyselect_1.1.0 glue_1.4.1      
## [33] R6_2.4.1         fansi_0.4.1      rmarkdown_2.3    modelr_0.1.8    
## [37] blob_1.2.1       magrittr_1.5     backports_1.1.8  scales_1.1.1    
## [41] ellipsis_0.3.1   htmltools_0.5.0  rvest_0.3.6      assertthat_0.2.1
## [45] colorspace_1.4-1 stringi_1.4.6    munsell_0.5.0    broom_0.7.0     
## [49] crayon_1.3.4

(1) 삼성카드 데이터

  • 우선 삼성카드 데이터를 불러와서 확인한다.
  • 한글 파일은 인코딩이 늘 항상 문제다.
    • 파일을 불러오기 전 항상 파일 인코딩을 확인하도록 한다.
readr::guess_encoding("data/Samsungcard.csv", n_max = 100)
## # A tibble: 2 x 2
##   encoding confidence
##   <chr>         <dbl>
## 1 EUC-KR         1   
## 2 GB18030        0.62
  • Encoding 확인 결과 EUC-KR로 확인하였다.
samsung_card <- read_xlsx("data/Samsungcard.xlsx")
samsung_card2 <- read.csv("data/Samsungcard.csv", fileEncoding = "EUC-KR")
  • 위 두 파일이 동일한 것을 확인해본다
head(samsung_card)
## # A tibble: 6 x 5
##   소비일자 소비업종  성별  연령대 소비건수
##      <dbl> <chr>     <chr> <chr>     <dbl>
## 1 20190101 가전/가구 남성  20대       5529
## 2 20190101 가전/가구 남성  30대      17536
## 3 20190101 가전/가구 남성  40대      22838
## 4 20190101 가전/가구 남성  50대      15801
## 5 20190101 가전/가구 남성  60대       6772
## 6 20190101 가전/가구 여성  20대       5937
head(samsung_card2)
##   소비일자  소비업종 성별 연령대 소비건수
## 1 20190101 가전/가구 남성   20대     5529
## 2 20190101 가전/가구 남성   30대    17536
## 3 20190101 가전/가구 남성   40대    22838
## 4 20190101 가전/가구 남성   50대    15801
## 5 20190101 가전/가구 남성   60대     6772
## 6 20190101 가전/가구 여성   20대     5937
  • 두 파일이 동일한 것을 확인하였다면 이제 samsung_card2는 삭제를 한다.
    • RAM을 아껴 쓰자.
rm(samsung_card2) # 객체 지우는 함수
ls() # 현재 저장된 객체 확인하는 함수
## [1] "samsung_card"

(2) 신한카드 데이터

  • 이번에는 ShinhanCard.xslx 데이터를 불러온다.
shinhancard <- read_xlsx("data/Shinhancard.xlsx")
head(shinhancard)
## # A tibble: 6 x 8
##   일별    성별  연령대별 업종               `카드이용건수(천건)`… ...6  ...7   ...8
##   <chr>   <chr> <chr>    <chr>                           <dbl> <lgl> <lgl> <dbl>
## 1 201901… F     20대     M001_한식                       299.  NA    NA       10
## 2 201901… F     20대     M002_일식/중식/양식…               88.3 NA    NA       NA
## 3 201901… F     20대     M003_제과/커피/패스트푸드…              291.  NA    NA       NA
## 4 201901… F     20대     M004_기타요식                   446.  NA    NA       NA
## 5 201901… F     20대     M005_유흥                        24.2 NA    NA       NA
## 6 201901… F     20대     M006_백화점                      35.3 NA    NA       NA
  • 위 데이터를 불러오니 불필요한 6:8 변수가 불러온 것을 확인할 수 있다.
    • 실제 엑셀 데이터를 열어도 빈값임을 확인할 수 있다.
    • 따라서, 6:8 변수는 삭제한다.
shinhancard <- shinhancard %>% 
  select(-c(6:8))

head(shinhancard)
## # A tibble: 6 x 5
##   일별     성별  연령대별 업종                      `카드이용건수(천건)`
##   <chr>    <chr> <chr>    <chr>                                    <dbl>
## 1 20190101 F     20대     M001_한식                                299. 
## 2 20190101 F     20대     M002_일식/중식/양식                       88.3
## 3 20190101 F     20대     M003_제과/커피/패스트푸드                291. 
## 4 20190101 F     20대     M004_기타요식                            446. 
## 5 20190101 F     20대     M005_유흥                                 24.2
## 6 20190101 F     20대     M006_백화점                               35.3

(3) 지인플러스

  • 지인플러스는 아파트시세(GIN00009A)와 아파트 거래량(GIN00008B)을 담은 코드이다.
gin_8a <- read_csv("data/GIN00008A.csv")
gin_9a <- read_csv("data/GIN00009A.csv")
  • 위 두개의 데이터를 확인해본다.
glimpse(gin_8a)
## Rows: 937,904
## Columns: 9
## $ ym             <dbl> 200601, 200602, 200603, 200604, 200605, 200606, 200607…
## $ area_lvl_scor  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ lgdng_cd       <chr> "0000000000", "0000000000", "0000000000", "0000000000"…
## $ trd_cont       <dbl> 23357, 38617, 52241, 44253, 41916, 30257, 28613, 37362…
## $ avg_trd_cont   <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ trd_deal_rat   <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ mtrnt_cont     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ avg_mtrnt_cont <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ mtrnt_deal_rat <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
glimpse(gin_9a)
## Rows: 785,805
## Columns: 4
## $ lgdng_cd <dbl> 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+09, 1.1e+0…
## $ std_date <date> 2006-01-21, 2006-02-21, 2006-03-21, 2006-04-21, 2006-05-21,…
## $ trd_prc  <dbl> 1289, 1271, 1291, 1307, 1321, 1335, 1357, 1381, 1411, 1444, …
## $ ldpb_prc <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …

(4) JSON 파일 불러오기

  • JSON 파일 불러올 때에는 jsonlite 패키지를 활용한다.
library(jsonlite)
GIN_10m <- fromJSON("data/center_GIN00010M.json")
glimpse(GIN_10m)
## Rows: 20,572
## Columns: 8
## $ AREA_LVL_SCOR <int> 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3…
## $ LGDNG_CD      <chr> "1100000000", "1111000000", "1111010100", "1111010200",…
## $ CTPV_NM       <chr> "서울특별시", "서울특별시", "서울특별시", "서울특별시", "서울특별시", "서울특별시", "…
## $ CTGG_NM       <chr> NA, "종로구", "종로구", "종로구", "종로구", "종로구", "종로구", "종로구", "종…
## $ EMD_NM        <chr> NA, NA, "청운동", "신교동", "궁정동", "효자동", "창성동", "통의동", "적선동"…
## $ LA            <dbl> 37.52934, 37.58586, 37.58920, 37.58449, 37.58468, 37.58…
## $ LNGT          <dbl> 126.9515, 126.9775, 126.9693, 126.9679, 126.9731, 126.9…
## $ PYN_CN        <chr> "{\"type\": \"Polygon\", \"coordinates\": [[[126.979658…
  • PYN_CN의 값이 조금 다른 것을 확인할 수 있다.
    • 이 부분은 추후 전처리할 때 정리하는 것으로 확인한다.

(5) SSC_Data

  • 이번에는 Mcorporation내 폴더 데이터를 올리도록 한다.
  • 이번에 파일을 불러올 때는 readr::read_csv()를 활용하여 불러온다.
readr::guess_encoding("data/Mcorporation/KDX시각화경진대회_SSC_DATA.csv")
## # A tibble: 2 x 2
##   encoding confidence
##   <chr>         <dbl>
## 1 EUC-KR         1   
## 2 GB18030        0.76
ssc_data <- read_csv("data/Mcorporation/KDX시각화경진대회_SSC_DATA.csv", locale = locale("ko", encoding = "EUC-KR"))
glimpse(ssc_data)
## Rows: 76,580
## Columns: 5
## $ 소비일자 <dbl> 20190101, 20190101, 20190101, 20190101, 20190101, 20190101, 2019…
## $ 소비업종 <chr> "가전/가구", "가전/가구", "가전/가구", "가전/가구", "가전/가구", "가전/가구", "가전/가구", "…
## $ 성별     <chr> "남성", "남성", "남성", "남성", "남성", "여성", "여성", "여성", "여성", "여성", "남…
## $ 연령대   <chr> "20대", "30대", "40대", "50대", "60대", "20대", "30대", "40대", "50대", …
## $ 소비건수 <dbl> 5529, 17536, 22838, 15801, 6772, 5937, 12895, 16896, 14025, 5909…

(6) 다중 엑셀파일 불러오기 예제

  • 상품 카데고리 데이터_KDX 시각화 폴더 내 엑셀 데이터를 확인해본다.
list.files(path = "data/Mcorporation/상품 카테고리 데이터_KDX 시각화 경진대회 Only/")
##  [1] "PC사무기기.xlsx"             "TV홈시어터.xlsx"            
##  [3] "가공식품.xlsx"               "가방지갑잡화.xlsx"          
##  [5] "건강관련용품.xlsx"           "건강식품.xlsx"              
##  [7] "계절가전.xlsx"               "골프용품.xlsx"              
##  [9] "공구류.xlsx"                 "구기.xlsx"                  
## [11] "국내외여행.xlsx"             "기타 스포츠.xlsx"           
## [13] "낚시.xlsx"                   "남성의류.xlsx"              
## [15] "노트북.xlsx"                 "농축수산물.xlsx"            
## [17] "도서음반DVD.xlsx"            "등산용품.xlsx"              
## [19] "메이크업.xlsx"               "문구사무용품.xlsx"          
## [21] "미용가전.xlsx"               "반려동물.xlsx"              
## [23] "생활가구.xlsx"               "생활가전.xlsx"              
## [25] "생활용품.xlsx"               "서비스티켓.xlsx"            
## [27] "성인용품.xlsx"               "세탁청소세면.xlsx"          
## [29] "수납가구.xlsx"               "수납용품.xlsx"              
## [31] "수영.xlsx"                   "스키보드.xlsx"              
## [33] "스킨케어.xlsx"               "스포츠의류.xlsx"            
## [35] "신발.xlsx"                   "악세서리시계주얼리.xlsx"    
## [37] "안전용품.xlsx"               "언더웨어.xlsx"              
## [39] "업소위생용품.xlsx"           "여성의류.xlsx"              
## [41] "완구키덜트게임.xlsx"         "욕실가전.xlsx"              
## [43] "욕실용품.xlsx"               "유아용품.xlsx"              
## [45] "유아패션.xlsx"               "음료.xlsx"                  
## [47] "음향가전.xlsx"               "인테리어용품.xlsx"          
## [49] "자동차용품.xlsx"             "자전거사이클보드인라인.xlsx"
## [51] "주방가전.xlsx"               "주방수납잡화.xlsx"          
## [53] "주방식기용기.xlsx"           "주방조리기구.xlsx"          
## [55] "출산임부용품.xlsx"           "취미악기.xlsx"              
## [57] "침실가구.xlsx"               "침실인테리어.xlsx"          
## [59] "카메라캠코더.xlsx"           "캠핑용품.xlsx"              
## [61] "테마의류.xlsx"               "헤어바디용품.xlsx"          
## [63] "헬스기구용품.xlsx"           "휴대폰악세서리.xlsx"
  • 몇가지 파일을 열어본다.
  • 엑셀 데이터의 변수 등이 동일한 것을 확인할 수 있다.
  • 이제 위 데이터를 한꺼번에 불러와서 하나의 데이터셋으로 합친다.
  • 검색키워드 Multiple Excel Files import in R
files <- list.files(path = "data/Mcorporation/상품 카테고리 데이터_KDX 시각화 경진대회 Only/", pattern = "*.xlsx", full.names = T)

products <- sapply(files, read_excel, simplify=FALSE) %>% 
  bind_rows(.id = "id") %>% 
  select(-id)

glimpse(products)
## Rows: 1,837,833
## Columns: 7
## $ 구매날짜   <dbl> 20190101, 20190101, 20190101, 20190101, 20190101, 20190101, 20…
## $ 카테고리명 <chr> "PC/사무기기", "PC/사무기기", "PC/사무기기", "PC/사무기기", "PC/사무기기", "PC/사무기기…
## $ 고객성별   <chr> "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F", "F…
## $ 고객나이   <dbl> 10, 10, 10, 10, 20, 20, 20, 20, 30, 30, 30, 30, 40, 40, 40, 40…
## $ OS유형     <chr> "IOS", "WINDOWS", "안드로이드", "없음", "IOS", "WINDOWS", "안드로이드", …
## $ 구매금액   <dbl> 352443, 84000, 80870, 3700, 27714776, 11414514, 21223319, 4832…
## $ 구매수     <dbl> 13, 1, 8, 1, 381, 60, 252, 41, 240, 75, 423, 19, 58, 110, 436…

3단계 데이터 시각화

  • 먼저, 데이터 저장 용량을 고려하여 products 데이터셋을 제외하고 나머지는 모두 삭제한다.
  • 데이터 시각화는 변수의 종류에 따른 시각화를 구현한 것이다.
  • 시각화 참조자료는 다음에서 작성이 가능하다.
  • 아래 샘플은 필자가 공부하는 형태를 구현한 것이다. 참조하기를 바란다.

(1) 수치형 변수 ~ 수치형 변수

  • 수치형 변수 ~ 수치형 변수 시각화의 대표적인 기법은 산점도(scatter) 또는 correlation이라 부른다.
    • scatter 시각화를 구현한다.
# load package and data
library(ggplot2)
data(mpg, package="ggplot2")
# mpg <- read.csv("http://goo.gl/uEeRGu")

# Scatterplot
theme_set(theme_bw())  # pre-set the bw theme.
g <- ggplot(mpg, aes(cty, hwy))
g + geom_count(col="tomato3", show.legend=F) +
  labs(subtitle="mpg: city vs highway mileage", 
       y="hwy", 
       x="cty", 
       title="Counts Plot")

삼성카드 대회 Track-2 - matplotlib 막대 그래프

대회 소개

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

환경 세팅

  • 먼저, 데이터가 모두 한글로 구성이 되어 있기 때문에 한글파일 설정부터 진행한다.
  • 한글파일 설정이 완료되면 구글 드라이브와 연동한다.
  • 데이터 시각화를 진행한다.
%config InlineBackend.figure_format = 'retina'
!sudo apt-get -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
fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumBarunGothic') 
plt.rcParams["figure.figsize"] = (20, 10)
mpl.font_manager._rebuild()
mpl.pyplot.rc('font', family='NanumGothic')
fm._rebuild()
  • 여기까지 실행하였으면 구글 코랩에서 런타임-런타임 다시 시작을 클릭한다.

구글 드라이브 연동

  • 이제 구글 드라이브를 연동한다.
# 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/samsung/datasets'

PROJECT_PATH = join(ROOT, MY_GOOGLE_DRIVE_PATH)
print(PROJECT_PATH)
/content/drive/My Drive/Colab Notebooks/samsung/datasets
%cd "{PROJECT_PATH}"
/content/drive/My Drive/Colab Notebooks/samsung/datasets
%ls
'[기타] SCDC_공모전 테이블 설명.xlsx'  '[Track1_데이터4] variable_dtype.xlsx'
'[Track1_데이터1] mrc_info.csv'        '[Track2_데이터1] trend_w_demo.csv'
'[Track1_데이터2] samp_train.csv'      '[Track2_데이터2] 업종_예시.xlsx'
'[Track1_데이터3] samp_cst_feat.csv'

데이터 불러오기

  • 패키지를 불러오기 위해 pandas 패키지를 활용하여 [Track2_데이터1] 데이터를 불러온다.
  • 파일을 불러 올 때, encoding="EUC-KR"를 설정해서 가져온다.
import pandas as pd

trend_w_demo = pd.read_csv('[Track2_데이터1] trend_w_demo.csv', encoding="EUC-KR")
trend_w_demo.head()
YM Category 성별구분 연령대 기혼스코어 유아자녀스코어 초등학생자녀스코어 중고생자녀스코어 대학생자녀스코어 전업주부스코어
0 202005 할인점 0 F high low high mid low low
1 202005 취미 0 B high low mid mid low low
2 202005 오픈마켓/소셜 1 D mid mid mid mid low mid
3 202005 뷰티 0 D mid mid mid mid low low
4 202005 오픈마켓/소셜 0 G high low mid mid mid low
trend_w_demo['기혼스코어'].value_counts()
high    314088
mid     107368
low      30582
Name: 기혼스코어, dtype: int64
  • 위 데이터는 전형적으로 범주형으로 구성이 되어 있다.
  • 위 변수에서 고려할 것이 있다.
    • Category, 성별구분, 연령대는 명목형 변수인데 반해
    • 기혼스코어:전업주부스코어의 경우는 확률이다.
  • 각 스코어의 확률에 대한 정의는 다음과 같다.
    • 기혼스코어 : 카드 이용 고객이 기혼일 확률
    • 유아자녀스코어 : 카드 이용 고객이에게 유아자녀가 있을 확률
    • 초등학생자녀스코어 : 카드 이용 고객이에게 초등학생 자녀가 있을 확률
    • 중고생자녀스코어 : 카드 이용 고객이에게 중고생 자녀가 있을 확률
    • 대학생자녀스코어 : 카드 이용 고객이에게 대학생 자녀가 있을 확률
    • 전업주부스코어 : 카드 이용 고객이 전업주부일 확률
  • 위 스코어의 데이터는 단순히 명목형이라고 보기는 어렵다. 즉, 순위(서열)형 척도/등간척도로 봐야 할 것이다.

측정척도의 유형과 내용

  • 명목척도: 범주형 데이터로 측정된 측정대상을 단순히 범주로 분류하기 위한 목적으로 숫자를 부여한 척도(수학적 가감승제 계산 안 됨)
    • 예시 - 성별, 종교, 직업, 혈액형
  • 순위(서열)척도: 범주형 데이터로 명목척도의 기능뿐 아니라 각 범주 간의 대소관계, 순위(서열성)에 관하여 숫자를 부여한 척도(수학적 가감승제 계산 안 됨)
    • 예시 - 학력, 건강상태 등
  • 등간척도: 연속형 데이터로 절대적 영점(absoulute zero)이 없으며 대상이 갖는 양적인 정도의 차이에 따라 등간격으로 숫자를 부여한 척도(수학적 가감승제 계산 안 됨)
    • 예시 - 온도, 만족도(리커트척도), 충성도(리커트척도), 물가지수, 생산지수 등
  • 비율척도: 연속형 데이터로 절대적 영점이 존재하며, 비율계산이 가능한 숫자를 부여한 척도(수학적 가감승제 계산 가능)
    • 매출액, 무게, 가격, 소득, 길이, 부피 등)

(1) 척도와 분석 간의 관계

  • 척도와 분석 간의 관계에 관한 표는 아래와 같다 (신건권, 2018).
독립변수 종속변수 분석방법
범주형 변수(명목, 서열) 범주형 변수(명목, 서열) 교차분석, 카이제곱
범주형 변수(명목, 서열) 연속형 변수(등간, 비율) t-검증, 분산분석, 다변량분산분석
연속형 변수(등간, 비율) 범주형 변수(명목, 서열) 판별분석, 군집분석, 로지스틱회귀분석
연속형 변수(등간, 비율) 연속형 변수(등간, 비율) 상관분석, 회귀분석, 경로분석/구조방정식모델링분석
  • 즉, 위 표를 기준으로 삼성카드를 매우 단순하게 본다면 교차분석 외에는 쓸만한 분석방법이 떠오르지 않는다.
  • 그러나, 연도, Category, 성별구분, 연령대를 제외하고는 나머지 변수들을 서열 또는 등간으로 본다면 조금 더 다양한 분석 방법이 생길 수 있다.

(2) 시각화 방법

  • 순위 및 서열척도를 다루는 데이터에 대한 시각화는 주로 다음과 같다.

(3) 모수 VS 비모수 통계

  • 통계 분석 방법은 매우 중요하다. 일종의 가이드라인이기 때문이다.
  • 모수 통계는 기본적으로 평균들의 차이를 파악해야 하기 때문에 연속형 자료형이 필요하다. 또한, 이러한 자료는 대개 정규분포라는 형태로 잘 포장되어야 하지만, 실상은 그렇지 않다.
  • 이러한 경우 비모수적 검정을 실시한다.
    • 비모수적 검정의 기본 조건은 모수 통계를 할 수 없는 상황이 생기면, 보다 완화된 조건으로 해석하는 것이 옳은 방법이다. (가정을 무시하는 것은 아니다!)
  • 비모수 검정에는 크게 윌콕슨 순위합 검정, 윌콕슨 부호순위 검정, 프리드먼 검정, 그리고 크러스컬-월리스 검정 등이 사용된다.
  • 정규성 검정에 따른 모수와 비모수 검정 방법은 다음과 같다.
  • T검정
    • 모수적 방법: 독립표본 T검정, 대응표본 T검정
    • 비모수적 방법: 윌콕슨(Wilcoxon) 검정, 맨-휘트니(Mann-Whitney) 검정
  • 분산분석
    • 모수적 방법: 일원 배치 분산분석
    • 비모수적 방법: 크루스칼-윌리스(Kruskal-Wallis)검정
  • 관계분석
    • 모수적 방법: 피어슨의 상관분석
    • 비모수적 방법: 스피어만의 로 상관분석
  • 삼성카드의 데이터는 일반적인 모수적 방법으로는 통계검정을 하기에는 어려움이 있다. 즉, 비모수 통계에 대한 기본적인 숙지가 필요하며, 파이썬에서 비모수 통계 소스코드 예제는 추후에 다시 정리한다.

범주형 데이터 시각화를 통한 EDA 보고서

  • 범주형 데이터 시각화를 진행한다.
  • matplotlib 모듈을 활용한다.

(1) Label이 있는 그룹 막대 그래프 (예제)

  • 막대그래프를 그린, 라벨링까지 적용해본다.
  • 먼저 공식 튜토리얼에 있는 것을 확인해본다.
import matplotlib
import matplotlib.pyplot as plt
import numpy as np


labels = ['G1', 'G2', 'G3', 'G4', 'G5']
men_means = [20, 34, 30, 35, 27]
women_means = [25, 32, 34, 20, 25]

x = np.arange(len(labels)) # x축 라벨의 위치를 말한다. 
y_labels = [0, 5, 10, 15, 20, 25, 30, 35] # y축 라벨의 위치를 말한다.
width = 0.35 # 막대의 너비를 말한다. 

fig, ax = plt.subplots() # 객체를 설정하는 것이다.
rects1 = ax.bar(x - width/2, men_means, width, label = "Men")
rects2 = ax.bar(x + width/2, women_means, width, label = "Women")

png

삼성카드 대회 Track-2 데이터 고려 사항 (1)

대회 소개

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

환경 세팅

  • 먼저, 데이터가 모두 한글로 구성이 되어 있기 때문에 한글파일 설정부터 진행한다.
  • 한글파일 설정이 완료되면 구글 드라이브와 연동한다.
  • 데이터 시각화를 진행한다.
%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) ...
from pandas.plotting import register_matplotlib_converters
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.font_manager as fm
fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'
font = fm.FontProperties(fname=fontpath, size=9)
plt.rc('font', family='NanumBarunGothic') 
plt.rcParams["figure.figsize"] = (20, 10)
register_matplotlib_converters()
mpl.font_manager._rebuild()
mpl.pyplot.rc('font', family='NanumGothic')
fm._rebuild()
  • 여기까지 실행하였으면 구글 코랩에서 런타임-런타임 다시 시작을 클릭한다.

구글 드라이브 연동

  • 이제 구글 드라이브를 연동한다.
# 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, force_remount=True)           # we mount the google drive at /content/drive
/content/drive
Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6qk8qdgf4n4g3pfee6491hc0brc4i.apps.googleusercontent.com&redirect_uri=urn%3aietf%3awg%3aoauth%3a2.0%3aoob&scope=email%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdocs.test%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive.photos.readonly%20https%3a%2f%2fwww.googleapis.com%2fauth%2fpeopleapi.readonly&response_type=code

Enter your authorization code:
··········
Mounted at /content/drive
# 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/samsung/datasets'

PROJECT_PATH = join(ROOT, MY_GOOGLE_DRIVE_PATH)
%cd "{PROJECT_PATH}"
/content/drive/My Drive/Colab Notebooks/samsung/datasets
%ls
'[기타] SCDC_공모전 테이블 설명.xlsx'  '[Track1_데이터4] variable_dtype.xlsx'
'[Track1_데이터1] mrc_info.csv'        '[Track2_데이터1] trend_w_demo.csv'
'[Track1_데이터2] samp_train.csv'      '[Track2_데이터2] 업종_예시.xlsx'
'[Track1_데이터3] samp_cst_feat.csv'

데이터 불러오기

  • 패키지를 불러오기 위해 pandas 패키지를 활용하여 [Track2_데이터1] 데이터를 불러온다.
  • 파일을 불러 올 때, encoding="EUC-KR"를 설정해서 가져온다.
import pandas as pd

trend_w_demo = pd.read_csv('[Track2_데이터1] trend_w_demo.csv', encoding="EUC-KR")
trend_w_demo.head()
YM Category 성별구분 연령대 기혼스코어 유아자녀스코어 초등학생자녀스코어 중고생자녀스코어 대학생자녀스코어 전업주부스코어
0 202005 할인점 0 F high low high mid low low
1 202005 취미 0 B high low mid mid low low
2 202005 오픈마켓/소셜 1 D mid mid mid mid low mid
3 202005 뷰티 0 D mid mid mid mid low low
4 202005 오픈마켓/소셜 0 G high low mid mid mid low
trend_w_demo['기혼스코어'].value_counts()
high    314088
mid     107368
low      30582
Name: 기혼스코어, dtype: int64
  • 위 데이터는 전형적으로 범주형으로 구성이 되어 있다.
  • 위 변수에서 고려할 것이 있다.
    • Category, 성별구분, 연령대는 명목형 변수인데 반해
    • 기혼스코어:전업주부스코어의 경우는 확률이다.
  • 각 스코어의 확률에 대한 정의는 다음과 같다.
    • 기혼스코어 : 카드 이용 고객이 기혼일 확률
    • 유아자녀스코어 : 카드 이용 고객이에게 유아자녀가 있을 확률
    • 초등학생자녀스코어 : 카드 이용 고객이에게 초등학생 자녀가 있을 확률
    • 중고생자녀스코어 : 카드 이용 고객이에게 중고생 자녀가 있을 확률
    • 대학생자녀스코어 : 카드 이용 고객이에게 대학생 자녀가 있을 확률
    • 전업주부스코어 : 카드 이용 고객이 전업주부일 확률
  • 위 스코어의 데이터는 단순히 명목형이라고 보기는 어렵다. 즉, 순위(서열)형 척도/등간척도로 봐야 할 것이다.

측정척도의 유형과 내용

  • 명목척도: 범주형 데이터로 측정된 측정대상을 단순히 범주로 분류하기 위한 목적으로 숫자를 부여한 척도(수학적 가감승제 계산 안 됨)
    • 예시 - 성별, 종교, 직업, 혈액형
  • 순위(서열)척도: 범주형 데이터로 명목척도의 기능뿐 아니라 각 범주 간의 대소관계, 순위(서열성)에 관하여 숫자를 부여한 척도(수학적 가감승제 계산 안 됨)
    • 예시 - 학력, 건강상태 등
  • 등간척도: 연속형 데이터로 절대적 영점(absoulute zero)이 없으며 대상이 갖는 양적인 정도의 차이에 따라 등간격으로 숫자를 부여한 척도(수학적 가감승제 계산 안 됨)
    • 예시 - 온도, 만족도(리커트척도), 충성도(리커트척도), 물가지수, 생산지수 등
  • 비율척도: 연속형 데이터로 절대적 영점이 존재하며, 비율계산이 가능한 숫자를 부여한 척도(수학적 가감승제 계산 가능)
    • 매출액, 무게, 가격, 소득, 길이, 부피 등)

(1) 척도와 분석 간의 관계

  • 척도와 분석 간의 관계에 관한 표는 아래와 같다 (신건권, 2018).
독립변수 종속변수 분석방법
범주형 변수(명목, 서열) 범주형 변수(명목, 서열) 교차분석, 카이제곱
범주형 변수(명목, 서열) 연속형 변수(등간, 비율) t-검증, 분산분석, 다변량분산분석
연속형 변수(등간, 비율) 범주형 변수(명목, 서열) 판별분석, 군집분석, 로지스틱회귀분석
연속형 변수(등간, 비율) 연속형 변수(등간, 비율) 상관분석, 회귀분석, 경로분석/구조방정식모델링분석
  • 즉, 위 표를 기준으로 삼성카드를 매우 단순하게 본다면 교차분석 외에는 쓸만한 분석방법이 떠오르지 않는다.
  • 그러나, 연도, Category, 성별구분, 연령대를 제외하고는 나머지 변수들을 서열 또는 등간으로 본다면 조금 더 다양한 분석 방법이 생길 수 있다.

(2) 시각화 방법

  • 순위 및 서열척도를 다루는 데이터에 대한 시각화는 주로 다음과 같다.

(3) 모수 VS 비모수 통계

  • 통계 분석 방법은 매우 중요하다. 일종의 가이드라인이기 때문이다.
  • 모수 통계는 기본적으로 평균들의 차이를 파악해야 하기 때문에 연속형 자료형이 필요하다. 또한, 이러한 자료는 대개 정규분포라는 형태로 잘 포장되어야 하지만, 실상은 그렇지 않다.
  • 이러한 경우 비모수적 검정을 실시한다.
    • 비모수적 검정의 기본 조건은 모수 통계를 할 수 없는 상황이 생기면, 보다 완화된 조건으로 해석하는 것이 옳은 방법이다. (가정을 무시하는 것은 아니다!)
  • 비모수 검정에는 크게 윌콕슨 순위합 검정, 윌콕슨 부호순위 검정, 프리드먼 검정, 그리고 크러스컬-월리스 검정 등이 사용된다.
  • 정규성 검정에 따른 모수와 비모수 검정 방법은 다음과 같다.
  • T검정
    • 모수적 방법: 독립표본 T검정, 대응표본 T검정
    • 비모수적 방법: 윌콕슨(Wilcoxon) 검정, 맨-휘트니(Mann-Whitney) 검정
  • 분산분석
    • 모수적 방법: 일원 배치 분산분석
    • 비모수적 방법: 크루스칼-윌리스(Kruskal-Wallis)검정
  • 관계분석
    • 모수적 방법: 피어슨의 상관분석
    • 비모수적 방법: 스피어만의 로 상관분석
  • 삼성카드의 데이터는 일반적인 모수적 방법으로는 통계검정을 하기에는 어려움이 있다. 즉, 비모수 통계에 대한 기본적인 숙지가 필요하며, 파이썬에서 비모수 통계 소스코드 예제는 추후에 다시 정리한다.

Reference

DataFrame의 변수 추가 및 삭제

강의 홍보

데이터 개요

  • German Credit Card를 활용하여 데이터를 가공하도록 한다.
    • 데이터셋에 대한 설명은 Kaggle에서 확인한다.
import pandas as pd
print(pd.__version__)
1.0.5
url = 'https://raw.githubusercontent.com/chloevan/kaggle2portpolio/master/datasets/german_credit_data.csv'
german_credit = pd.read_csv(url)
german_credit.head(3)
Unnamed: 0 Age Sex Job Housing Saving accounts Checking account Credit amount Duration Purpose
0 0 67 male 2 own NaN little 1169 6 radio/TV
1 1 22 female 2 own little moderate 5951 48 radio/TV
2 2 49 male 1 own little NaN 2096 12 education
  • Pandas DataFrameIndex와 나머지 열로 구성이 되어 있다.
  • 데이터의 행과 크기를 알아보는 가장 좋은 방법은 DataFrame객체의 shape변수를 이용하는 것이다.
print('DataFrame 크기: ', german_credit.shape)
DataFrame 크기:  (1000, 10)
  • 생성된 DataFrame 객체인 german_credit은 10개의 칼럼으로 이루어져 있다.
  • 이번에는 describe() 함수를 활용하여 개략적인 분포도를 확인한다.
german_credit.describe()
Unnamed: 0 Age Job Credit amount Duration
count 1000.000000 1000.000000 1000.000000 1000.000000 1000.000000
mean 499.500000 35.546000 1.904000 3271.258000 20.903000
std 288.819436 11.375469 0.653614 2822.736876 12.058814
min 0.000000 19.000000 0.000000 250.000000 4.000000
25% 249.750000 27.000000 2.000000 1365.500000 12.000000
50% 499.500000 33.000000 2.000000 2319.500000 18.000000
75% 749.250000 42.000000 2.000000 3972.250000 24.000000
max 999.000000 75.000000 3.000000 18424.000000 72.000000
german_credit['Sex'].value_counts()
male      690
female    310
Name: Sex, dtype: int64
  • Sex의 반환 결과는 1이 700개, 0이 300개로 확인할 수 있다.
  • 이 때 value_counts()는 많은 건수 순서로 정렬되어 값을 반환한다.

새로운 변수 추가

  • 기존 데이터에서 변수를 추가하고 삭제하는 것을 진행해본다.
  • 이러한 과정을 보통 도출변수로 표현되기도 한다.
german_credit['Age+100'] = german_credit['Age'] + 100
german_credit.shape
(1000, 11)

(1) 수치형 조건에 따른 변수 추가

  • 수치형 변수의 특성에 따라 새로운 변수를 추가한다.
  • Age를 기준으로 크게 ">50"<=50이하로 구분한다.
  • 그러기 위해서는 각 조건이 맞는지를 확인하는 if 조건과 반복 수행을 위한 for-loop 조건이 필요하다.
# 빈 리스트 객체 생성
age_group = []

for age in german_credit['Age']:
  if age > 50:
    age_group.append('>50')
  else:
    age_group.append('<=50')

(age_group[0:3])
['>50', '<=50', '<=50']
  • 출력된 결과물은 위와 같은 형태로 저장된 것을 확인할 수 있다.
  • age_group에 저장된 리스트 값을 새로운 변수로 추가한다.
german_credit['Age_group'] = age_group
german_credit['Age_group'].value_counts()
<=50    887
>50     113
Name: Age_group, dtype: int64

(2) 문자형 조건에 따른 변수 추가

  • 이번에는 특정문자열의 존재 유무에 따라 새로운 column is_own을 추가한다.
german_credit['Housing'].value_counts()
own     713
rent    179
free    108
Name: Housing, dtype: int64
  • 위 데이터에서 own인 경우는 True 그렇지 않은 경우는 False로 저장한다.
  • np.where을 사용하면 if처럼 매우 쉽게 사용이 가능하다.
import numpy as np 
german_credit['is_own'] = np.where(german_credit['Housing'] == "own", True, False)
german_credit['is_own'].value_counts()
True     713
False    287
Name: is_own, dtype: int64

변수 삭제

  • 이렇게 생성된 변수를 삭제하도록 한다.
  • 이 때, 가장 많이 사용되는 함수는 drop() 메서드를 이용한다.
  • 함수 사용 시, 주의해야 하는 것 중 하나는 axis 0은 행의 방향, axis 1은 열의 방향 축으로 움직인다.
    • 즉, drop()함수를 사용 시에는 axis 1를 같이 입력한다.
german_credit = german_credit.drop('Age+100', axis = 1)
german_credit.shape
(1000, 12)
  • 이번에는 두개의 변수를 추가한 뒤, 한꺼번에 삭제하는 예제를 실습해본다.
german_credit['age+10'] = german_credit['Age'] + 10
german_credit['age+20'] = german_credit['Age'] + 20
german_credit.shape
(1000, 14)
  • 이제 새로 추가된 변수 2개를 삭제 한다.
german_credit = german_credit.drop(['age+10', 'age+20'], axis = 1)
german_credit.shape
(1000, 12)
  • 이렇게 두개 이상의 변수를 삭제할 때는 list를 활용해서 삭제가 가능하다.

정리

  • DataFrame에서 간단하게 변수를 추가 및 삭제하는 방법에 대해 배웠다.
    • 수치형 변수를 활용한 변수 추가, 문자형 변수를 활용한 변수 추가의 기본적인 내용을 숙지한다.
  • 변수를 삭제할 때는 drop()메서드를 사용하는 데, 행을 삭제할 때는 axis = 0, 열을 삭제할 때는 axis = 1 활용한다.

EDA with Pandas - Data Merge

강의 홍보

I. 개요

  • 실무 데이터에서는 여러가지 데이터를 만나는 경우가 흔하다.
  • 이 때, SQL에서 데이터를 직접 병합하는 방법이 좋다.
  • 그러나, 현실적으로 DB에 접근하는 권한을 가진 경우는 흔하지는 않다. 현재 운영중인 서비스상에 DB를 직접 만지는 경우는 거의 없다 (DBA가 할지도..)
  • 따라서, 데이터분석가는 흩어져 있는 데이터 Dump를 받게 될 가능성이 큰데, 이 때 Python에서 데이터를 병합하는 작업을 진행하게 된다.
  • Kaggle이나 각종 경진대회에 출전하게 되면 서로 다른 데이터를 합쳐야 하는 경우가 매우 많다.

II. 모듈 Import

import pandas as pd
print(pd.__version__)
1.0.4
  • 데이터프레임을 보다 이쁘게 출력하기 위해 다음 2개의 패키지를 불러온다.
from IPython.core.display import display, HTML
from tabulate import tabulate

III. Pandas 데이터 병합 Sample Tutorial

  • 간단하게 데이터를 병합하는 방법에 대해 실습을 진행한다.

(1) 파라미터 세팅

  • 먼저, 행과 열을 최대 출력하는 개수를 지정한다.
pd.set_option('display.max_columns', 500)
pd.set_option('display.max_rows', 500)

(2) 데이터 생성

  • 먼저 가상의 데이터를 두개 만든다.
temp_1 = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 
                       'num1': [1,2,3,4]})
print(tabulate(temp_1, headers=['key', 'num'], tablefmt='pipe'))
|    | key   |   num |
|---:|:------|------:|
|  0 | A     |     1 |
|  1 | B     |     2 |
|  2 | C     |     3 |
|  3 | D     |     4 |
temp_2 = pd.DataFrame({'key': ['A', 'B', 'E', 'F'], 
                       'num2': [5,6,7,8]})
print(tabulate(temp_2, headers=['key', 'num'], tablefmt='pipe'))
|    | key   |   num |
|---:|:------|------:|
|  0 | A     |     5 |
|  1 | B     |     6 |
|  2 | E     |     7 |
|  3 | F     |     8 |

(3) Data Merge - inner join

  • key값을 근거로 데이터를 병합한다.
  • 이 때, merge의 형태는 inner join 형태로 출력된다.
merge_df = pd.merge(temp_1, temp_2, on='key')
print(tabulate(merge_df, headers=['key', 'num1', 'num2'], tablefmt='pipe'))
|    | key   |   num1 |   num2 |
|---:|:------|-------:|-------:|
|  0 | A     |      1 |      5 |
|  1 | B     |      2 |      6 |
inner_df = pd.merge(temp_1, temp_2, on='key', how='inner')
print(tabulate(inner_df, headers=['key', 'num1', 'num2'], tablefmt='pipe'))
|    | key   |   num1 |   num2 |
|---:|:------|-------:|-------:|
|  0 | A     |      1 |      5 |
|  1 | B     |      2 |      6 |
  • 위 두개의 결과값이 똑같음을 확인할 수 있다.

(4) Data Merge - outer join

  • 이번에는 outer join을 해보자.
outer_df = pd.merge(temp_1, temp_2, on='key', how='outer')
print(tabulate(outer_df, headers=['key', 'num1', 'num2'], tablefmt='pipe'))
|    | key   |   num1 |   num2 |
|---:|:------|-------:|-------:|
|  0 | A     |      1 |      5 |
|  1 | B     |      2 |      6 |
|  2 | C     |      3 |    nan |
|  3 | D     |      4 |    nan |
|  4 | E     |    nan |      7 |
|  5 | F     |    nan |      8 |
  • 결과값을 보면, 우선 key값은 모두 출력되었다.
  • 이 때, 각 데이터에서 가져오는 num1num2Column도 같이 들어오는데, 각 column마다 없는 값들은 이렇게 nan으로 조회됨을 확인할 수 있다.

(5) Assignment

  • 이제 수강생 분들이 left & right 조인을 해보도록 한다.
  • 공식문서를 보면서 코드 작성하는 것을 추천한다.
# pd.merge(temp_1, temp_2) 여기 코드에서 남은 코드를 작성하면 됩니다. 
right_df = pd.merge(temp_1, temp_2, on='key', how='left')
print(tabulate(right_df, headers=['key', 'num1', 'num2'], tablefmt='pipe'))
|    | key   |   num1 |   num2 |
|---:|:------|-------:|-------:|
|  0 | A     |      1 |      5 |
|  1 | B     |      2 |      6 |
|  2 | E     |    nan |      7 |
|  3 | F     |    nan |      8 |
  • 그리고 이번에는 left join을 해본다.
# pd.merge(temp_1, temp_2) 여기 코드에서 남은 코드를 작성하면 됩니다. 
right_df = pd.merge(temp_1, temp_2, on='key', how='left')
print(tabulate(right_df, headers=['key', 'num1', 'num2'], tablefmt='pipe'))
|    | key   |   num1 |   num2 |
|---:|:------|-------:|-------:|
|  0 | A     |      1 |      5 |
|  1 | B     |      2 |      6 |
|  2 | C     |      3 |    nan |
|  3 | D     |      4 |    nan |

VI. What’s next

  • 데이터를 병합하는 방법 중 Merge에 대해서 배웠다.
  • Merge에는 크게 4가지 방법이 있고, 방법에 따라서 최종 데이터의 출력값이 서로 다름을 확인하였다.
  • 다음 시간에는 또다른 병합 방법인 Concatenate에 학습하도록 한다.

Data Transformation - Merging Data

강의 홍보

공지

제 수업을 듣는 사람들이 계속적으로 실습할 수 있도록 강의 파일을 만들었습니다. 늘 도움이 되기를 바라며. 참고했던 교재 및 Reference는 꼭 확인하셔서 교재 구매 또는 관련 Reference를 확인하시기를 바랍니다.

  • 데이터는 코로나 데이터를 활용했다.

I. Data Transform Overview

  • 데이터 변환은 데이터를 하나의 형식이나 구조에서 다른 형식이나 구조로 변환하는 데 사용되는 기법이다.

R - Select Helper Functions

I. 개요

dplyr 문법에서 select에 대해 다룬다. 보통 select는 열 추출 함수로 소개되고 있다. 그런데, select 함수에는 열 추출을 할 때 도와주는 helper functions가 있는데, 간단하게 소개하고자 한다.

  • starts_with
  • ends_with
  • contains
  • matches
  • num_range
  • one_of

작은 도움이 되었기를 바란다.

II. 사전 준비

  • 본격적인 실습에 앞서서, 패키지를 로드 한다.
library(dplyr)
library(nycflights13)
  • flights 데이터셋의 변수들을 확인하자.
glimpse(flights)
## Rows: 336,776
## Columns: 19
## $ year           <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, …
## $ month          <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ day            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ dep_time       <int> 517, 533, 542, 544, 554, 554, 555, 557, 557, 558, 558,…
## $ sched_dep_time <int> 515, 529, 540, 545, 600, 558, 600, 600, 600, 600, 600,…
## $ dep_delay      <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -…
## $ arr_time       <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849…
## $ sched_arr_time <int> 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851…
## $ arr_delay      <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -…
## $ carrier        <chr> "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", …
## $ flight         <int> 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79, 301, …
## $ tailnum        <chr> "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N39…
## $ origin         <chr> "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR", "LGA"…
## $ dest           <chr> "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL", "IAD"…
## $ air_time       <dbl> 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, …
## $ distance       <dbl> 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733,…
## $ hour           <dbl> 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, …
## $ minute         <dbl> 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, …
## $ time_hour      <dttm> 2013-01-01 05:00:00, 2013-01-01 05:00:00, 2013-01-01 …
  • 총 19개의 변수들로 구성이 되어 있는 것을 확인 할 수 있다.

III. 다양한 Helpers 응용

  • 앞서 개요에서 소개한 것처럼 순차적으로 helpers 활용한 변수추출을 진행하도록 한다.
  • 필자는 간단하게 소개하는 것이기 때문에, 어떻게 응용할지는 각자 주어진 데이터에서 다시한번 응용하는 것을 추천한다.
  • help(select)를 실행하면 더 자세히 나와 있다.

(1) starts_with

  • 변수명의 prefix를 가져오는 것이다.
  • 예를 들어 알파벳 문자 a만 가져오도록 해보자.
flights %>% select(starts_with("a")) %>% glimpse()
## Rows: 336,776
## Columns: 3
## $ arr_time  <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849, 853…
## $ arr_delay <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14, 3…
## $ air_time  <dbl> 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, 158, …
  • 만약 여기에서 ar로 변경하면, air_time 변수는 추출되지 않는다.
flights %>% select(starts_with("ar")) %>% glimpse()
## Rows: 336,776
## Columns: 2
## $ arr_time  <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849, 853…
## $ arr_delay <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14, 3…

(2) ends_with

  • starts_with의 정확히 반대되는 개념이다. 변수명의 suffix를 기준으로 변수명을 추출한다.
flights %>% select(ends_with("y")) %>% glimpse()
## Rows: 336,776
## Columns: 3
## $ day       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ dep_delay <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1, 0,…
## $ arr_delay <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14, 3…
  • y와 연관된 변수명은 3가지였다.
  • 그런데, 조금더 구체적으로 delay라는 글자를 기준으로 추출해보자.
flights %>% select(ends_with("delay")) %>% glimpse()
## Rows: 336,776
## Columns: 2
## $ dep_delay <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1, 0,…
## $ arr_delay <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14, 3…

(3) contains

  • 변수명에 특정 문자열이 있으면 추출할 때 유용하다.
  • 특정 문자열 el을 조회하는 함수를 작성하도록 한다.
flights %>% select(contains("el")) %>% glimpse()
## Rows: 336,776
## Columns: 2
## $ dep_delay <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -1, 0,…
## $ arr_delay <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -14, 3…

(4) matches

  • helper 함수 중에서 정규 표현식 입력이 가능한 유일한 helper 함수 이다.
  • 우선 아래코드를 확인해보자.
flights %>% select(matches("a{1}")) %>% glimpse()
## Rows: 336,776
## Columns: 10
## $ year           <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, …
## $ day            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ dep_delay      <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2, -2, -…
## $ arr_time       <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 753, 849…
## $ sched_arr_time <int> 819, 830, 850, 1022, 837, 728, 854, 723, 846, 745, 851…
## $ arr_delay      <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -3, 7, -…
## $ carrier        <chr> "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV", "B6", …
## $ tailnum        <chr> "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N39…
## $ air_time       <dbl> 227, 227, 160, 183, 116, 150, 158, 53, 140, 138, 149, …
## $ distance       <dbl> 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 944, 733,…
  • a{1}는 변수명에서 a가 1번 이상 나온 것을 확인하여 추출하는 정규표현식이다.
  • 정규표현식의 관한 정리된 글을 활용하여 익히도록 한다.

(5) num_range

  • num_range는 변수명 중에서 A1, A2와 같이 코드화하여 정리하는 테이블에 변수명을 추출할 때 유용하다.
  • 아래코드를 확인해보자.
set.seed(1)
df <- data.frame(A1 = runif(10), 
                 A2 = runif(10), 
                 A3 = runif(10), 
                 A4 = runif(10), 
                 A5 = runif(10))

df %>% select(num_range('A', range = 2:4)) %>% glimpse()
## Rows: 10
## Columns: 3
## $ A2 <dbl> 0.2059746, 0.1765568, 0.6870228, 0.3841037, 0.7698414, 0.4976992, …
## $ A3 <dbl> 0.93470523, 0.21214252, 0.65167377, 0.12555510, 0.26722067, 0.3861…
## $ A4 <dbl> 0.4820801, 0.5995658, 0.4935413, 0.1862176, 0.8273733, 0.6684667, …

(6) one_of

  • one_of를 활용할 때는 vector를 응용하는데, 이 때 vector안에 있는 변수명과 매칭되는 테이블을 추출한다.
flights %>% select(one_of(c("tailnum", "year"))) %>% glimpse()
## Rows: 336,776
## Columns: 2
## $ tailnum <chr> "N14228", "N24211", "N619AA", "N804JB", "N668DN", "N39463", "…
## $ year    <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2…

VI. Reference

출처: Select/rename variables by name

Python - Pandas 병렬처리

강의 홍보

공지

제 수업을 듣는 사람들이 계속적으로 실습할 수 있도록 강의 파일을 만들었습니다. 늘 도움이 되기를 바라며. 참고했던 교재 및 Reference는 꼭 확인하셔서 교재 구매 또는 관련 Reference를 확인하시기를 바랍니다.

지난 포스트에서는 lambda의 기본적인 개념에 대해서 익혔다면, 이제 본격적인 데이터 전처리와 관련된 예제를 올리려고 한다.