※ 해당 내용은 ADP를 준비하며 학습한 내용을 정리한 것 입니다.

 

1. 데이터 탐색

데이터를 분석하기 전에 대략의 데이터의 특성을 파악하고, 데이터에 대한 통찰을 얻기 위해 다각도로 접근한다.

 

  . 기초 데이터 탐색 ( 예시 )

data(iris)
head(iris, 10) # 데이터 앞 10줄만 출력
str(iris) # 데이터 구조 파악
summary(iris) # 데이터의 기초 통계량 출력
cov(iris[,1:4]) # 공분산
cor(iris[,1:4]) # 상관계수

2. 결측값 처리

결측값을 어떻게 처리하느냐에 따라 작업속도가 달라진다.

 

 . 간단한 결측값 제거

  → 해당 방법은 결측값이 포함된 관측치를 모두 제거한다. 결측값이 넓게 분포된 경우 주의가 필요.

y <- c(1,2,3,NA)
is.na(y)

y[complete.cases(y)] # 결측값 제거

y

 

R에서 주로 결측값처리에는 Amelia II, Mice, mistools 등 여러가지 패키지가 활용.

 

이 중 Amelia 패키지를 실습해 보자

 

library(Amelia)

data(freetrade)
head(freetrade)
str(freetrade)

# m = 몇개의 imputation 데이터셋을 만들지 결정하는 값
# ts = 시계열 정보, cs = cross-sectional 정보
# 즉, 아래 모델에서는 연도와 국가를 고려해
# 모든 freetrade 정보를 활용한 결측값에 대한 imputation(대체)가 이루어 짐
a.out <- amelia(freetrade, m=5, ts = "year", cs = "country")
hist(a.out$imputations[[5]]$tariff, col="grey", border="white")
save(a.out, file = "imputation.RData")
write.amelia(obj=a.out, file.stem="outdata")

missmap(freetrade) # 결측값 처리 전

 

#결측값 처리, inputation
freetrade$tariff <- a.out$imputations[[5]]$tariff
missmap(freetrade) # 결측값 처리 후

3. 이상값 검색

 . 이상값 검색의 활용

  ① 전처리를 어떻게 할지를 결정

  ② 부정사용방지 시스템에서 규칙을 발견하는데 사용

 

 . 이상값의 분류

  ① 의도하지 않게 잘못 입력한 경우 ( a1 )

  ② 의도하지 않계 입력되었으나 분석 목적에 부합하지 않아 제거해야하는 경우 ( a2 )

  ③ 의도되지 않은 현상이지만 분석에 포함해야 하는 경우 ( a3 )

  ④ 의도된 이상값인 경우 ( b1 )

 

 . 관련 알고리즘

  → ESD(Extreme Studentized Deviation)

      : 평균으로부터 K*표준편차만큼 떨어져 있는 값을 이상값으로 판단, 일반적으로 K=3으로 한다.

 

  . 상자그림으로 이상값 식별

x <- rnorm(100)
x <- c(x, 19, 28,30) # 이상값 추가
boxplot(x)

 

  . outliers 패키지 사용

library(outliers)
set.seed(1234)
y=rnorm(100)
outlier(y) # 평균과 가장 많이 차이나는 값 출력
outlier(y, opposite=TRUE)
dim(y) = c(20,5) # 행 20 열 5의 행렬 생성
outlier(y) # 각 열의 평균과 가장 차이가 많은 값을 각 열별로 출력

 # 각 열별로 반대 방향으로 열 평균과 가장 차이가 많은 값 출력

outlier(y, opposite = TRUE)
boxplot(y)

※ 해당 내용은 ADP 준비를 위해 데이터 마트 부분을 학습하며 정리한 내용입니다.

 

. 데이터 마이닝에서의 모델링

  → 다양한 분석 기법을 적용해 모델을 개발하는 과정, 데이터 마트를 개발해 놓으면 효율적이고 신속한 모델링 가능.

 

. 데이터 마트

  → 데이터의 한 부분, 특정 사용자가 관심을 갖는 데이터들을 담은 비교적 작은 규모의 데이터 웨어하우스.

 

. [참고] 데이터 웨어하우스와 마트 비교

  → 사용자의 기능 및 제공 범위를 기준으로 구분함.

  → 웨어하우스=전체의 상세 Data / 마트=특정 사용자 대상, 웨어하우스에 있는 일부 Data

 

