R

오픈소스 비즈니스 컨설팅
이동: 둘러보기, 검색

통계소프트웨어인 GNU R language를 정리 합니다.

R 개요

통계/데이터 마이닝 및 그래프를 위한 언어

  • 데이터 분석용 객체지향언어인 GNU S language의 구현
  • 통계 분석과 그래픽 처리 분야에 특화된 프로그램 언어와 패키지로 구성된 소프트웨어 환경
  • CRAN (Comprehensive R Archive Network)라는 R package site 제공
  • 3826개 이상의 package
  • 많이 사용하는 통계 Software
  • SaS
  • Rapid Miner, Weka
  • Minitab, SPSS, Systat, RATS, KXEN

R 데이터 종류

개요도

Rdata.png

데이터 속성

  • 비율식 (Ratio) < 구간식 (Interval) < 순서식 (Ordinal) < 명명식 (Nominal)
데이터 속성 상세
명명식 (Nominal)
  • 명목척도
  • 이름으로 구분되는 자료, 예) 성별
순서식 (Ordinal)
  • 서열척도
  • 순서가 있는 명명식, 예) 소득의 상, 중, 하
구간식 (Interval)
  • 간격척도
  • 순서의 간격을 측정할 수 있는 순서식, 예) 온도
비율식 (Ratio)
  • 비율척도
  • 절대 영점이 존재해 비율이 의미가 있는 구간식, 예) 체중

변수

변수 상세
연속형 변수
  • Continuous, 연속된 변수
이산형 변수
  • Discrete, 값의 개수가 정의된 변수, 예) 동전의 앞, 뒤
  • 범주형 변수 (Categorical)
  • 이산형 변수의 한 종류로 연속형 변수를 그룹화하여 이산화할 때 사용할 수 있음
  • 예) 나이 : 10대, 20대, 30대, ...

데이터 품질

데이터 품질 상세
특이값
  • Outlier, 이상 데이터
결측값
  • Missing, 측정되지 않은 값
중복
  • 중복된 값
정확도
  • Accuracy, 실제값과 측정된 값의 가까운 정도
  • 오차 (Error)
정밀도
  • Precision, 반복 측정시 측정된 값의 가까운 정도
  • 표준펀차
편향
  • Bias, 측정값과 측정값의 평균의 차이
  • 변이도 (Variation)

데이터 형

  • 기본형
데이터형 상세
numeric
(수치형)
  • Integer, Double
  • numeric(25)
logical
(논리형)
  • 상수 : TRUE, FALSE
  • 변수 : T, F
  • logical(25)
character
(문자형)
  • "~", '~'
  • character(25)
  • paste(var1, var2, sep = " ") : sep를 사용하여 두 문자열을 결합
  • 구조형
  • 동일한 자료형을 가지는 데이터를 가짐
데이터형 상세
Scalar
(스칼라)
  • 하나의 기본형 데이터를 가지는 변수
Factor
(요인)
  • 범주형(Categorical) 변수, 여러 개의 값을 가질 수 있음
  • 명명식 또는 순서식 데이터를 저장
sex <- factor("남", levels=c("남", "여"))           #--- 명명식 (Nominal)
sex <- factor(c("남", "여"), levels=c("남", "여"))  #--- 명명식 (Nominal)
factor(c("a", "b", "c"), ordered=TRUE)              #--- 순서식 (Ordinal)
ordered("a", "b", "c")                              #--- 순서식 (Ordinal)

nlevels(~)                                          #--- 범주의 수
levels(~)                                           #--- 범주 목록
sex[1]                                              #--- 첫번재 값 표시 (1, 2, 3, …)
Vector
(벡터)
  • Scalar의 조합, Factor의 조합도 가능
  • 속성 : 자료형, 길이 (length(vectorA), NROW(vectorA))
vectorA <- c(1, 2, 3)                               #--- c. concatenating
vectorA <- vector(mode = "numeric", length = 3)
names(vectorA) <- c("aaa", "bbb", "ccc")            #--- 이름 지정
vectorA["aaa"]                                      #--- 이름으로 데이터 반환
vectorA[2]                                          #--- 두번째 값 반환 (1, 2, 3, …)
vectorA[-1]                                         #--- 첫번째 값을 제외하고 반환
vectorA[c(1, 3)]                                    #--- 첫번째와 세번째 값 반환
vectorA[vectorA > 5]                                #--- 5보다 큰 값
vectorA[c(FALSE, FALSE, TRUE)]                      #--- TRUE로 표시된 순서의 데이터 반환

vectorC = append(~, ~), vectorC <- c(~, ~)          #--- 두개의 Vector 결합
1 %in% vectorA                                      #--- vectorA에 1이 포함되어 있으면 TRUE 반환
union(~, ~), intersect(~, ~), setdiff(~, ~)         #--- 합집합, 교집합, 차집합
setequal(~, ~)                                      #--- Vector간 비교
Matrix
(행렬)
  • R의 기본 데이터형
  • 속성 : 행 개수(nrow(~)), 열(ncol()) 길이 (nrow(matrixA), NROW(matrixA)), 자료형, 행 이름