1. R reshape를 활용한 데이터 마트 개발

① reshape

 

 reshape는 데이터 재정렬을 위한 기법 중 하나, 비견될 수 있는 기법 중 밀집화가 있다.

 

 . [참고] 밀집화

  → 데이터를 축소하고, 재정렬 ( ex) Excel Pivot )

  → 밀집화는 데이터가 간단하게 표시되지만, 원본이 손실되고, reshape는 원본이 유지된다는 점에서 차이가 있다.

 

 . melt() & cast 함수

  → reshape 패키지로 melt(), cast()만을 사용하여 데이터를 재구성 or 밀집화된 Data를 유연하게 생성 가능

  → melt로 데이터를 녹여 유연하게 만든 후 피벗과 비슷한 cast로 모양을 잡아준다고 생각하면 됨.

library(reshape)

names(airquality)
names(airquality) <- tolower(names(airquality)) #소문자 변환

# id에 있는 변수를 기준으로
# 각변수 Variable이란 이름의 데이터로 만듬
# [참고] na.rm = 결측값 제거
aqm <- melt(airquality, id=c("month","day"), na.rm = TRUE)
aqm

# cast를 이용해 엑셀의 Pivoting을 하듯이 자료를 변환

# cast( data, y축~x축~값 )

a <- cast(aqm, day~month~variable)
a

mean을 적용해 평균값을 산출할 수도 있다.

b <- cast(aqm, month~variable, mean) # 월별 평균값 계산
b

|를 이용하여 산출물을 분리해 표시도 가능하다. ( 조회에 적합 )

c <- cast(aqm, month ~ .|variable, mean)
c

margin 함수로 행/열의 소계도 산출 가능

# 행과 열의 소계 산출
d <- cast(aqm, month~variable, mean, margins=c("grand_row", "grand_col"))
d

 

특정 변수만 처리하고자 할 때 subset 옵션을 추가

# 특정변수만 처리하고자 할 때
e <- cast(aqm, month~variable, mean, subset = variable=="ozone")
e

 

range 옵션을 추가하면 min, max를 동시에 표시해 준다

 

# min, max 표시 ( min=_X1 / max=_X2 )
f <- cast(aqm, month~variable, range)
f

 

2. sqldf를 이용한 데이터 분석

sql를 R에서도 사용할 수 있도록 하는 패키지, 단순히 sqldf 괄호 안에 SQL 언어를 입력하여 사용하면 됨.

 

data(iris)
sqldf("select * from iris limit 10") # head와 같은 기능 구현

 

3. plyr : 데이터 분리+처리 후 결합

 

ply 함수와 multi-core 사용 함수를 이용하면 for loop를 간단하고 매우 빠르게 처리 가능

 

ply() 함수는 앞에 두 개 문자를 접두사로 가진다.

 

첫 번째 문자=입력하는 데이터 형태, 두 번째 문자= 출력하는 데이터 형태

 

  [ 접두사(데이터형태) 종류 ]

  가. d = 데이터 프레임 ( data.frame )

  나. a = 배열 ( array )

  다. l = 리스트 ( list )

 

실습에 사용할 Data 생성

set.seed(1) # 난수 고정, 같은 난수를 생성하도록 해줌

# runif( 생성할 난수 개수, 최소값, 최대값)
d = data.frame(year = rep(2012:2014, each=6), count = round(runif(9,0,20)))
d

. ddply을 사용해 데이터 프레임을 입력받아 sd와 mean의 비율인 변동계수 cv 구하기

 → test 결과 Rcpp 패키지도 추가해 주어야 함

library(plyr)
library(Rcpp)

ddply(d, "year", function(x){
  mean.count = mean(x$count)
  sd.count = sd(x$count)
  cv = sd.count/mean.count
  data.frame(cv.count=cv)
})

 

 . transform, summarise 옵션

  → summarise 옵션 = 변수에 명령된 평균이나 합 등을 계산해 줌

  → transform 옵션 = summarise 옵션과 달리 계산에 사용된 변수도 출력

 

ddply(d, "year", summarise, mean.count = mean(count))

ddply(d, "year", transform, total.count = sum(count))

4. 데이터 테이블 ( Data Table )

데이터 테이블은 데이터 프레임과 우사하지만 보다 빠른 그룹화, 순서화, 짧은 문장 지원 측면에서 매력적

 

data.frame과 같은 방법으로 생성되나, 행 번호가 콜론(:)으로 표시

# rnorm(n) 함수는 정규분포에서 n개의 난수 생성
DT <- data.table(x=c("b","b","b","a","a"),v=rnorm(5))
DT

 

기존 data.frame을 data.table 형식으로 변환 가능하다.

CARS <- data.table(cars)

. data.frame과 data.table 차이점

 → 데이터 테이블 = 인덱스(목차) 생성이 가능한 데이터 프레임

 → 따라서 검색과 같은 작업을 할 때 성능의 차이점을 보인다.

 → [참고] 검색 시 data.frame은 하나하나 비교해 찾는 벡터 검색 방식 / data.table은 목차를 이용, 바이너리 검색

※ 해당 글은 R 기초를 복습하면서 작성한 자료입니다.

 

R의 데이터 구조

① 벡터: 하나의 스칼라값, 혹은 하나 이상의 스칼라 원소들을 갖는 단순한 형태의 집합.

   → c함수를 활용하여 선언 ( 하나의 Column=열 이라고 생각 )

x <- c(1, 10, 24, 40) #c함수를 이용하여 벡터 선언

 

②행렬: 행과 열을 갖는 m x n 형태의 직사각형에 데이터를 나열한 데이터 구조

  → [주의] 각 열이 같은 데이터 Type이여야 함

  → matrix 함수를 활용하여 선언

mx <- matrix(c(1,2,3,4,5,6), ncol=2)

  →[참고] rbind와 cbind를 사용해 벡터를 행렬에 합칠 수도 있다.

     ( rbind= 행 결합 / cbind= 열 결합 )

 

r1 <- c(10,20)
rbind(mx, r1) # row bind, 행 결합

c1<- c(20,20,20)
cbind(mx, c1) # Column bind, 열 결합

 

③ 데이터 프레임: 행렬과 유사한 2차원 목록 데이터 구조

  → [행렬과 차이점] 각 열이 서로 다른 데이터 타입을 가질 수 있음

  → data.frame 함수로 선언

income <- c(100,200,150)
car <- c("kia", "hyundai", "toyota")
marriage <- c(FALSE, TRUE, FALSE)

mydata <- data.frame(income, car, marriage)

 

외부 데이터 불러오기

 

① csv 파일 불러오기

 → read.table 함수를 이용하여 R에 Data frame 형태로 불러옴

data1 <- read.table("파일경로\파일명.csv", header=T,sep=",")

 → [참고] read.csv를 써도 무방, 대신 사용 시 sep=","로 구분자 구분 X

 

② txt 파일 불러오기

  → sep=","로 구분자 구분 X

data2 <- read.table("파일경로\파일명.txt", header=T)

 

③ xls/xlsx 파일 불러오기

  → 2가지 존재, csv파일 변환 후 불러오거나 패키지 이용

  → ex) RODBC 패키지 이용

library(RODBC)
new <- odbcConnectExcel("파일경로")
yourdata <- sqlFetch(new,"Sheet이름")
close(new)

 

R 기초 함수

① 수열 생성하기

  . rep(): 첫 번째 인수를 두 번째 인수만큼 반속하는 수자 벡터 생성

rep(1,3) # 1을 3번 반복하는 벡터 생성

  . seq(): 첫 번째 인수부터 두 번째 인수까지 1씩 증가하는 수열을 숫자 벡터 생성

    → [옵션1] by=n 으로 설정하면 n씩 증가하는 벡터 생성 가능

    → [옵션2] length=m 으로 설정하면 전체 수열의 갯수가 m개가 되도록 자동적으로 증가하는 수열 생성 

seq(1,5) # 1부터 5까지 1씩 증가하는 벡터 생성
seq(1,5,by=2) # by 옵션을 추가하여 2씩 증가하도록 변경
seq(1,5,length=7) # length 옵션을 추가하여 수열을 갯수 7개로 자동계산

 