matrixA <- matrix(1:15, nrow=3, ncol=5)             #--- 열부터 데이터 채움
matrixA <- matrix(c(1, 3, 5, 7), nrow=2, ncol=2,    #--- 행부터 데이터 채움
   byrow=TRUE, dimnames=list(c('R1', 'R2'), c('C1', 'C2)))
matrixA[row, col]                                   #--- row 또는 col은 생략 가능 (1, 2, 3, …)
matrixA[1:2,]                                       #--- 1행과 2행 데이터 반환
matrixA[-3,]                                        #--- 3행을 제외한 데이터 반환
matrixA["R1", "C1", drop=FALSE]                     #--- R1 행, C1열 데이터를 Matrix 형태로 반환

matrixA %*% matrixB                                 #--- 행렬 곱
solve(~)                                            #--- 역행렬
t(~)                                                #--- 전치 행렬 (행과 열을 교환)
Array
(배열)
  • 3차원 이상의 데이터를 다룰 경우 주로 사용
  • 속성 : 열 길이, 자료형, 차원수(dim(~)), 차원 이름
arrayA <- array(1:12, dim=c(3, 4))                  #--- 2차원 배열 생성

attr(arrayA, "dim") <- NULL                         #--- Array에서 dim 속성을 삭제하면 vector가 됨
Vector                                              #--- dim 속성이 없음
Matrix                                              #--- dim 속성이 c(~, ~) 임
Array                                               #--- dim 속성이 있음
  • 복합형
  • 서로 다른 자료형의 데이터를 가질 수 있음
데이터형 상세
List
(리스트)
  • vector와 동일한 연산 방식 적용
  • 속성 : 컴포넌트 개수 (length()), 자료형, 이름
listA <- list(name='aa', age=45)
list$name, listA1                 #--- 'aa' 반환
listA[1]                              #--- list(name='aa') 반환
list$name <- NULL                     #--- List에서 name 항목 삭제
vectorB <- unlist(listA)              #--- list를 vector로 변환
sort(~), ~[sort(~)]                   #--- 정렬
Data Frame
(데이터 프레임)
  • matrix와 동일한 연산 방식 적용
  • 속성: 열 길이, 자료형(복수), 변수 이름, data.frame 객체
data <- data.frame(x=c(1, 2, 3), y=(4, 5, 6))   #--- x, y열을 같는 데이터 정의
data <- data.frame(cols1, cols2, cols3)
data <- data.frame(1:3, c("col1", "col2", "col3"))
names(~), colnames(~)                 #--- 열이름 조회
colnames(~) <- c(~, ~)                #--- 열이름 지정
rownames(~)                           #--- 행 이름 조회
dim(~)                                #--- 차수(5행 * 2열)를 조회
data[row, col]                        #--- row/col (1, 2, 3, …)
data["rowName", "colName"]
data$col1                             #--- 컬럼 이름에 해당하는 데이터
#--- R search path에 data 등록, col1 이름을 직접 사용 가능
attach(data)               
data[, 1]                             #--- 결과를 Vector로 반환
data[, 1, drop=FALSE]                 #--- 결과를 Data Frame으로 반환
data[, names(data) %in% c("col2", "col3")]   #--- col2, col3 열 표시
data[, c(FALSE, TRUE, TRUE)]          #--- 위 라인과 동일한 결과 표시
data[, !names(data) %in% c("col1")]   #--- col1 열을 제외한 열 표시

head(~), head(~, 12)                  #--- 몇 개의 시작 데이터만 조회
tail(~), tail(~, 3)                   #--- 몇 개의 마지막 데이터만 조회
subset(data, math > 6), data[data$math > 6)  #--- 조건을 만족하는 데이터 반환
data[, "math" <- data2[, "math"] + 1
transform(data, math = math + 1)
rbind(~, ~), cbind(~, ~)              #--- 두개의 data를 행기준, 열기준으로 결합
split(data$a, data$b)                 #--- b를 기준으로 그룹화된 list 반환
  • Special Values
데이터 상세
NULL
  • Empty value
is.null(~)
NA
  • Not Available (missing value, 결측치), is.na(var1)
  • mean(~, na.rm=T) : NA 값은 계산에서 제외
var1[!complete.cases(var1),]          #--- var1에서 NA 데이터가 포함된 레코드 제외
var1[is.na(!var1$field1), ]           #--- var1에서 field1이 NA인 데이터 레코드 제외
na.omit(data)                         #--- NA가 포함된 행 제외
na.pass(data)                         #--- NA 여부에 상관없이 처리
na.fail(data)                         #--- NA 포함시 Exception 발생

library(Amelia)
data(freetrade)

#--- year, country를 고려하고 5개의 파일을 만들어 NA 데이터 처리
imsi <- amelia(freetrade, m=5, ts="year", cs="country") 
freetrade$tariff <- imsi$imputation5$tariff
missmap(freetrade)

hist(imsi$imputations3$tariff, col="grey", border="white")
write.amelia(obj=imsi, file.stem="outdata")   #--- outdata1.csv ~ outdata5.csv
NaN
  • Not a Number
is.nan(var1)
Inf
  • Infinite number (-Inf)
is.finite(var1)
  • Formulas
  • y ~ x : y는 x로 기술됨
  • + : 효과 추가 (y ~ x1 + x2)
  •  : : Interaction ( y ~ x1 : x2)
  • * : Main effect + interaction (y ~ x1 * x2는 다음과 동일 y ~ x1 + x2 + x1 : x2)
  • I(~) : I(~)를 사용하여 수식 형태의 독립변수 추가, 예) I(x^2)
  • (x1 + x2 + x3)^2 : 최대 2개까지의 변수가 상호 작용이 있음
  • x1 + x2 + x3 + x1:x2 + x1:x3 + x2:x3
  • -1 : Remove intercept

빅데이터 분석

  • 요약 변수 (Summary Variables)
  • 빅데이터 분석을 위해서 1차 가공한 변수
  • 연속형 변수 : 구간화
  • 시계열 : 기간별 ~, 요일별 ~, 주중/주말별 ~
  • Trend : 증감액, 증감비율
  • 순서 : 구매 순서
  • SNS 데이터 : 단어 빈도
  • 파생 변수 (Derived Variables)
  • 분석자의 판단에 따라 특정 조건을 만족하는 변수
  • 예) 가중치를 부여한 데이터, 주구매 상품 10개
  • 예) 근무시간 구매지수, 주구매 매장, 주 활동 지역, 주구매 상품(10개), 구매 상품 다양성, 가격 선호대, 시즌 선호 고객, Life Stage, Life Style, 행사 민감, 휴면 가망, 최대 가치, 고객 생애 가치 (CLV), Best Call Time
  • 독립 변수
  • 종속 변수를 설명하기 위해서 사용하는 변수
  • 종속 변수
  • 분석의 대상이 되는 변수
  • 독립 변수로 설명을 하고자 하는 변수
  • 데이터의 속성을 확인하는 함수
  • class(~) : 변수의 type을 표시
  • is.numeric, is.factor, is.matrix, is.data.frame 등의 함수 제공
  • typeof(~) : 저장된 데이터 type을 표시
  • mode(~) : 데이터의 저장 구조 표시
  • str(~) : 데이터의 내부 구조 표시
  • 데이터 변환
  • 생성자의 인자로 데이터를 전달하여 변환
  • as.character, as.numberic, as.factor 등의 함수 제공
  • R의 객체는 불변하므로 객체 연산을 하는 것이 속도와 메모리 측면에서 유리

CentOS에서 R 설치

사전 준비 사항

설치

  • R을 설치 합니다.
yum install R R-*
R --version
  • 관련 패키지 설치
R
    install.packages("KoNLP")
  • 설치 정보
  • 홈 디렉토리 : /usr/lib64/R
  • 라이브러리 설치 폴더 : /usr/lib64/R/library
  • R_SHARE_DIR=/usr/share/R
  • R_INCLUDE_DIR=/usr/include/R
  • R_DOC_DIR=/usr/share/doc/R-3.0.0
  • 실행
R
    q() 와 n을 입력하여 종료 합니다.

Windows에서 R 설치

R 설치

  • http://cran.rstudio.com/ 사이트에서 Windows용 R 설치 파일(R-3.0.2-win.exe)을 다운로드 하여 설치 합니다.
  • Windows의 시작 메뉴에서 "R -> R x86 3.0.2" 메뉴를 선택하여 R을 실행 합니다.
q()                      //--- R 종료

RStudio 설치

  • Windows의 시작 메뉴에서 "RStudio -> RStudio" 메뉴를 선택하여 RStudio를 실행 합니다.

R 매뉴얼

R의 기본 문법

  • R 기본 명령어
? cmd                       //--- 명령어/함수 등에 대한 도움말
help(cmd)                   //--- 명령어/함수 등에 대한 도움말
?? cmd                      //--- 명령어/함수 검색   
install.packages("~")       //--- Package 설치
library(package)            //--- Package 로딩
q()                         //--- 종료
  • 제어문
  • var : 데이터의 내용 표시
  • var <- val : 변수에 값 지정
  • while (~) { break; continue; }
  • if (~) { ~ }
  • 함수 선언 : funcName <- function(~) { return(result) }
  • Sequence value : 1:5 -> 1, 2, 3, 4, 5
1:5
seq(0, 10, by=1)
seq(0, 10, length=20)
rep(5, 10)                //--- 5를 10번 반복
  • debug(함수명), undebug(함수명) : 함수 실행시 debug 모드로 실행
  • n : 함수를 한줄씩 실행
  • c : 함수의 현단계 마지막까지 실행함
  • ls() : 확인 가능한 변수를 보여줌
  • where : 활성화된 함수의 traeback 목록 표시
  • Q : Debug Browser 종료
  • 기본 함수
  • summary(~) : 통계 정보
  • range(~) : 최대/최소, quantile(~) : 4분위 수, var(~) : 분산, sqrt(~) : 표준펀차
  • hist(~) : Histogram, plot(~) : 선 그래프, boxplot(~), plot(~) : 산점도 행렬
  • 데이터 입력
  • 표준 입력 : scan()
  • 파일 입력 : read.table(), text, csv, 압축파일 (zip, gzip, bzip 등)
  • 데이터 소스 입력 : URL, Database 등
varA <- read.csv(~.csv)
load("~.Rdata")
  • 데이터 처리
print(varA)
rm(varA)                             //--- varA 변수를 삭제
rm(list=ls(pattern="a01?"))          //--- a01로 시작하는 모든 변수 삭제

data(varA)
describe(varA)
summary(varA)
  • 데이터 저장
write.csv(varA, "~.csv")
save(varA, file="~.Rdata")           //--- 데이터 파일로 저장

R 사용법

  • R
memory.limit(4096)                   #--- Memory를 4GB로 설정
  • Package Library
  • bigmemory package
install.packages("bigmemory", repos="Http://R-Forge.R-project.org")
  • biganalytics package
install.packages("biganalytics", repos="Http://R-Forge.R-project.org")
  • doSMP
  • Rhipe (R and Hadoop Integrated Processing Environment)
  • Google Protocol Buffers (protobuf 2.4.1)
R CMD INSTALL Rhipe_version.tar.gz

library(Rhipe)
system("wget ~")
rhput("~", "hdfs://user/root/~")

map<-expression({
    words_vector<-unlist(strsplit(unlist(map.values), " "))
    lapply(words_vector, function(i) rhcollect(i, 1))
})

reduce<-expression(
    pre={total <- 0},
    reduce={total<-sum(total, unlist(reduce.values))},
    post={rhcollect(reduce.key, total)}
)

Job <- rhmr(
    map=map, reduce=reduce, inout=c("text", "sequence"),
    ifolder="hdfs://user/root/~", 
    ofolder="hdfs://user/root/out/~",
    jobname="word_count"
)
rhex(job)

x<-rhread("hdfs://user/root/out/~")
head(do.call("rbind", lapply(x, function(x) list(xx, x2))))

m <- expression({
    for (i in 1:length(map.values)) rhcollect(map.keyi, map.valuesi)
})

res <- rhmr(map=m, inout=c("seq", "map")
    ifolder="hdfs://user/root/out/~",
    ofolder="hdfs://user/root/out2/~",
)
rhex(res)

rhgetkey(list("whale"), "hdfs://user/root/out2/~")

R 한글

샘플링

###-----------------------------------------------------------------------------
### Sample 추출
###-----------------------------------------------------------------------------
data <- iris

#--- Index를 사용한 샘플링
#--- replace = TRUE : 복원 추출
#--- 2. 그룹수, 70% : 30%
idx <- sample(2, nrow(data), replace = TRUE, prob = c(0.7, 0.3))
train <- data[idx == 1, ]
test <- data[idx == 2, ]

#--- 데이터를 랜덤하게 섞은 후 샘플링
idx <- sample(1:nrow(data), nrow(data), replace = FALSE)
data01 <- data[idx, ]
train <- data01[1:floor(nrow(data) * 0.7), ]
test <- data01[(floor(nrow(data) * 0.7) + 1):nrow(data), ]

#--- 가장 나쁜 샘플링
idx1 <- sample(1:nrow(data), floor(nrow(data) * 0.7), replace = FALSE)
idx2 <- setdiff(1:nrow(data), idx1)
train <- data[idx1, ]
test <- data[idx2, ]
rm(list = c("idx1", "idx2")) 

#--- 분류별 샘플 추출
library(doBy)
train <- sampleBy(~ Species, frac = 0.7, replace = FALSE, data = data)
train <- sampleBy(~ Species, frac = 0.7, systematic = TRUE, data = data)   #--- 계통 추출 

#--- 층화 임의 추출
library(sampling)
#--- 비복원 단순 임의 추출, Species의 3가지 종류별로 3개, 4개, 5개 샘플 추출
idx <- strata(c("Species"), size = c(3, 4, 5), method = "srswor", data = data)
train <- getdata(data, idx)
#--- 복원 단순 임의 추출, Species의 3가지 종류별로 3개, 4개, 5개 샘플 추출
idx <- strata(c("Species"), size = c(3, 4, 5), method = "srswr", data = data)
train <- getdata(data, idx)

#--- K-Fold Cross Validation
library(cvTools)
m <- cvFolds(nrow(data), K = 10, R = 3) #--- 1/10만큼 테스트 데이터 추출
idx <- m$subset[which(m$which == 1), 1] #--- 첫번째 반복에 사용할 행 번호
train <- data[-idx, ]
test <- data[idx, ]

#--- createDataPartition
library(caret)
part <- createDataPartition(data$Species, p = 0.7)   #--- 70% 샘플링
train <- data[part$Resample1, ]
test <- data[-part$Resample1, ]

#--- 불균형을 없애는 샘플링
library(caret)
train <- upSample(subset(data, select = - Species), data$Species)
train <- downSample(subset(data, select = - Species), data$Species)

library(DMwR)
train <- SMOTE(Species ~ ., data, perc.over = 600, perc.under = 100)


pSample <- function(data, prob = c(0.7, 0.3), type = 1) {
  if (type == 1) {
    idx <- sample(2, nrow(data), replace = TRUE, prob = prob)
    train <- data[idx == 1, ]
    test <- data[idx == 2, ]
    list(train = train, test = test)  
  } else {
    idx <- sample(1:nrow(data), nrow(data), replace = FALSE)
    data01 <- data[idx, ]
    train <- data01[1:floor(nrow(data) * prob[1]), ]
    test <- data01[(floor(nrow(data) * prob[1]) + 1):nrow(data), ]
    list(train = train, test = test)  
  }
}
data <- pSample(iris, type = 2)
data$train
data$test

rm(list=ls(all=TRUE))                   #--- 작업 영역에 저장된 데이터 모두 삭제

데이터 입출력

  • 데이터 로딩
data <- read.table("data/ADV_4_2_003.csv", header=TRUE, sep=",", 
                   stringsAsFactors=FALSE, na.strings=c('NIL'), 
                   comment.char="#", encoding="UTF-8") 
load("~.RData")
  • 데이터 저장
write.table(data, file="data/data.csv", append=FALSE, quote=FALSE, sep=",", row.names=FALSE)
save(data, "~.RData)

Package

knitr

R에는 Markdown을 지원하는 markdown 이라는 패키지가 있습니다. 여기에 knitr 패키지를 사용하면 손쉽게 R 코드를 사용하여 HTML 문서를 만들수 있습니다.

  • 패키지 설치
install.packages("knitr")
install.packages("markdown")
  • Rmd 파일로 HTML 파일 생성

1. 첨부된 SampleKnitr.Rmd 파일을 RStudio의 작업 폴더로 복사 합니다.

2. RStudio에서 SampleKnitr.Rmd 파일을 오픈 합니다.

    방법 1. "File --> Open File..." 메뉴를 선택하여 파일을 오픈 합니다.
    방법 2. 작업 폴더에서 해당 파일을 마우스로 클릭하여 오픈 합니다.

Markdown001.png

3. "Knit HTML" 아이콘을 선택하여 Rmd 파일을 HTML 파일(SampleKnitr.html)로 변환 합니다. Markdown002.png

  • Markdown 문법

~.Rmd 파일에서 사용할 수 있는 markdown 문법은 간단하기 때문에
아래 SampleKnitr.Rmd 파일을 RStudio에서 HTML로 변환하여 비교를 하여 보세요.

Markdown 사용법
=


기본 문법
-

### 줄바꾸기
한 라인의 끝에 두자 이상의 공백 문자를 사용하면   
줄이 변경 됩니다.  

### 설명문
> 라인의 시작을 ">" 문자로 시작하면  
> 설명문을 표시 합니다.

### 참조 

#### 링크
http://www.jopenbusiness.com/  
[오픈소스 비즈니스 컨설팅](http://www.jopenbusiness.com/)

[오픈소스 비즈니스 컨설팅][id1].  
[id1]: http://www.jopenbusiness.com/ "Title" 

#### 이미지
![오픈소스 비즈니스 컨설팅](h ttp://www.jopenbusiness.com/mediawiki/images/2/28/Namecard_10.png)

![오픈소스 비즈니스 컨설팅][id2]
[id2]: h ttp://www.jopenbusiness.com/mediawiki/images/2/28/Namecard_10.png "Title"


### 글씨체 등
*이탤릭체*  
**볼드체**  
위 첨자^2  
~~삭제된 문장~~


목록
-

### 순서 없는 목록
* 항목 1
* 항목 2
 * 항목 2-1
 * 항목 2-2

### 순서 있는 목록
1. 항목 1
2. 항목 2
 1. 항목 2-1
 2. 항목 2-2

### 테이블
제목 1 | 제목 2
----------|----------
항목 11 | 항목 21
항목 12 | 항목 22


R 코드 실행
-

### 코드 블럭 추가
```{r}
#--- R 코드 추가, R 코드 실행 결과 표시
summary(iris)
```

```
#--- R 코드 추가
summary(iris)
```

### 인라인 코드 추가
R 코드 실행 결과 추가 : iris의 dimension은 `r dim(iris)` 입니다.  
R 코드만 추가 : iris의 dimension은 `dim(iris)` 입니다.
  • knitr 패키지 사용법
library(knitr)
library(markdown)

knit("~.Rmd")
markdownToHTML("~.md", "~.html")
  • 참고 문헌

dplyr

  • dplyr 패키지
library(dplyr) 
data(iris)
함수 상세
tbl_df()
  • data.frame 데이터를 data.frame table 형태의 데이터로 변환 합니다.
  • print() 시 한 페이지에 해당하는 데이터만 보여주는 기능외에는 특별한 기능은 없습니다.
(data <- tbl_df(iris))
filter()
  • 데이터 추출
  • 조건 : & - AND (,로 구분시), | - OR
  • data <- filter(data, 조건1, 조건2)
(data <- filter(data, Species == 'setosa' | Species == 'versicolor'))
arrange()
  • 정렬 : desc() 사용시 내림차순으로 정렬
  • data <- arrange(data, field1, desc(field2))
(data <- arrange(data, Sepal.Length))
select()
  • 열 추출 (- 사용시 추출에서 제외할 열 지정)
  • data <- select(data, field1, -field2)
(data <- select(data, Sepal.Length, Sepal.Width, Species))
mutate()
  • 열 추가 : 새로 추가된 열은 다음 계산식에서 사용 가능
  • data <- mutate(data, newField = 계산식)
(data <- mutate(data, Total = Sepal.Length + Sepal.Width))
group_by()
  • 그룹화 : field1의 값으로 그룹화
  • data <- group_by(data, field1)
(data <- group_by(data, Species))
summarise()
  • 집계 : group_by()로 지정한 그룹을 기준으로 집계
  • summarise(data, t1 = 수식, t2 = 수식)
summarise(data, meanLength = mean(Sepal.Length), meanWidth = mean(Sepal.Width))
  • dplyr는 chain 형태로도 사용할 수 있습니다.
  • data %.% 함수1 %.% 함수2 %.% 함수3
data(iris)
(data <- iris)
(data <- data %.% filter(Species == 'setosa' | Species == 'versicolor')
              %.% arrange(Sepal.Length)
              %.% select(Sepal.Length, Sepal.Width, Species)
              %.% mutate(Total = Sepal.Length + Sepal.Width)
              %.% group_by(Species)
              %.% summarise(meanLength = mean(Sepal.Length), meanWidth = mean(Sepal.Width))
)

Classification

분류 분석

  • 분류 분석 개요
#--- MASS           : m <- lda(Species ~ ., data=train); pred$class
#--- MASS           : m <- qda(Species ~ ., data=train); pred$class
#--- party          : m <- ctree(Species ~ ., data=train); pred
#--- party          : m <- cforest(Species ~ ., data = train, control = cforest_unbiased(mtry = 3)); pred
#--- randomForest   : m <- randomForest(Species ~ ., data = train, ntree = 100, proximity = TRUE); pred

#--- rpart          : m <- rpart(Species ~ ., data = train, control = rpart.control(minsplit = 10)))
#---                  predict(result$m, result$train)
#---                  class가 숫자일 경우 사용
  • 분류 분석
###--- 데이터 준비
data <- iris
idx <- sample(2, nrow(data), replace = TRUE, prob = c(0.7, 0.3))
train <- data[idx == 1, ]
test  <- data[idx == 2, ]
cls <- "Species"
formula = Species ~ .

###--- 분류 분석 (아래에서 한가지 선택)
library(MASS)
m <- lda(formula, data=train)   #--- Linear Discriminant Analysis, 선형 판별 분석

library(MASS)
m <- qda(formula, data=train)   #--- Quadratic Discriminant Analysis, 이차 판별 분석

library(party)
m <- ctree(formula, data=train)

library(party)
m <- cforest(formula, data = train, control = cforest_unbiased(mtry = 3))

library(randomForest)
m <- randomForest(formula, data = train, ntree = 100, proximity = TRUE)
#--- ntree = 100 : 최대 트리개수 100개
#--- proximity = TRUE : 다양한 트리분할 시도

###--- data로부터 분류 산정
pred <- predict(m)                #--- cforest
pred <- predict(m, train)         #--- ctree, randomForest
pred <- predict(m, train)$class   #--- lda, qda 

###--- 분류 분석 시각화
plot(m)                           #--- lda, ctree, randomForest
plot(m, type = "simple")          #--- ctree

###--- 변수 및 분류 분석 평가
margin(m, data[, cls])            #--- randomForest
varImpPlot(m)                     #--- randomForest
importance(m)                     #--- randomForest

table(pred, train[, cls])  #--- 예측값과 실제값의 비교
correct <- pred == train[, cls]
print(paste(round(mean(correct) * 100, 2), "% of predicted classifications correct for train", sep=""))

###--- 분류 분석을 통한 예측
pred <- predict(m, newdata = test)         #--- ctree, cforest, randomForest
pred <- predict(m, newdata = test)$class   #--- lda, qda
table(pred, test[, cls])                   #--- 예측값과 실제값의 비교
correct <- pred == test[, cls]
print(paste(round(mean(correct) * 100, 2), "% of predicted classifications correct for test", sep=""))

Estimation

formula

  • 문자열을 사용하여 R Language에서 제공하는 formula 생성하기
formula("문자열")

회귀분석

###--- 데이터 준비
data <- iris
left <- "Sepal.Length"
upper = "~ Sepal.Width + Petal.Length + Petal.Width"

###--- 수작업으로 회귀 분석, 유의한 결과가 나올 때까지 formula를 변경해 가면서 적용
plot(data)                              #--- 데이터의 분포를 보고 초기 회귀식을 작성

m <- lm(formula(paste(left, upper)), data = data)   
#--- 회귀식 : Sepal.Length = 1.8560 + 0.6508 * Petal.Length + 0.7091 * v - 0.5565 * Petal.Width
#--- formula(paste(left, upper)) 부분을 원하는 formula로 변경해 가면서 회귀식을 작성 하세요.

summary(m)
#--- F 통계량 (F-statistic)
#---   p-value : 유의수준 5%하에서 0.05보다 작으면 통계적으로 유의함
#--- 결정 계수 (Multiple R-Squared) : 회귀식이 데이터를 설명하는 정도
#---   수정 결정 계수 (Adjusted R-squared)
#--- 유의수준 (Pr(>|t|)) : 회귀계수들의 p-value, 0.05보다 작으면 통계적으로 유의함
#---   후진제거법으로 변수 선택시, 유의수준이 높은 변수부터 제거 합니다.

###--- 자동으로 회귀 분석
step(lm(formula(paste(left, "~ 1")), data=data), scope=list(lower=~ 1, upper=formula(upper)),  direction="forward")    #--- 전진선택법 
step(lm(formula(paste(left, upper)), da ta=data), scope=list(lower=~ 1, upper=formula(upper)), direction="backward")   #--- 후진소거법
step(lm(formula(paste(left, "~ 1")), data=data), scope=list(lower=~ 1, upper=formula(upper)), direction="both")       #--- 단계적방법

시계열 분석

###--- 데이터 준비
(data <- c(60, 43, 67, 50, 56, 42, 50, 65, 68, 43, 
           65, 34, 47, 34, 49, 41, 13, 35, 53, 56,
           16, 43, 69, 59, 48, 59, 86, 55, 68, 51,
           33, 49, 67, 77, 81, 67, 71, 81, 68, 70,
           77, 56))
(data <- ts(data))                      #--- 데이터를 시계열 자료 형식으로 변환

###-----------------------------------------------------------------------------
#--- 자동으로 시계열 모형 선택
library(forecast)
auto.arima(data)                        #--- 자동으로 최적의 ARIMA 모형을 제시

###-----------------------------------------------------------------------------
#--- 수동으로 시계열 모형 선택
plot(data)                              #--- 각 요인(추세, 순환, 계절, 불규칙)을 시각적으로 확인
data01 <- data 

#--- 평활 : 들쭉날쭉한 시계열자료 값을 평탄한 값으로 변환
#--- 이동평균법, 지수평활법 등
library(TTR)                            #--- 평활
plot(data01)
plot(SMA(data01, n = 2))                #--- 2년마다 평균을 낸 데이터로 변환
plot(SMA(data01, n = 3))                #--- 3년마다 평균을 낸 데이터로 변환
plot(SMA(data01, n = 4))                #--- 4년마다 평균을 낸 데이터로 변환
plot(SMA(data01, n = 5))                #--- 5년마다 평균을 낸 데이터로 변환
plot(SMA(data01, n = 6))                #--- 6년마다 평균을 낸 데이터로 변환
plot(SMA(data01, n = 7))                #--- 7년마다 평균을 낸 데이터로 변환
plot(SMA(data01, n = 8))                #--- 8년마다 평균을 낸 데이터로 변환
plot(SMA(data01, n = 9))                #--- 9년마다 평균을 낸 데이터로 변환
(data01 <- SMA(data01, n = 3))          #--- n의 값은 위 그래프를 보고 판단

#--- 정상형 시계열 자료로 만들기 위해서 차분을 진행
plot(data01)                              
plot(diff(data01, differences = 1))     #--- 1차 차분 (difference), ARIMA(p, 1, q) 모델
plot(diff(data01, differences = 2))     #--- 2차 차분 (difference), ARIMA(p, 2, q) 모델
plot(diff(data01, differences = 3))     #--- 3차 차분 (difference), ARIMA(p, 3, q) 모델
plot(diff(data01, differences = 4))     #--- 4차 차분 (difference), ARIMA(p, 4, q) 모델
plot(diff(data01, differences = 5))     #--- 5차 차분 (difference), ARIMA(p, 5, q) 모델
plot(diff(data01, differences = 6))     #--- 6차 차분 (difference), ARIMA(p, 6, q) 모델
plot(diff(data01, differences = 7))     #--- 7차 차분 (difference), ARIMA(p, 7, q) 모델
plot(diff(data01, differences = 8))     #--- 8차 차분 (difference), ARIMA(p, 8, q) 모델
plot(diff(data01, differences = 9))     #--- 9차 차분 (difference), ARIMA(p, 9, q) 모델
(data01 <- diff(data01, differences = 2))   #--- differences의 값은 위 그래프를 보고 판단

#--- 부분자기함수(PACF)
(pacf(data01, lag.max=10))              #--- 부분자기함수(PACF)
#--- lag = 0인 지점은 판단에서 제외
#--- lag = 만약 4에서 절단점을 가질 경우 AR(3) 모형
 
#--- 자기상관함수(ACF)
(acf(data01, lag.max=10, Plot=TRUE))    #--- 자기상관함수(ACF)
#--- lag = 0인 지점은 판단에서 제외
#--- lag = 만약 2에서 절단점을 가질 경우 MA(1) 모형
 
###-----------------------------------------------------------------------------
#--- 모델 보정 (fitting) 및 예측
(data02 <- arima(data, order=c(2, 0, 0)))

library(forecast)
(data03 <- forecast.Arima(data02, h=20))#--- 20개 데이터 예측
plot(data03)                            #--- 신뢰구간 80%와 95%에서 예측값 표시

###-----------------------------------------------------------------------------
#--- 분해 시계열 모형
plot(data)                              #--- 각 요인(추세, 순환, 계절, 불규칙)을 시각적으로 확인

m <- decompose(data)                    #--- 시계열에 영향을 주는 일반적인 요인을 시계열에서 분리              
m$x                                     #--- 원본 데이터
m$trend                                 #--- 추세요인 (Trend factor, 경향요인)
m$seasonal                              #--- 계절요인 (Seasonal factor)
m$random                                #--- 불규칙요인 (Irregular factor)
plot(m)                                 #--- 추세요인, 계절요인, 불규칙요인이 포함된 그래프

plot(data - m$trend)                    #--- 추세요인을 제거한 그래프
plot(data - m$trend - m$seasonal)       #--- 추세요인과 계절요인을 제거한 그래프
  • 참고 문헌

Clustering

군집 분석

  • 군집 분석 개요
#--- stats          : m <- kmeans(data, centers = 3); m$cluster
#--- stats          : m <- hclust(dist(data, method = "euclidean")^2, method = "ward")
#---                  pred <- cutree(m, k = 3)
#--- cluster        : m <- pam(data, 3), m$cluster
#--- cluster        : m <- fanny(data, 2), m$cluster

#--- fpc            : m <- dbscan(data, eps = 0.5, MinPts = 5); m$cluster
#---                  pred <- predict(m, data)
#--- class          : m <- SOM(data, somgrid(topo = "hexagonal"))
#---                  m <- SOM(data, somgrid(topo = "hexagonal"), 
#---                           alpha = list(seq(0.05, 0, len = 1e4), seq(0.02, 0, len = 1e5)), 
#---                           radii = list(seq(8, 1, len = 1e4), seq(4, 1, len = 1e5)))
  • 군집 분석
#--- 데이터 준비
data <- iris[, 1:4]      #--- 원본 데이터
cls  <- iris[, 5]        #--- 원본 데이터의 분류
group <- 3   #--- 군집수, Clustering - 군집수 결정 참조

#--- 군집 분석 (아래에서 한가지 선택)
library(stats)
m <- kmeans(data, group) #--- K-평균군집

library(cluster)
m <- pam(data, group) #--- PAM (Partitioning Around Medoids)

library(cluster)
m <- fanny(data, group) #--- Fuzzy Clustering

library(fpc)
m <- dbscan(data, eps = 0.5), MinPts = 5) #--- Density-based Clustering
 #--- eps : Maximum distance
 #--- MinPts : 최소 데이터 개수
 #--- eps 범위내에 MinPts 개수의 데이터가 있으면 군집으로 분류 

#--- data로부터 군집 산정
pred <- m$cluster
  • 시각화를 위해서는 아래 방식을 사용해 보세요.
  plot(m)                         #--- pam, fanny
 plot(data, col = pred)     #--- kmeans, pam, fanny
 plot(m, data)                 #--- dbscan
 plotcluster(data, pred)   #--- dbscan
  • 군집 분석의 제대로 되고 있는지 확인 하려면 아래와 같이 수작업을 하세요.
table(pred, cls)
#--- predStr : 숫자로 표시된 pred를 문자로 변경하기 위해 사용
#--- data 별로 다르므로 매번 수작업이 필요 합니다.
predStr <- c("setosa", "versicolor", "virginica")   
print(paste(round(mean(predStr[pred] == cls) * 100, 2), "% of predicted clusters correct", sep=""))


참고 문헌

군집의 개수 산정

###-----------------------------------------------------------------------------
### 군집의 개수 산정
###     data        : 원본 데이터
###     groups      : 확인할 군집의 개수 범위
### 그래프의 경사가 완만해 지는 지점이 군집의 개수 입니다
###-----------------------------------------------------------------------------
findCluster = function(data = iris[, 1:4], groups = 1:10) {
  models <- 0
  for (i in groups) {
    models[i] <- sum(kmeans(data, centers = i)$withinss)
  }
  plot(groups, models, type = "b", main = "군집의 개수 산정",
       xlab = "군집의 수", ylab = "군집간 거리 제곱합")
}
findCluster()

Association

연관 분석

###-----------------------------------------------------------------------------
### 연관 분석
###     트랜잭션 데이터 : items, transactionID, TimeStamp
###         items : 트랜잭션(rows)에 속한 항목(columns)의 이름과 값
###         transactionID : 트랜잭션 아이디 (rows 이름)
###         TimeStamp : 트랜잭션이 발생한 시간
###-----------------------------------------------------------------------------

###--- 데이터 준비
data(Epub, package = "arules")
(data <- Epub)

length(data)                            #--- transactions 데이터 개수
size(data[1])                           #--- 첫번째 트랜잭션의 항목수

data[1]                                 #--- 첫번째 트랜잭션 데이터 조회
inspect(data[1])                        #--- 첫번째 트랜잭션 데이터 상세 조회
transactionInfo(data[1])                #--- transactions 데이터 조회
itemsetInfo(data[1])                    #--- 첫번째 트랜잭션 아이디
itemInfo(data[1])                       #--- 모든 항목의 목록 

summary(data[1])                        #--- 첫번째 트랜잭션 데이터 요약
summary(data)                           #--- 트랜잭션 데이터 요약

as(data, "list")[1]                     #--- list로 변환한 후 첫번째 데이터 조회
format(as.POSIXlt(transactionInfo(data[1])"TimeStamp"), "%Y-%m-%d %H:%M:%S")   #--- TimeStamp를 문자열로 변환

#--- support = 0.1 : 최소지지도 10% 이상
#--- cex.names = 0.8 : 글씨 크기
itemFrequencyPlot(data, support = 0.1, cex.names = 0.8)   #--- 항목별 빈도수

#--- support = 0.01 : 최소지지도 1% 이상, 최소신뢰도 60% 이상인 연관 규칙 탐색
(m <- apriori(data, parameter = list (support = 0.01, confidence = 0.6)))
summary(m)
length(m)                               #--- 연관규칙의 개수
inspect(m[1:10])                        #--- 10개의 연관규칙 조회
#--- 연관규칙 : lhs 발생 후에 rhs 발생
#--- support : 지지도, confidence : 신뢰도, lift. 향상도
inspect(sort(m[1:10]))                      #--- 지지도 내림 차순으로 정렬후 조회
inspect(sort(m[1:10], by = "confidence"))   #--- 신뢰도 내림 차순으로 정렬후 조회
inspect(sort(m[1:10], by = "lift"))         #--- 향상도 내림 차순으로 정렬후 조회

#--- rhs가 "income=small"이고 향상도(lift)가 1.2 이상이 연관규칙 추출
(small <- subset(m, subset = rhs %in% "income=small" & lift > 1.2))
inspect(small[1:10])                    #--- 10개의 연관규칙 조회

#--- rhs가 "income=large"이고 향상도(lift)가 1.2 이상이 연관규칙 추출
(large <- subset(m, subset = rhs %in% "income=large" & lift > 1.2))
inspect(large[1:10])                    #--- 10개의 연관규칙 조회

write(m[1:10], file="m.txt", sep = "\t", col.names = NA)   #--- 연관규칙을 파일로 저장
library("pmml")
saveXML(pmml(m[1:10]), file = "m.xml")  #--- 연관규칙을 XML로 변환한 후, XML 파일로 저장

Optimization

loSolve

#--- "판매 수익 최대화"
#--- 제품        : A, B, C, D
#--- 목적 함수   : 4 * A + 6 * B + 7 * C + 8 * D (최대 수익)
#--- 제약식
#---   혼합 공정 시간 : 1 * A + 1.5 * B + 2 * C + 3 * D <= 800시간
#---   주형 공정 시간 : 1.5 * A + 2 * B + 2 * C + 3 * D <= 1000시간
#---   검사 공정 시간 : 0.5 * A + 0.6 * B + 1 * C + 1 * D <= 340시간
#---   B <= A         : 1 * A - 1 * B + 0 * C + 0 * D >= 0
library(lpSolve)
f.obj <- c(4, 6, 7, 8)                  #--- 목적함수 계수
(f.con <- matrix(c(
  1, 1.5, 2, 3,                      
  1.5, 2, 2, 3, 
  0.5, 0.6, 1, 1, 
  1, -1, 0, 0), nrow = 4, byrow = TRUE))#--- 제약식 행렬
(f.dir <- c("<=", "<=", "<=", ">="))    #--- 제약식 부등호
(f.rhs <- c(800, 1000, 340, 0))         #--- 제약식 우변값 

lp("max", f.obj, f.con, f.dir, f.rhs)   #--- 목적함수 값
lp("max", f.obj, f.con, f.dir, f.rhs)$solution   #--- 최적의 해

lp("max", f.obj, f.con, f.dir, f.rhs, compute.sens = TRUE)$duals
lp("max", f.obj, f.con, f.dir, f.rhs, compute.sens = TRUE)$duals.from
lp("max", f.obj, f.con, f.dir, f.rhs, compute.sens = TRUE)$duals.to
lp("max", f.obj, f.con, f.dir, f.rhs, compute.sens = TRUE)$sens.coef.from   #--- 목적식 계수의 민감도 분석 - 하한
lp("max", f.obj, f.con, f.dir, f.rhs, compute.sens = TRUE)$sens.coef.to     #--- 목적식 계수의 민감도 분석 - 상한

lpSolveAPI

#--- "판매 수익 최대화"
#--- 제품        : A, B, C, D
#--- 목적 함수   : 4 * A + 6 * B + 7 * C + 8 * D (최대 수익)
#--- 제약식
#---   혼합 공정 시간 : 1 * A + 1.5 * B + 2 * C + 3 * D <= 800시간
#---   주형 공정 시간 : 1.5 * A + 2 * B + 2 * C + 3 * D <= 1000시간
#---   검사 공정 시간 : 0.5 * A + 0.6 * B + 1 * C + 1 * D <= 340시간
#---   B <= A         : 1 * A - 1 * B + 0 * C + 0 * D >= 0
library("lpSolveAPI")
m <- make.lp(0, 4)                      #--- 4는 변수의 개수
lp.control(m, sense="max")              #--- 최대값 구하기
set.objfn(m, c(4, 6, 7, 8))             #--- 목적 함수
add.constraint(m, c(1, 1.5, 2, 3), "<=", 800)     #--- 혼합 공정 시간의 제약식
add.constraint(m, c(1.5, 2, 2, 3), "<=", 1000)    #--- 주형 공정 시간의 제약식
add.constraint(m, c(0.5, 0.6, 1, 1), "<=", 340)   #--- 검사 공정 시간의 제약식
add.constraint(m, c(1, -1, 0, 0), ">=", 0)        #--- B <= A 인 제약식
m                                       #--- 등록된 목적 함수와 제약식 보기

solve(m)                                #--- 최적해 구하기
get.objective(m)                        #--- 최적해
get.variables(m)                        #--- 최적해일 때, 변수들의 값

Text Mining

  • 텍스트 마이닝
library(tm)
getReaders()                            #--- Reader의 종류 확인
getTransformations()                    #--- tm_map용 함수 목록

###-----------------------------------------------------------------------------
### Corpus 생성
(lines <- c("You're awe some and I love you", 
            "I hate and hate and hate. So angry. Die!",
            "Impressed and amazed: you are peer less in your achievement of unparalleled mediocrity.", 
            "I love you"))
(doc <- Corpus(VectorSource(lines))) 

#--- XML 파일 읽기
#--- C:/Program Files/R/R-3.0.3/library/tm/texts/crude/ 폴더 지정
(folder <- system.file("texts", "crude", package = "tm"))
(doc <- Corpus(DirSource(folder), readerControl = list(reader = readReut21578XML)))
rm(folder)

###-----------------------------------------------------------------------------
### Corpus 조회
summary(doc)
doc1                                #--- 첫번째 문서 조회
inspect(doc[1])                         #--- 첫번째 문서 조회 

#writeCorpus(doc)                        #--- Corpus 저장
#writeCorpus(doc[1], filenames="01.txt") #--- 첫번째 Corpus 저장

###-----------------------------------------------------------------------------
### Corpus 변환
(doc <- tm_map(doc, as.PlainTextDocument))1                #--- XML 문서를 Text로 변환
(doc <- tm_map(doc, stripWhitespace))1                     #--- 두개 이상의 공백을 하나의 공백으로 치환
(doc <- tm_map(doc, tolower))1                             #--- 소문자로 변환
(doc <- tm_map(doc, removePunctuation))1                   #--- 구두점 삭제
(doc <- tm_map(doc, removeWords, stopwords("english")))1   #--- Stopword (조사, 띄어쓰기, 시제 등)를 제거하고 표준화
(doc <- tm_map(doc, stripWhitespace))1                     #--- 두개 이상의 공백을 하나의 공백으로 치환
(doc <- tm_map(doc, stemDocument))1                        #--- 어근만 추출
#(doc <- tm_map(doc, removeNumbers))1                       #--- 숫자 삭제
#removeURL <- function(x) gsub("httpalnum:*", "", x)
#(doc <- tm_map(doc, removeURL))1                           #--- URL 삭제
#rm(removeURL)
#(doc <- tm_map(doc, gsub, pattern = "diamond", replacement = "aaa"))1   #--- 문자열 치환

#(doc <- tm_map(doc, grep, pattern = "diamond"))1           #--- diamond가 포함된 라인 번호 반환
#(doc <- tm_map(doc, stemCompletion, dictionary = doc))1    #--- 어근으로 원래 단어 유추
#    (a <- c("mining", "miners", "mining"))
#    (b <- stemDocument(a))
#    (d <- stemCompletion(b, dictionary=a))

###-----------------------------------------------------------------------------
### DocumentTermMatrix / TermDocumentMatrix
(m <- DocumentTermMatrix(doc))          #--- DocumentTermMatrix 생성
#--- Non-/sparse entries : 단어가 있는 entry / 단어가 없는 entry
#--- Sparsity : 문서별 단어 중 한번도 사용하지 않은 비율
(m <- removeSparseTerms(m, 0.70))       #--- Sparsity가 70% 이상인 경우 삭제

dic <- c("prices", "crude", "oil")      #--- 여기 기술된 단어를 포함하는 모델 생성
(m <- DocumentTermMatrix(doc, list(dictionary = dic)))

(m <- TermDocumentMatrix(doc))          #--- TermDocumentMatrix 생성
(m <- t(m))                             #--- DocumentTermMatrix로 변환
(data <- as.matrix(m))                  #--- DocumentTermMatrix를 matrix로 변환

m$nrow                                  #--- 문서 (document) 개수 / 단어 (term) 개수
m$ncol                                  #--- 단어 (term) 개수 / 문서 (document) 개수
m$dimnames                              #--- 문서 (document)와 단어 (term) 목록
m$dimnames$Docs
m$dimnames$Terms
m$i                                     #--- 문서 (document) 인덱스 / 단어 (term) 인덱스
m$j                                     #--- 단어 (term) 인덱스 / 문서 (document) 인덱스
m$v                                     #--- m$i[0] 문서에서 m$j[0] 단어의 발생 빈도
                                        #--- m$j[0] 문서에서 m$i[0] 단어의 발생 빈도

inspect(m)                              #--- 단어의 분포를 확인
inspect(m[1:2, 3:5])                    #--- 처음 2개 문서의 3번째에서 5번째 단어의 분포를 확인

findFreqTerms(m, 10)                    #--- 10회 이상 사용된 단어 표시
findFreqTerms(m, 10, 15)                #--- 10회 이상, 15회 이하 사용된 단어 표시
findAssocs(m, "oil", 0.65)              #--- "oil" 단어와 연관성(같이 사용될 확률)이 65% 이상이 단어를 표시 

rm(dic)
  • 단어의 빈도 분석
###-----------------------------------------------------------------------------
### 단어의 빈도 분석
(frequency <- colSums(data))            #--- 단어별 발생 건수 계산
(frequency <- subset(frequency, frequency >= 20))   #--- 10건 이상 발생한 단어 추출

#library(gdata)
(frequency <- as.data.frame(available.packages()))  #--- 패키지 목록 추출
(frequency <- gdata::trim(unlist(strsplit(as.character(frequency$Depends), ','))))   #--- 패키지 의존 정보 추출
(frequency <- gsub('[ \\(].*|\\n', , frequency))  #--- 다양한 문자 부호 제거
(frequency <- table(frequency))         #--- 단어의 빈도수 테이블

library(ggplot2)
barplot(frequency, las = 2)

library(wordcloud)                      #--- 워드 클라우드
wordcloud(names(frequency), as.numeric(frequency), colors = c("green", "red"))
wordcloud(names(frequency), log(as.numeric(frequency)), colors = c("green", "red"))

(colors <- gray((frequency + 10) / (max(frequency) + 10)))
wordcloud(words = names(frequency), freq = frequency, min.freq = 2, random.order = F, colors = colors)
rm(frequency, colors)

rm(list=ls(all=TRUE))                   #--- 작업 영역에 저장된 데이터 모두 삭제
  • 문서의 군집 분석
###-----------------------------------------------------------------------------
### 문서의 군집 분석
(fit <- hclust(dist(scale(data)), method = "ward"))
plot(fit)
rect.hclust(fit, k = 3)                 #--- 5개의 그룹으로 구분
(groups <- cutree(fit, k = 3))          #--- 문서별로 그룹 지정
rm(fit, groups)


k <- 3
(kmeansResult <- kmeans(m, k))          #--- k-평균 군집 모형
for (i in 1:k) {
  cat(paste("cluster", i, ": ", sep = ""))
  s <- sort(kmeansResult$centers[i,], decreasing = T)
  cat(names(s), "\n")
}


library(fpc)
(pamResult <- pamk(m, metric = "manhatttan"))
(k <- pamResult$nc)

(pamResult <- pamResult$pamobject)
for (i in 1:k) {
  cat(paste("cluster", i, ": "))
  cat(colnames(pamResult$medoids)[which(pamResult$medoids[i, ] == 1)], "\n")
}

plot(pamResult, color = F, labels = 4, lines = 0,   #--- 오류가 발생함
     cex = .8, col.clus = 1, col.p = pamResult$clustering)

rm(list=ls(all=TRUE))                   #--- 작업 영역에 저장된 데이터 모두 삭제
  • 감성 분석
###-----------------------------------------------------------------------------
### 감성 분석
###-----------------------------------------------------------------------------
#--- 문장을 입력받아 문장과 점수를 반환
#--- 점수 = 긍정 점수 - 부정 점수
#---     긍정 점수 : 긍정 단어 (pos.words)가 포함된 개수
#---     부정 점수 : 부정 단어 (neg.words)가 포함된 개수
(pos.word <- scan("data/ADV_4_5_positiveWords.txt", what = "character", comment.char = ";"))   #--- 긍정 단어
(pos.words <- c(pos.word, "upgade"))
(neg.word <- scan("data/ADV_4_5_negativeWords.txt", what = "character", comment.char = ";"))   #--- 부정 단어
(neg.words <- c(neg.word, "wait", "waiting"))

scores <- function(sentences, pos.words, neg.words, .progress='none') { #--- 점수와 문장을 반환
  require(plyr)
  require(stringr) 
  scores = laply(
    sentences, 
    function(sentence, pos.words, neg.words) {
      sentence = gsub('punct:', , sentence)   #--- 구두점 삭제
      sentence = gsub('cntrl:', , sentence)   #--- 특수기호 삭제
      sentence = gsub('\\d+', , sentence)  	       #--- 숫자 삭제
      sentence = tolower(sentence)                   #--- 소문자로 변환
      
      word.list = str_split(sentence, '\\s+')        #--- 하나 이상의 공백으로 단어 추출
      words = unlist(word.list)                      #--- list를 벡터로 변환
      
      pos.matches = match(words, pos.words)          #--- 긍정의 점수 계산 (긍정 단어와 매핑되는 개수 산정)
      pos.matches = !is.na(pos.matches)
      neg.matches = match(words, neg.words)          #--- 부정의 점수 계산 (부정 단어와 매핑되는 개수 산정)
      neg.matches = !is.na(neg.matches)     
      score = sum(pos.matches) - sum(neg.matches)
      return (score)
    }, 
    pos.words, neg.words, .progress=.progress
  )
  scores.df = data.frame(score=scores, text=sentences)
  return(scores.df)
}


(result <- scores(lines, pos.words, neg.words))
library(ggplot2)
qplot(result$score)
hist(result$score)
  • 연관 분석
###-----------------------------------------------------------------------------
### 연관 분석
###-----------------------------------------------------------------------------
library(KoNLP)
extractNoun("연습을 해보고자 한다. 명사가 잘 추출되는지 보자. 빨간색으로 글씨를 쓴다.")
sapply("연습을 해보고자 한다. 명사가 잘 추출되는지 보자. 빨간색으로 글씨를 쓴다.", extractNoun)
system.time(nouns <- sapply(head(lines, 1000), extractNoun, USE.NAMES = FALSE))
rm(nouns)


(data <- Map(extractNoun, lines))       #--- 각 문장에서 명사 추출 (문장 -> 문자열 목록)
(data <- unique(data))1             #--- 라인별 데이터를 unique하게
(data <- sapply(data, unique))1     #--- 각 라인내 데이터를 unique하게

(data <- sapply(data, function(x) {     #--- 2자 이상 4자 이하의 한글 단어 추출
  Filter(function(y) {
    nchar(y) <= 4 && nchar(y) > 1 && is.hangul(y)
  },
  x)
}))
(data <- Filter(function(x) { length(x) >= 2 }, data))   #--- 단어가 2개 이상 포함된 문장만 추출
(names(data) <- paste("Tr", 1:length(data), sep = ""))   #--- 데이터에 행 이름 지정
data                                    #--- 문장별 단어 목록 

library(arules)
(data <- as(data, "transactions"))
(dataTab <- crossTable(data))

#--- 빈도수 5%, 같이 있을 확률이 10%인 단어 목록 추출
#---     최소지지도 5% 이상, 최소신뢰도 10% 이상인 연관 규칙 탐색
(m <- apriori(data, parameter = list(supp = 0.05, conf = 0.1)))   
inspect(m)

rm(list=ls(all=TRUE))                   #--- 작업 영역에 저장된 데이터 모두 삭제

Social Network Analytics

###-----------------------------------------------------------------------------
### 데이터 준비

#data <- read.table("http://sna.stanford.edu/sna_R_labs/data/Krack-High-Tec-edgelist-Advice.txt")
#write.table(data, file="data/ADV_4_5_001.csv", append=FALSE, quote=FALSE, sep=",", row.names=FALSE)
(data01 <- read.table("data/ADV_4_5_001.csv", header=TRUE, sep=",", 
                      stringsAsFactors=FALSE, na.strings=c('NIL'), comment.char="#", 
                      fileEncoding="UTF-8", encoding="CP949"))
colnames(data01) <- c("ego", "alter", "advice_tie")

#data <- read.table("http://sna.stanford.edu/sna_R_labs/data/Krack-High-Tec-edgelist-Friendship.txt")
#write.table(data, file="data/ADV_4_5_002.csv", append=FALSE, quote=FALSE, sep=",", row.names=FALSE)
(data02 <- read.table("data/ADV_4_5_002.csv", header=TRUE, sep=",", 
                      stringsAsFactors=FALSE, na.strings=c('NIL'), comment.char="#", 
                      fileEncoding="UTF-8", encoding="CP949"))
colnames(data02) <- c("ego", "alter", "friendship_tie")

#data <- read.table("http://sna.stanford.edu/sna_R_labs/data/Krack-High-Tec-edgelist-ReportsTo.txt")
#write.table(data, file="data/ADV_4_5_003.csv", append=FALSE, quote=FALSE, sep=",", row.names=FALSE)
(data03 <- read.table("data/ADV_4_5_003.csv", header=TRUE, sep=",", 
                      stringsAsFactors=FALSE, na.strings=c('NIL'), comment.char="#", 
                      fileEncoding="UTF-8", encoding="CP949"))
colnames(data03) <- c("ego", "alter", "reports_to_tie")

#data <- read.csv("http://sna.stanford.edu/sna_R_labs/data/Krack-High-Tec-Attributes.csv", header = T)
#write.table(data, file="data/ADV_4_5_004.csv", append=FALSE, quote=FALSE, sep=",", row.names=FALSE)
(data04 <- read.table("data/ADV_4_5_004.csv", header=TRUE, sep=",", 
                      stringsAsFactors=FALSE, na.strings=c('NIL'), comment.char="#", 
                      fileEncoding="UTF-8", encoding="CP949"))

which(data01$ego != data02$ego)         #--- 두 데이터의 ego가 동일한지 검사
which(data01$ego != data03$ego)         #--- 두 데이터의 ego가 동일한지 검사
which(data01$alter != data02$alter)     #--- 두 데이터의 alter가 동일한지 검사
which(data01$alter != data03$alter)     #--- 두 데이터의 alter가 동일한지 검사

#(data <- cbind(data01, data02$friendship_tie, data03$reports_to_tie))
#names(data)[4:5] <- c("friendship_tie", "reports_to_tie")
(data <- data.frame(ego = data01[, 1], alter = data01[, 2], advice_tie = data01[, 3],
                    friendship_tie = data02[, 3], reports_to_tie = data03[, 3]))
(data <- subset(data, (advice_tie > 0 | friendship_tie > 0 | reports_to_tie > 0)))
(attrs <- cbind(1:length(data04[, 1]), data04))
rm(list = c("data01", "data02", "data03", "data04"))

###-----------------------------------------------------------------------------
### 그래프 생성
library(igraph)
#(m <- graph.data.frame(data))          #--- 방향 그래프 생성
(m <- graph.data.frame(d = data, directed = TRUE, vertices = attrs))   
#--- 그래프
#---     Node : vertex, link : edge
#---     첫번째 컬럼이 두번째 컬럼을 가르키는 방향성 그래프 생성
#---     세번째 이상의 컬럼은 edge의 attribute로 추가됨
#--- directed : TRUE. 방향 그래프, FALSE. 무방향 그래프
#--- vertices : vertex의 속성, 첫번째 열이 vertices의 아이디
#(m <- as.undirected(m, mode = "collapse"))   #--- 무방향 그래프로 변환
#(m <- as.directed(m))                        #--- 방향 그래프로 변환 

#--- 방향성을 삭제한 인접(adjacency) 매트릭스 생성
#(m <- graph.adjacency(data, weight = T, mode = "undirected"))   

#(m <- simplify(m))                      #--- 그래프 단순화
m$layout <- layout.fruchterman.reingold(m)   #--- Fruchterman-Reingold Layout 


summary(m)

vcount(m)                               #--- Vertex 개수
V(m)                                    #--- Vertex
get.vertex.attribute(m, "name")         #--- Vertex 이름
get.vertex.attribute(m, "AGE")          #--- Vertex attribute
get.vertex.attribute(m, "TENURE")       #--- Vertex attribute
get.vertex.attribute(m, "LEVEL")        #--- Vertex attribute
get.vertex.attribute(m, "DEPT")         #--- Vertex attribute

#--- vertex 크기          : V(m)$size           : vertex.size
#--- vertex 색상          : V(m)$color          : vertex.color
#--- vertex 프레임        : V(m)$frame          : vertex.frame
#--- vertex 프레임 색상   : V(m)$frame.color    : vertex.frame.color
#--- vertex 모양          : V(m)$shape          : vertex.shape

#--- vertex 라벨          : V(m)$label          : vertex.label
#--- vertex 라벨 폰트     : V(m)$label.font     : vertex.label.font
#--- vertex 폰트 family   : V(m)$label.family   : vertex.label.family
#--- vertex 라벨 크기     : V(m)$label.cex      : vertex.label.cex
#--- vertex 라벨 distance : V(m)$dist           : vertex.label.dist
#--- vertex 라벨 색상     : V(m)$label.color    : vertex.label.color

ecount(m)                               #--- Edge 개수
E(m)                                    #--- Edge
get.edge.attribute(m, "advice_tie")     #--- Edge attribute
get.edge.attribute(m, "friendship_tie") #--- Edge attribute
get.edge.attribute(m, "reports_to_tie") #--- Edge attribute
get.edge.ids(m, c(20, 18, 21, 18))      #--- 20 -> 18, 21 -> 18인 edge ID 반환
#--- edge 색상            : E(m)$color          : edge.color 
#--- edge 길이            : E(m)$width          : edge.arrow.width
#--- edge 화살표 크기     : E(m)$arrow.size     : edge.arrow.size
#--- edge 화살표 길이     : E(m)$arrow.width    : edge.arrow.width
#--- edge 타입            : E(m)$lty            : edge.lty

#--- edge 라벨            : E(m)$label          : edge.label
#--- edge 라벨 폰트       : E(m)$label.font     : edge.label.font
#--- edge 폰트 family     : E(m)$label.family   : edge.label.family
#--- edge 라벨 크기       : E(m)$label.cex      : edge.label.cex
#--- edge 라벨 색상       : E(m)$label.color    : edge.label.color

#write.graph(m, file = "sns.txt", format = "pajek")   #--- 그래프를 파일로 저장

###-----------------------------------------------------------------------------
### 그래프 시각화
(layouts <- layout.fruchterman.reingold(m))   #--- Fruchterman-Reingold Layout 

plot(m, main = "Krackhardt High-Tech Managers", edge.arrow.size = .05)   #--- 매번 그래프가 변경
plot(m, layout = layouts, main = "Krackhardt High-Tech Managers", edge.arrow.size = .05) 

#--- DEPT별로 vertex 색상 지정
(vcolors <- get.vertex.attribute(m, "DEPT"))
vcolors[vcolors == 0] <- "Black"
vcolors[vcolors == 1] <- "Red"
vcolors[vcolors == 2] <- "Blue"
vcolors[vcolors == 3] <- "Yellow"
vcolors[vcolors == 4] <- "Green"
vcolors
plot(m, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors, vertex.label = NA, 
     edge.arrow.size = .05)
plot(m, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors, 
     edge.arrow.size = .05)

#--- TENURE로 vertex 크기 지정
(vsizes <- get.vertex.attribute(m, "TENURE"))
plot(m, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors, vertex.size = vsizes,
     edge.arrow.size = .05)

#--- edge 색상 지정
(colorStr <- c(rgb(1, 0, 0, .5), rgb(0, 0, 1, .5), rgb(0, 0, 0, .5)))
#--- rgb : red, green, blue, alpha (투명도)
(ecolors <- 1:length(E(m)))
ecolors[E(m)$advice_tie == 1]     <- colorStr[1]
ecolors[E(m)$friendship_tie == 1] <- colorStr[2]
ecolors[E(m)$reports_to_tie == 1] <- colorStr[3]
ecolors
plot(m, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors, vertex.size = vsizes,
     edge.color = ecolors, edge.arrow.size = .05)
legend(1, 1.25, legend = c("Advice", "Friendship", "Reports To"),   #--- 범례 표시
       col = colorStr, lty = 1, cex = .7)
rm(colorStr)

#--- V(m)과 E(m)의 속성 지정 방식으로 그래프 표시
plot(m, layout = layouts, main = "Krackhardt High-Tech Managers")
(V(m)$size <- vsizes)
(E(m)$color <- ecolors)
(E(m)$arrow.size <- .05)
plot(m, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors)
rm(list = c("vsizes", "ecolors"))

###-----------------------------------------------------------------------------
### 그래프 가공
#--- advice_tie에 값이 있는 것만 추출
(mAdvice <- delete.edges(m, E(m)[get.edge.attribute(m, name = "advice_tie") == 0]))
plot(mAdvice, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors)

#--- 다른 vertex와 연결되지 않은 vertex 삭제
(mAdviceNo <- delete.vertices(mAdvice, V(mAdvice)[degree(mAdvice) == 0]))   
plot(mAdviceNo, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors)

(mFriendship <- delete.edges(m, E(m)[get.edge.attribute(m, name = "friendship_tie") == 0]))
plot(mFriendship, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors) 

(mReport <- delete.edges(m, E(m)[get.edge.attribute(m, name = "reports_to_tie") == 0]))
plot(mReport, layout = layouts, main = "Krackhardt High-Tech Managers",
     vertex.color = vcolors)

###-----------------------------------------------------------------------------
#--- 매개 중심성 (Betweenness centrality) : 한 노드가 연결망 내의 
#---     다른 노드들 사이의 최다 경로 위에 위치할수록 그 노드의 중심성이 높다.
(m1 <- edge.betweenness.community(m))       #--- 매개 중심성 계산
plot(as.dendrogram(m1))                     #--- 계층적 군집
rm(m1)

###-----------------------------------------------------------------------------
#--- community detection : walktrap과 edge-betweenness 방법
#--- steps : random walks의 길이
#--- modularity = TRUE : modularity scores를 결과에 포함
(m1 <- walktrap.community(m, steps = 200, modularity = TRUE))
plot(as.dendrogram(m1, use.modularity = TRUE))    #--- 계층적 군집
m1$modularity
rm(m1)

###-----------------------------------------------------------------------------
#--- 연결정도 중심성 (Degree centrality) : 한 점에 직접적으로 연결된 점들의 합
(deg_full_in <- degree(m, mode = "in"))     #--- indegree 계산
(deg_full_out <- degree(m, mode = "out"))   #--- outdegree 계산
(deg_advice_in <- degree(mAdvice, mode = "in"))
(deg_advice_out <- degree(mAdvice, mode = "out"))
(deg_friendship_in <- degree(mFriendship, mode = "in"))
(deg_friendship_out <- degree(mFriendship, mode = "out"))
(deg_reports_to_in <- degree(mReport, mode = "in"))
(deg_reports_to_out <- degree(mReport, mode = "out")) 

###-----------------------------------------------------------------------------
#--- 근접 중심성 (Closeness centrality) : 친밀감, shortest.paths의 역
#---   노드 수 / 최단거리합
(m1 <- closeness(m))
(m1.score <- round((m1 - min(m1)) * length(m1) / max(m1)) + 1)
(m1.colors <- rev(heat.colors(max(m1.score))))
plot(m1, col = m1.colors[m1.score])
rm(m1, m1.score, m1.colors)

###-----------------------------------------------------------------------------
#--- 근접 중심성 (Closeness centrality) : 한 노드로부터 다른 노드에 도달하기까지 필요한 최소 단계의 합
#---   최단거리합 / 노드 수
(sp_full_in <- shortest.paths(m, mode = "in"))    #--- 노드간 짧은 거리 표시
(sp_full_out <- shortest.paths(m, mode = "out"))   #--- 노드간 짧은 거리 표시
(sp_advice_in <- shortest.paths(mAdvice, mode = "in"))
(sp_advice_out <- shortest.paths(mAdvice, mode = "out"))
(sp_friendship_in <- shortest.paths(mFriendship, mode = "in"))
(sp_friendship_out <- shortest.paths(mFriendship, mode = "out"))
(sp_reports_to_in <- shortest.paths(mReport, mode = "in"))
(sp_reports_to_out <- shortest.paths(mReport, mode = "out"))

###-----------------------------------------------------------------------------
#--- matrix에서 행 vertex에서 열 vertex로 연결이 있으면 1을 설정
reachability <- function(m, mode) {
  reach_mat <- matrix(nrow = vcount(m), ncol = vcount(m))
  for (idx in 1:vcount(m)) {
    reach_mat[idx, ] <- 0
    #    reaches <- subcomponent(m, idx, mode = mode)   #--- 특정 vertex와 연결된 버텍스 집합을 반환
    reaches <- subcomponent(m, idx, mode = mode)[2:(degree(m, mode = mode)[idx] + 1)]
    for (pos in 1:(length(reaches))) {
      reach_mat[idx, reaches[pos]] <- 1
    }
  }
  return(reach_mat)
}

(reach_full_in <- reachability(m, "in"))
(reach_full_out <- reachability(m, "out"))
(reach_advice_in <- reachability(mAdvice, "in"))
(reach_advice_out <- reachability(mAdvice, "out"))
(reach_friendship_in <- reachability(mFriendship, "in"))
(reach_friendship_out <- reachability(mFriendship, "out"))
(reach_reports_to_in <- reachability(mReport, "in"))
(reach_reports_to_out <- reachability(mReport, "out"))

Visualization

graphics

#--- 그래프의 공통 Parameter
#---   main : 제목
#---   xlab, ylab : X축, Y축 이름
#---   xlim, ylim : X축, Y축 값의 범위
#---   type  	: p. 점, l. 라인, s. 라인, o. 점과 선, b. 점과 선, n. 빈 화면 표시
#---   col : 색상 (색상명 또는 "#FF0000" (RGB 코드))
#---   col.lab, col.axis  : 레이블 색상, 축 색상
#---   pch : 점의 모양
#---   axes : FALSE - 축을 표시하지 않음
(data <- data.frame(y = iris$Species, y1 = iris$Sepal.Length, 
                    y2 = iris$Sepal.Width, y3 = iris$Petal.Length,
                    x = iris$Petal.Width))
(idx <- sample(2, nrow(data), replace = TRUE, prob = c(0.7, 0.3)))
(data <- data[idx == 1, ])              #--- 랜덤하게 샘플 추출
rm(idx)

hist(data$x, freq = T, breaks = 10)     #--- 히스토그램
hist(data$x, freq = F, breaks = 10)     #--- 밀도 히스토그램

lines(density(data$x))                  #--- 밀도 그래프 추가
plot(density(data$x))                   #--- 밀도 그래프

plot(data$x, type = "l")                #--- 선 그래프
plot(data$x, type = "s")                #--- 선 그래프 

plot(data$x, data$y1)                   #--- 산점도
plot(y1 ~ x, data = data)               #--- 산점도
plot(x ~ y1 + y2 + y3, data = data)     #--- 산점도

plot(~ y1 + y2 + y3, data = data)       #--- 산점도 행렬
pairs(~ y1 + y2 + y3, data = data)      #--- 산점도 행렬
library(caret)
featurePlot(data[, 2:4], data$y, "ellipse")   #--- 산점도 행렬

plot(data$y)                            #--- 막대 그래프
barplot(tapply(data$x, data$y, mean))   #--- 막대 그래프

plot(data$y, data$x)                    #--- 박스 그래프
boxplot(x ~ y, data = data, notch = F)  #--- 박스 그래프
boxplot(x ~ y, data = data, notch = T)  #--- 박스 그래프
boxplot(data[, 2:4])                    #--- 박스 그래프

plot(y ~ y1 + y2 + y3, data = data)     #--- 모자이크 플롯


(data <- data[sort(data$y1, index.return = TRUE)$ix, ])   #--- y1을 기준으로 데이터 정렬
plot(data$y1, data$y2,                  #--- 산점도 (빈화면 표시)
     main="붓꽃의 3가지 종", xlab="꽃받침 길이", ylab="꽃받침 넓이", 
     pch=20, cex=1, 
     col="yellowgreen", col.axis="green", col.lab="blue", 
     xlim=c(4, 8), ylim=c(1, 5), type="n")

points(data$y1, data$y2,                #--- 점 추가
       pch="+", cex=1, col="green")

lines(data$y1, data$y2, col="blue")     #--- 선 추가
lines(lowess(data$y1, data$y2))  	      #--- 회귀 분석선 추가
abline(h=mean(data$y2), lty=2, col="blue")    #--- Y축 평균 (가로선)
abline(v=mean(data$y1), lty=2, col="green")	  #--- X축 평균 (세로선)

curve(sin(5 * x) + 3, 4, 8, n = 100, add=T) #--- 곡선을 추가
polygon(data$y1, data$y2)               #--- 다각형을 추가

text(data$y1, data$y2, data$x, pos=4)   #--- 문자열 추가
legend("topleft", legend=c("꽃받침 넓이"),    #--- 범례 표시
      pch=c(43), col=c("green"), bg="gray")

다중축

par(mar = c(5, 12, 4, 4) + 0.1)         #--- 그래프에 여백 지정
plot(data$x, data$y1, pch=20, col="green",
     xlim=c(0, 3), ylim=c(4, 8),
     main = "", xlab = "", ylab = "", axes = FALSE)

axis(1, pretty(range(data$x), 10))      #--- x축 추가
mtext(text = "x", side = 1, line = 2)   #--- X축에 라벨 추가

axis(2, ylim = c(0, max(data$y1)), line = 0)   #--- y축 추가
mtext(2, text = "y1", line = 2)         #--- y축에 라벨 추가

par(new = T)                            #--- 원래 그래프에 새 그래프 추가
plot(data$x, data$y2, pch=21, col="blue",
     xlim=c(0, 3), ylim=c(2, 5),
     main = "", xlab = "", ylab = "", axes = FALSE)
axis(2, ylim = c(0, max(data$y2)), line = 3.5)      #--- y축 추가
mtext(2, text = "y2", line = 5.5)         #--- y축에 라벨 추가

par(new = T)                            #--- 원래 그래프에 새 그래프 추가
plot(data$x, data$y3, pch=20, col="red",
     xlim=c(0, 3), ylim=c(1, 7),
     main = "", xlab = "", ylab = "", axes = FALSE)
axis(2, ylim = c(0, max(data$y3)), line = 7)      #--- y축 추가
mtext(2, text = "y3", line = 9)         #--- y축에 라벨 추가

legend("topleft",
       legend = c("y1", "y2", "y3"),
       pch = c(20, 21, 22),
       col = c("green", "blue", "red"), bg = "grey")

title(main = "산점도", sub = "x별 y1, y2, y3의 분포")

par(mar = c(0, 0, 0, 0) + 4)            #--- 그래프에 여백 지정

qplot

  • ggplot2에서 시각화 단계

Ggplot2.png

  • qplot 주요 arguments
  • x, y : x, y 좌표의 값
  • data : 데이터
  • geom : 챠트의 형태
  • auto : 자동으로 선택
  • point : 산점도, 점 그래프
  • smooth : 회귀선 표시
  • line : 선 그래프 (방향 : 왼쪽 -> 오른쪽)
  • path : 선 그래프 (무방향)
  • boxplot : 박스 챠트
  • jitter :
  • histogram : 히스토그램
  • density : 밀도 그래프
  • bar : 막대 그래프, 도수분포표
  • facets : 챠트 분할
  • main : 제목
  • xlab, ylab : X축, Y축 이름
  • xlim, ylim : X축, Y축 값의 범위
  • binwidth : 구간의 넓이
  • colour, color : 색상 분류 기준 (선/점 색)
  • shape : 점의 모양
  • alpah : 투명도, 작을수록 투명함
  • fill : 채우는 색
  • 예약어
  • ..count.. : 관측 개수
  • ..ncount.. : (0, 1)인 관측 개수
  • ..density.. : 밀도
  • ..ndensity.. : (0, 1)인 밀도
  • qplot 기타 arguments
  • weight : 가중치 적용
  • method
  • loess : smooth용 회귀분석
  • gam : 데이터로 자유도 계산한 lm
  • lm : 회귀분석
  • formula : 수식
  • se = FALSE : smooth에서 편차 제거
  • span : smooth와 같이 사용, 0~1
  • log : 로그 적용 (x, y, xy)
  • asp : y/x 비율
  • margins : 마진
  • stat : 통계
  • position :

ggplot2

  • GEOM : geometric object, 기하 객체
  • ggplot() : 데이터와 미적속성을 매핑하는 메타데이터 생성
  • ggplot(~, aes(x=~, y=~, colour=~, group=~))
  • 추가적으로 하나 이상의 레이어가 생성이 되어야 챠트가 생성됨
  • + 로 레이어를 추가할 경우, 미적 속성은 +뒤의 레이어로 상속됨
ggplot(data = diamonds, aes(x=carat, y=price)) + geom_point(aes(colour=clarity)) + geom_smooth()
ggplot(data = diamonds, aes(x=carat, y=price, colour=clarity) + geom_point() + geom_smooth()
  • data : 데이터
  • graph %+% dataFrame : 그래프의 데이터 교체
  • aes(~) : Aesthetic attributes, 미적 속성 (데이터와 매핑됨)
  • x, y : x, y 좌표의 값
  • colour : 색상 분류 기준 (선/점 색)
  • shape : 점의 모양 분류 기준, NA. 표시하지 않음
  • size : 점의 크기, 선의 굵기 (1. default)
  • alpha : 투명도, 작을수록 투명함
  • fill : 색상 분류 기준 (채워넣는 색)
  • group : 그룹 지정
  • order : 누적 데이터 표시시 누적되는 순서 변경, order = desc(~)
  • geom_point() : 산점도, 점 그래프
  • geom_smooth() : 회귀선 표시
  • stat_smooth() : smooth 추가
  • binwidth() : 한칸당 간격
  • geom_line() : 선 그래프 (방향 : 왼쪽  오른쪽)
  • geom_histogram() : 히스토그램
  • geom_density() : 밀도 그래프
  • geom_bar() : 막대 그래프, 도수분포표
  • aes(~) : Aesthetic attributes, 미적 속성
  • binwidth : 구간의 넓이, X축 간격
  • colour : 색상 분류 기준 (선/점 색)
  • shape : 점의 모양 분류 기준, NA. 표시하지 않음
  • size : 점의 크기, 선의 굵기 (1. default)
  • alpha : 투명도, 작을수록 투명함
  • fill : 채우는 색
  • linetype : 선의 모양 (2, "dotdash")
  • method : lm
  • position : 그룹항목을 누적 표시, dodge (그룹 항목을 개별 표시), fill
  • geom_pointrange() : 값과 범위 표시
  • ymin, ymax : pointrange()에서 사용할 최소값과 최대값
  • stat_bin2d() : 격자 형태의 그래프
  • bins : stat_bin2d()에서 격자의 크기
  • stat_bin2d(bins=25, colour="grey50")
  • stat_bin() : 그래프 지정
  • geom : bar, area, point, tile
  • facet_grid() : 챠트 분할
  • facet_wrap() : 챠트 분할
  • nrow : 한 행에 표시할 챠트의 수
  • xlab(), ylab() : X축, Y축 이름
  • coord_cartesian()
  • xlim, ylim : X축, Y축 값의 범위
  • scale_x_continuous() : X축의 범위를 지정
  • limits
  • scale_y_continuous() : Y축의 범위를 지정
  • limits
  • sacle_x_date(breaks="2 years", labels=date_format("%Y-%m")) : 날자축 지정
  • guides()
  • colour = "colourbar" : 색상 범례 사용
  • colour = guide_legend() : 이산형 범례, 작은값  큰값
  • colour = guide_legend(reverse = TRUE) : 이산형 범례, 큰값  작은값
  • scale_color_hue() : 색상 범례 제목 지정
  • scale_colour_continuous() : 색상 범례
  • breaks : break point 지정
  • scale_shape_identity() : shape에 주어진 연속값을 불연속 값으로 매핑
  • last_plot() : 마지막으로 그린 그래프
  • coord_flip() : 가로, 세로 변경
  • scale_x_reverse() : X축 값의 순서를 반대로 설정
  • scale_y_reverse() : Y축 값의 순서를 반대로 설정
  • opts() : 테마(theme) 상세 설정
  • opts(axis.text.x=theme_text(angle=90, hjust=1)) : X축 라벨 90 회전
  • geom_hline() : 가로선
  • annotate() : 사각형 상자
  • annotate("rect", xmin = 2, xmax = 3.5, ymin = 2, ymax = 25, fill = "dark grey", alpha = 0.5)
  • 예약어
  • ..count.. : 관측 개수
  • ..ncount.. : (0, 1)인 관측 개수
  • ..density.. : 밀도
  • ..ndensity.. : (0, 1)인 밀도
  • ggsave("~.png") : 챠트 저장

Java 연동

  • rJava 설치
### Sys.setenv(JAVA_HOME="C:/appl/jre170")
install.packages("rJava")
install.packages("JavaGD")
  • 환경변수 설정
  • R_HOME
  • Path에 URL 추가 : %R_HOME%\bin\x64;%R_HOME%\library\rJava\jri\x64
  • Java 프로그램
  • $R_HOME/library/rJava/jri/*.jar 파일을 Java의 classpath에 추가
package MiD.R

import org.rosuda.JRI.*;

public class RMain {  
    public static void main(String arg[]) {  
        String[] Rargs = { "--vanilla " };  
        Rengine ren = new Rengine(Rargs, false, null);

        if (!ren.waitForR())  {   
            System.out.println("Cannot Load R");   
            return;  
        }    

        REXP rn = ren.eval("rnorm(10)");  
        double[] rnd = rn.asDoubleArray();    
        for (int i = 0 ; i < rnd.length ; i++)  {   
            System.out.println(rnd[i]);  
        }  
        ren.end(); 
   }
}
  • JavaGD_~.zip 파일에 포함된 javaGD.jar를 classpath에 추가
  • 애플릿 상에서 그래프 표시
package MiD.R;

import javax.swing.JFrame;
import org.rosuda.javaGD.GDCanvas;
import org.rosuda.javaGD.GDInterface;

public class MiDJavaGD extends GDInterface { 
   public JFrame f; 
   
   public void gdOpen(double w, double h)  {  
       f = new JFrame("JavaGD");  
       c = new GDCanvas(w, h);  
       f.add((GDCanvas) c);  
       f.pack();  
       f.setVisible(true);  
       f.setTitle("Naked R plot");  
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
   }
}

public class RMain  {    
   public static void main(String[] args) {        
       Rengine engine = new Rengine(new String[] {"--vanilla"}, false, null);              
       engine.eval("library(JavaGD)");        
       engine.eval("Sys.putenv('JAVAGD_CLASS_NAME'='MiDJavaGD')");        
       engine.eval("JavaGD()");        
       engine.eval("plot(rnorm(100))");    
   }
}
  • 그래프를 저장
public class RMain  {    
   public static void main(String[] args) {        
       Rengine engine = new Rengine(new String[] {"--vanilla"}, false, null);              
       if (!engine.waitForR()) {         
           System.out.println("Cannot Load R");         
           return;        
       }        
       
       engine.eval("png(filename=\"c:/aaa/test3.png\")");        
       engine.eval("plot(rnorm(100))");        
       engine.eval("dev.off()");        
       engine.end();    
   }
}

관리자 매뉴얼

  • rJava 로딩시 오류 발생
Error : .onLoad가 loadNamespace()에서 'rJava'때문에 실패했습니다:
  호출: inDL(x, as.logical(local), as.logical(now), ...)
  에러: unable to load shared object 'C:/Users/ghkim/Documents/R/win-library/3.1/rJava/libs/x64/rJava.dll':
  LoadLibrary failure:  지정된 모듈을 찾을 수 없습니다.
  • 원인 : JDK 1.8 설치시 오류 발생
  • 조치 : 작업 폴더에 있는 .Rprofile 파일에 아래 코드 추가 합니다.
Sys.setenv(JAVA_HOME="C:/appl/jre170")

데이터셋

국내 데이터셋


해외 데이터셋

온라인교육

DBGuide.net

참고 문헌

  • R 추천 도서
  • An Introduction to R
  • R Cookbook - Paul Teetor
  • Beginning R
  • R in a Nutshell
  • R Graphics Cookbook
  • The Art of R Programming
  • 통계 추천 도서
  • Head First Statistics - Dawn Griffiths
  • Statistics for the Behavioural Sciences - Frederick J Gravetter 외