② 기초적인 수치 계산

  . 사칙연산 ( +, -, *, / )

    → 사칙연산을 수행하고자 할 때 기본적으로 백터의 크기는 같아야 함.

 

   . 전치행렬과 행렬곱

    → 전치행렬= t함수 활용, 행렬곱 = %*% ( 행렬에 * 사용 시 단순히 스칼라 곱 반환 )

a <- c(2,7,3)
t(a) # a의 전치행렬
A <- a%*%t(a)

   . 역행렬

     → solve 함수 사용 ( 단, 정방행렬이어야 함. )

solve(mx) #mx의 역행렬 계산

   . 기초 기술 통계량 계산

    → mean(): 평균 / var(): 분산 / sd(): 표준편차 / sum(): 합 / median(): 중간값 / log(): 자연로그값

    → cov(): 공분산 / cor(): 상관계수 / sumary(): 사분위 수 계산 및 정보 요약

 

R 데이터 핸들링

b = c(1,2,3,4,5) 라는 벡터가 존재할 때,

 

① 벡터형 변수

  → b[2] : 2번째 원소에 해당되는 값만 불러옴

  → b[-4] : -를 붙이면 4번째 원소에 해당되는 값을 제외 후 불러옴

  → b[ c(2,3) ] : 벡터의 2, 3번째 위치 값을 선택

 

 ② 행렬/데이터 프레임 변수

  → 대괄호 안에 두가지 숫자가 추가될 뿐, 방식은 벡터형 변수와 동일.

mydata[3,2] # 3행 2열을 값을 불러옴
mydata[ ,2] # 2열의 값을 불러옴
mydata[4, ] # 4행의 값을 불러옴

 

  ③ 반복 구문과 조건문

 

   . For 반복문 : i값을 하나씩 증가시켜가며 중괄호 { } 안의 구문은 반복실행

a = c() # 아무런 값도 포함되지 않은 벡터 생성
for(i in 1:9){
  a[i] = i*i
}

    . while 반복문 : 괄호 ( ) 조건 하에서 중관호 { } 안의 구문을 반복

x=0
while( x<5 ){
  x=x+1
  print(x)
}

    . if ~ else 조건문: 특정 조건이 만족하는 경우 이후의 구문을 실행

StatScore <- c(10,11,2,14,11,9,7,15,6,7)
over10 <- rep(0,10)

# 10이상의 점수의 수 구하기
for(i in 1:10){
  if ( StatScore[i] >= 10) over10[i] = 1
  else over10[i] = 0
}
sum(over10)

 

    . 사용자 정의 함수: function()을 이용, 함수를 정의하여 사용 가능

addto <- function(a){
  isum = 0
  for(i in 1:a){
    isum = isum+i
  }
  print(isum)
}
addto(100)

 

기타 유용한 기능들

① paste() : 입력받은 문자열들을 하나로 붙여줌. ( 'sep=' 옵션을 통해 문자열 사이 구분자 추가도 가능 ) 

number <- 1:10
alphabet <- c("a","b","c")
paste(number,alphabet, sep=" to the ")

② substr() : paste와 반대로 주어진 문자열에서 특정 문자열을 추출함.

   → 해당 기능을 통하여 출력 결과를 간소화 할 수 있다.

country <- c("Korea", "Japan", "China", "Singapore", "Russia")
substr(country, 1, 3)

 

③ 자료형 데이터 구조 변환

  → 주어진 객체의 데이터 구조를 바꾸자 할 때 사용

  

   가. as.data.frame(x) : 데이터 프레임 형식으로 변환

   나. as.list(x) : 리스트 형식으로 변환

   다. as.matrix(x) : 행렬 형식으로 변환

   라. as.vector(x) : 벡터 형식으로 변환

   마. as.factor(x) : 팩터 형식으로 변환

 

④ 문자열을 날짜로 변환

  → as.Date로 변환, 표준형식은 바로 변환되지만, 임의 형식은 Format을 지정해주어야 함.

 

⑤ 날짜를 문자열로 변환

※ 해당 내용은 위의 책을 통해 R을 학습하면서 개인적으로 정리한 내용임을 밝힙니다.

 

[ 사용 Packages = tidyverse ] 

library(tidyverse)

[ 실습용 Data Set = diamonds ]

# diamonds : 54,000개 다이아몬드 각각으 가격, 캐럿, 색상, 투명도 등 정보를 가진 Data Set
diamonds

[ 참고 사항 ]

ggplot2는 보통 ggplot(data=<데이터>)에 지옴 함수를 + 하여 작동

  → 즉 그래프 형식을 변경하거나 표현을 추가하고 싶다면 +되는 지옴함수를 바꾸면 됨 

막대 그래프 그리기 ( geom_bar() )

 

막대그래프는 범주형 자료들을 한 눈에 비교하여 볼 때 유용하다. ggplot2에서는 아래와 같이 geom_bar() 함수를 활용하여 쉽게 구현 가능하다.

# geom_bar 활용 막대 그래프 작성 ( cut에 포함되는 범주들을 Count하여 구분 )
ggplot(data=diamonds)+geom_bar(mapping = aes(x = cut))

 

특이한 점이 보인다. Count라는 변수는 선언하지도 않았는데, 저절로 범주별 Count를 진행하였다. 여기서 알아야할 개념이 '스탯 = 통계적의 줄인말 = stat ' 이다. ggplot2에서 스탯이란 ' 그래프에 사용될 새로운 값을 지정해 나가는 과정'을 의미한다. 위처럼 cut 변수만 지정하였는데, Count 변수가 저절로 생긴 이유는 geom_bar()에는 기본으로 count 스탯이 있기 때문이다. 아래처럼 지옴과 스탯을 바꾸어 작성해도 결과는 같다.

ggplot(data=diamonds)+stat_count(mapping = aes(x = cut))

 

그렇다면 기본 스탯을 다른 스탯으로 덮어 씌울 수 는 없을까? 가능하다. stat 변수에 identity를 입력하면 된다.

 

# 연습용 Data
demo = tribble(
  ~cut, ~freq,
  "Fair", 1610,
  "Good", 4906,
  "Very Good", 12082,
  "Premium", 13791,
  "Ideal", 21551
)

ggplot(data=demo) + geom_bar(
  mapping = aes(x=cut, y=freq), stat = "identity"

 

빈도 수 (Count)가 아닌 비율로 막대 그래프를 그리고 싶다면, 매핑 aes 함수 y에 ..prop.. 변수를 입력해주면 된다.

 

ggplot(data=diamonds) + geom_bar( mapping = aes(x=cut,y=..prop.., group=1))

요약 값 ( Min, Max, 중간값 ) 등에 집중시키고 싶다면, stat_summary를 사용해도 좋다.

 

ggplot(data=diamonds) + stat_summary(
  mapping = aes(x=cut, y=depth),
  fun.min = min,
  fun.max = max,
  fun = median
  )

geom_bar()와 비슷한 함수 중 geom_col() 도 있다. Bar와 col의 차이는 통계적으로 변환을 하냐, 안하냐 차이다. 따라서 Col 같은 경우 매핑 시 2개의 변수를 지정해주어야 하는데, Bar의 경우 한 개의 변수만 지정해 주어도 기본 통계적 변수로 알아서 변환해 준다.

 

# geom_bar은 스탯 활용, X축만 입력해도 통계적 변환 후 그래프에 표시
#  geom_col은 Data를 통계적 변환하지 않고 그대로 표시

ggplot(data=diamonds)+geom_bar(mapping = aes(x = cut))
ggplot(data=diamonds)+geom_col(mapping = aes(x = cut, y=depth))

산점도, 기하 그래프를 학습할 때, 항상 학습한 것이 있다. 그래프에 한가지 변수를 더 추가하여 구분하는 것이다. geom_bar()에서는 Fill 변수에 구분하고자 하는 변수를 입력하면 된다. ( 색상은 랜덤 )

 

# Cut 변수를 Cut 변수로 구분, 즉, 각 범주마다 색상 입히ggplot(data=diamonds) + geom_bar(mapping = aes(x=cut, fill=cut))  

# 막대그래프 상 Clatity 변수로 색상 구분
ggplot(data=diamonds) + geom_bar(mapping = aes(x=cut, fill=clarity))

위의 막대 그래프는 한 변수 위에 다른 변수가 축적된 누적 막대그래프이다. 누적 막대그래프가 아니게 표현하고 싶다면, Position을 "identity", "dodge", "fill" 등으로 지정해주면 된다.

 

먼저 "identity"를 살펴보자. "identity"는 누적 막대그래프가 아닌 변수마다 0부터 시작하게 포지션을 잡고, 같은 범주끼리 묶어버린다. 아래 그래프를 보면 직관적으로 이해가 가능하다. ( 잘 보기 위해선 투명도도 추가 하자 )

 

# 누적 막대그래프가 아닌, 중복 막대그래프 그리기
# 외쪽 Count 범위를 보면 지정 안했을 때와의 차이를 알 수 있다.
ggplot(
  data=diamonds,
  mapping = aes(x=cut, fill = clarity)
) +
  geom_bar(alpha = 1/5, position = "identity")

동일한 기준에서 범주마다 한 변수의 비율을 비교하고 싶다면, Position을 "fill"로 지정하면 된다.

 

ggplot(
  data=diamonds,
  mapping = aes(x=cut, fill = clarity)
) +
  geom_bar( position = "fill")

 

각 범주마다 직관적으로 비교해보고 싶다면, "dodge"를 입력하면 된다.

 

 

※ 해당 내용은 위의 책을 통해 R을 학습하면서 개인적으로 정리한 내용임을 밝힙니다.

 

[ 사용 Packages = tidyverse ] 

library(tidyverse)

[ 실습용 Data Set = mpg ]

# mpg : 미 환경보호당국이 수집한 38개의 차 모델들에 대한 관측값
mpg

[ 참고 사항 ]

ggplot2는 보통 ggplot(data=<데이터>)에 지옴 함수를 + 하여 작동

  → 즉 그래프 형식을 변경하거나 표현을 추가하고 싶다면 +되는 지옴함수를 바꾸면 됨 

 

기하 그래프 그리기 ( geom_smooth() )

 

지난번 산점도에 이어서 기하 그래프를 그리는 방법을 학습해보자. 산점도로 상관관계 파악이 가능하지만, 평활선을 그려 추세를 볼 수 있다면, 더 효과적인 Data 이해가 가능하다. 이 때는 geom_smooth() 함수를 사용하면 된다.

 

산점도 보다 배기량(displ)과 연비(hwy)의 상관 관계를 선으로 보다 명확히 볼 수 있다.

 

# geom_smooth(), 데이터에 적합한 평활선을 만들어 추세 보여줌
# geom_Point()와 사용 방법은 비슷하다. ( 지옴함수만 바뀜 )
ggplot(data=mpg) + geom_smooth(mapping = aes(x=displ, y=hwy))

 

geom_point()에서는 다양한 방식(색상, 모양, 투명도 등)으로 1개의 변수 안 항목을 그래프 상에서 구분 표현하였다. 이처럼 geom_Smooth()에서는 linetype을 추가하면, 1개의 변수의 Data의 항목을 구분하여 표현이 가능하다.

 

구동방식(drv) 변수를 지정해서 4륜, 전륜, 후륜을 구분해서 평활선을 볼 수 있다.

 

# geom_smooth() + linetype 추가, 지정 Data로 평활선을 구분
ggplot(data=mpg)+geom_smooth(mapping = aes(x=displ, y=hwy, linetype = drv))

 

평활선을 산점도와 같이 보고 싶다면, 지옴 함수를 더 + 해주면 된다.

# ggplot()에 추가 표현하고 싶은 지옴함수를 +로 추가
ggplot(data=mpg)+
  geom_smooth(mapping = aes(x=displ, y=hwy)) +
  geom_point(mapping = aes(x=displ, y=hwy))

위와 같이 지옴 함수마다 x,y에 어떤 변수를 매핑하는지 각각 지정해 줄 수도 있다. 그러나 X,Y 변수가 동일할 땐, 상위

ggplot에 매핑을 지정하여, 전역 처리하면 보다 코드를 간단히 할 수 있다. 

ggplot(data=mpg,mapping = aes(x=displ, y=hwy))+
  geom_smooth()+
  geom_point()

 

<참고> 중복되는 것은 전역처리하고, 지옴 함수 별 심미성을 표현하면 더 깔끔하게 작성 가능하다.

ggplot(data=mpg,mapping = aes(x=displ, y=hwy))+
  geom_smooth(
    data=filter(mpg, class == "subcompact"),
    se = FALSE
  )+
  geom_point(mapping = aes(color=class))

+ Recent posts