한의대 생활/└ R studio 중급 문법

결측치

image


setwd('c:/users/is2js/R_da/')
#### 결측치(Missing value)처리 - [is.na(칼럼인덱싱), ]활용 / summary()활용 ####
# NA/NULL의 기본 형식으로 값이 비어있거나 다양한 형식(NILL)으로 숨어있는 값
# - 가장 재수없는 것은 .. 빈칸...


#### 데이터 준비 ####
data("Orange")
dim(Orange) # row와 칼럼수를 한번에 파악할 수 있다.
#nrow(Orange)
#ncol(Orange)

set.seed(1228)
# *** 모든칼럼에 대해 평등하게 랜덤 NA를 억지로 넣어주기 위해 행렬연산을 이용한다.***
# df를 matrix로 바꾸면, n X m 요소에 접근시 칼럼을 넘어가도 순서대로 붙어버린다.
# 그래서 1차원 벡터연산(1차원 인덱싱)으로만으로도 모든 요소에 접근이 가능해진다.
df = as.matrix(Orange)
# 1부터 행x열값까지의 수중에 랜덤하게 10개를 뽑아,
# 행인덱싱 자리에 넣어, 해당 행 전체에 NA를 집어넣는다.

df[sample(1:(nrow(df) * ncol(df)), size = 10) ] = NA
df = as.data.frame(df)
df


#### 1. is.na($칼럼인덱싱) 을 이용한 결측치 확인 ####
df[is.na(df$Tree), ]
df[is.na(df$age), ]
df[is.na(df$circumference), ]

df[(is.na(df$Tree))|(is.na(df$age)),]
df[(is.na(df$Tree))&(is.na(df$age)),]

# 값을 대입을 할려고보니, 오류가 난다.
df[is.na(df$Tree), "Tree"] = 123
# sapply(df, "class")로 속성확인! 을 해보니 factor였다.***
sapply(df, "class")

#### factor의 결측치 처리를 하는  -> NA에 넣을 값을 levels에 추가한다.. ####
# 1. 해당 칼럼인덱싱으로 levels확인
df[ , "Tree"] # 1,2,3,4,5 5개의 levels이 있다.
# 2. levels를 하나 더 추가해준다.
df[ , "Tree"] = factor(df$Tree, levels = c(1:5, 123))
df[is.na(df$Tree), "Tree"] = 123
# 3. 만약 다양한 levels이 적혀있다면, 직접 levels를 적어주기 곤란하다.
levels(df$Tree) # 이것을 factor의 levels에 적어준다.
df[ , "Tree"] = factor(df$Tree, levels = c(levels(df$Tree), 123))


#### 2. summary() ####
# - NA에 대해서만 칼럼별로 쉽게 파악 가능하다.
# - NULL 등은 따로 확인해야한다.
summary(df)

이상치

image

setwd('c:/users/is2js/R_da/')
#### 이상치(Outliers) ####
# - 데이터의 중심경향성에서   많이 떨어져있는 값
# - 이상치, 이상값, 특이치, 특이값
# - 처리절차 : 이상치 확인 -> 필터(또는색인) -> 처리방법 선정 -> 치환또는 제거
# - 처리방법 선정 :
# (1) 단순 제거 : 너무 적을 때
# (2) 대표값 치환 : 보너스 점수 받은 102점 -> 100점으로 치환
# (3) 통계기반 처리 : 평균값으로..
# (4) 머신러닝 기반 처리 : 남자의 평균, 여자의 평균.. 등

#### 데이터 준비 ####
set.seed(1228)
df = data.frame(xx = 1:200,  #xx에는 1부터 200까지
                 yy = rnorm(n = 200, mean = 5, sd = 3)) #yy에는 정규분포(rnorm) 개수 200, 평균5 표준편차 3짜리
head(df)

#### 1. 이상치 확인 ####
####...L (1) order()를 활용한 상위, 하위 3개값 추출하기 ####
# order(df$하위칼럼)을 행인덱싱자리에 넣어주면, 해당 칼럼 기준 오름차순으로 정리해준다.****
df[order(df$yy), ]
# 열인덱싱자리에 기준칼럼명을 인덱싱하여, 오름차순된 yy칼럼값을 뽑아낸다.
df[order(df$yy), "yy"]
df_sub = df[order(df$yy), ]
head(df_sub)

# 하위 3개 뽑기
df_sub[1:3,]      #하위 3개 row전
df_sub[1:3, "yy"] #하위 3개 yy값

# 하위3개(오름차순) 다시 한줄로 요약( 새로운 객체를 만들지 않는 장점!)
df[order(df$yy), "yy"][1:3]
# 상위3개(내림차순) 추출 : ***order(-특정칼럼) 형태로서, ()안에 -를 붙힌다.
df[order(-df$yy), "yy"][1:3]

# 상위 3개 추출값을 %in%을 이용해 매칭되는 row 추출해보기
df[ df$yy %in% ( df[order(-df$yy), "yy"][1:3] )   ,    ]
# 하위 3개도..
df[ df$yy %in% ( df[order(+df$yy), "yy"][1:3] )   ,    ]


####...L (2) quantile($인덱싱)을 통해 이상치 확인하기 ####
quantile(df$yy) # 제 4분위 수값을 알 수 있다.
quantile(df$yy, probs = 0.99)# 확률값을 넣어주면, 해당 %에 해당하는 값을 뿌려준다.
quantile(df$yy, probs = c(0.95, 0.99)) # 확률값은 c()를 이용해 여러개 줄 수 있음.
quantile(df$yy, probs = c(0.95, 0.99))[1]
quantile(df$yy, probs = c(0.95, 0.99))[2]
# 결과값을 보면, 99%라는 칼럼처럼 보이지만, name vector로서, name이 붙어있을 뿐,
# 가져오는 것은 벡터연산(인덱싱)으로 한다. [1] or [2]

aa = quantile(df$yy, probs = c(0.95, 0.99))
aa
names(aa) # name vector로서 95%, 99%가 있으나, 인덱싱은 벡터연산[1], [2]로..
aa[1]
aa[2]
# quantile의 결과값인 name vector에서 name을 제거 하고 싶다면
bb = as.numeric(aa)
bb

# ------예제 시작------
# 이제 quantile()을 통해 나온 분위수를 행인덱싱자리 조건문으로 넣어서 이상치 추출
# 상위 98% 백분위수보다 넘어가는 것만 추출해보자.( 2% 미만)
df[ df$yy > quantile(df$yy, probs = 0.98), ]

# 뽑은 것을 처리해보자.- 해당 칼럼에다가 값을 대입해주면 된다.
df[ df$yy > quantile(df$yy, probs = 0.98), "yy"] = 20
df[ df$yy > quantile(df$yy, probs = 0.98), "yy"]


#### ggplot()을 활용해서 확인 ####
library("ggplot2")
ggplot() +
   geom_point(data= rbind(df,
                          data.frame(xx = c(30, 50, 84),
                                     yy = c(35, 40, 39))),
              aes(x = xx,
                  y = yy),
              size = 7,
              alpha = 0.5,
              color = "#FFA500") +
   scale_y_continuous(limit = c(-10, 50))

#### 기본 boxplot()을 활용해서 확인 ####
boxplot(rbind(df,
               data.frame(xx = c(30, 50, 84),
                          yy = c(35, 40, 39))))

setwd('c:/users/is2js/R_da/')
#### 데이터 준비 ####
data("airquality")
df = airquality

#### 1. 단순 필터링(인덱싱, 벡터연산) ####
df_sub = df[1:4, ] # 전체에서 뽑아낼 때, 뒤에 _sub라는 접미사를 붙히는 버릇을 가지자.
df_sub

df[df$Day == 1, ]
df[df$Day != 1, ]

df[df$Day <= 2, ]

# 2개이상의 조건시 [()&(), ]
df[(df$Day == 1) & (df$Day == 2), ]
df[(df$Day == 1) | (df$Day == 2), ]


#### 2. %in% 연산자를 활용한 필터링 ####
# - %in% 1:2 1 or 2 포함 -> | 연산자를 여러개 사용할 필요가 없어진다.
# - 결과는 T / F 의 논리 연산자로 나옴. 앞에 !( )를 붙힐 수 있다. -> 행의 갯수를 nrow()할 필요없이 sum()으로도 바로 출력가능하다.

# %in%를 이용하여 or를 대신하기****
df$Day %in% 1:2 #조건문(mask개념)이다. --> TRUE or FALSE
df[df$Day %in% 1:2, ]

# 해당 조건을 만족하는 셀때는 nrow( %in% )한것을 할 필요 없이 sum()으로 바로 할 수 있다.
# row의 개수 빠르게 세기
sum(df$Day %in% 1:2) # %in%의 결과는 T/F이므로 sum은 1만 더해진 것이다. 값의 합이 아님.


#### 3. subset() 함수를 이용한 필터링 ####
# - 되도록이면 벡터연산(인덱싱)으로 해결하자.
# - subset(df, 조건문, select = c(컬럼명1, 컬럼명2)) # -컬럼명 : 해당 컬럼 제외 모든 컬럼
# - ***subset의 장점 : 칼럼명1:칼럼명3 으로 칼럼이름으로 연속하게 뽑아낼 수 있긴하다...
# - 사용하지말자


#### 4. dplyr패키지 - filter()함수로 필터링 : 조건문에 $없이 칼럼명만 사용(대신 자동완성x)한다. #####
# - filter(df, 단순칼럼명의 조건문)
# - dplyr는 속도가 빠르고 신뢰할만한 패키지다(bindr cpp -> c++을 사용하기 때문에)

install.packages("dplyr")
library("dplyr")
df = airquality

# 칼럼명만 변수처럼 바로 입력해서 조건문을 입력****
# - df$Day형태가 아니라 자동완성은 안되는 단점
filter(df, Day == 1)

filter(df, Day == 1 & Month == 5)

filter(df, Day %in% c(1, 3, 6)) # *** 1:3의 범위 뿐만 아니라 c(1, 2, 3)형태로 이산으로도 바로 or를 적용시킬 수 있다.!!!****

기초

setwd('c:/users/is2js/R_da/')
#### 사용자 정의 함수(user defined function) ####
# - 사용자 정의 함수를 모은 것이 패키지
# - apply() 관련함수와 같이 사용시 연산 소요시간 단축

#### 사용자 정의 함수 기본 ####
aaa = function(x){} # 함수명 = function(변수){} --> env창에 올라간다
aaa() # 사용은 함수명()으로 사용
aaa   # ()파라미터 입력을 안열어주면, 사용자 정의함수 자체가 나옴
aaa(x=123) # {}안에 함수가 없기 때문에, NULL값이 나옴

# 예제 01 - 입력값을 받지 않은 함수 - (x)가 없이 ()만
bbb = function(){
   print("Hi!")
}
bbb()
bbb(123) # 만약 인자를 억지로 넣어주면, 에러가 난다.


# 예제 02 - 입력값을 그대로 출력
# function(x){ print(x) } 처럼 {}안에서 x가 사용되는 순간, 함수 호출시에 반드시 파라미터가 포함되어야한다.
ccc = function(echo){
   print(echo)
}
ccc
ccc()
ccc(echo = "asdf")


# 예제 03 - 단순계산
ddd = function(x){
   x + 5
}
ddd( x = 10)
ddd( x ="계산인데 문자열을?" ) # 에러나옴
# **** 숫자를 문자열로 가지는 것까지 계산되게 할려면
ddd_upgrade = function(x){
  as.numeric(x) + 5
}
ddd_upgrade(x = "25")


# 예제 04 - 파라미터에 기본값을 지정해주기
# - ()안에 아무값이 없어도 기본값으로 작동함. 새로운 값이 들어가면 새로운 값으로
eee = function(x = 5){
   x^2
}
eee() # 기본값이 계산됨
eee(2)


# 예제 05 - 2가지 파라미터 넣어주기.
fff = function(aa, bb){
   aa*bb
}
fff(aa = 1, bb = 3)


# 예제 06 - {}안에 여러개 함수 호출하기
ggg = function(aa, bb){
   print(paste0("aa = ", aa)) # paste0를 이용하여, print문에 설명도 넣어주기
   print(paste0("bb = ", bb))
   print(paste0("aa * bb = ", aa*bb))
}
ggg(aa = 1, bb= 2)


응용

setwd('c:/users/is2js/R_da/')
#### udf 응용 ####
#### 캡슐화 ####
# - 코드를 묶어주는 것 -> source()를 활용한다.


#### 1. 할당연산자를 활용한 udf ####

# - 할당연산자(<<-)를 이용하여 전역변수도 생성한다
# - return을 이용하여 값을 반환한다(print에서 벗어나...)
# 예제 1
# 1) 들어온 x를 3번 반복한다음, 각각을 "-"로 연결한 뒤, global_object에 넣어준다.
# 2) 들어온 x를 nchar()를 이용해 문자열 개수를 return하자.

udf = function(x){
   # paste()에서 collapse = 로 이어준다. <-> 구분자는 sep =
   global_object <<- paste(rep(x, 3), collapse = "-" ) # 할당연산자 = 를 사용하면 전역변수가 인식이 안된다..
   return(nchar(x))
}
udf("a")
global_object

udf("asdfasfda")
global_object # 하지만, 기존에 사용하던 변수를 덮어쓸 수 있으므로, 전역변수+할당연산자를 쓰는 것은 위험할 수 있다.


# 사용자 정의 함수 안에서, 여러 개의 자료형태를 반환해주고 싶을 때 list()를 사용하면 된다.
udf2 = function(x){
   aa = paste(rep(x, 3), collapse = "-")
   bb = nchar(x)
   cc = rep(x, 3)
   print(aa)
   print(bb)
   print(cc)
}
udf2("asdf") # 이런식이면, print는 3개가 될지라도, 변수에 할당시 마지막 값만 대입된다.
f = udf2("asdf")
f # 마지막 cc만 대입이 되어버린다. 묶여있는 구조가 아니라서..

# 여러 자료를 return시 list()를 이용하면 된다.
udf3 = function(x){
   aa = paste(rep(x, 3), collapse = "-")
   bb = nchar(x)
   cc = rep(x, 3)
   return(list(aa, bb, cc))
}
l = udf3("asdf")
l
l[[1]]
l[[3]]


#### 2. apply( FUN = "udf")함수를 활용한 udf ####
# 예제1) apply()없이.. udf로 들어온 x를 문자열로 바꾸고, 문자열 갯수를 반환하여 칼럼 생성
udf_noapply = function(x){
   return(nchar(as.character(x)))
}
data("iris")

iris[,"n_char"] = udf_noapply(iris$Species)
head(iris)

# 하지만, 여기서 문자열개수를 +1 정도 추가하려면 또 함수를 적어야한다
iris[,"n_char"] = udf_noapply(iris$Species) + 1
head(iris)
# 이때는, 사용자 정의 함수의 마지막 return 에 + 1 해주는 식으로 실수를 줄이자.

# 예제2)
# 1) 먼저 데이터를 df로 만든 다음(apply()에는 df를 넣더라)

df = head(iris)
# 2) 숫자정보만 빼낸 다음, 세로방향2으로 적용시키면
# FUN = 인자에 "사용자 정의함수" 를 적용시키면, df전체에 문자열 갯수가 반환되서 대입된다.
apply(X = df[1:4], MARGIN = 2, FUN = "udf_noapply" )

setwd('c:/users/is2js/R_da/')

# for 반복문은 쉽지만, 속도가 느리다는 단점이 있다. 그것을 대체할 함수가 2개이다.
# 1. apply()
# 2. ifelse()

# ifelse( test = 특정 칼럼(?)에 대한 조건, yes = 참일 경우, no = 거짓일 경우 ) 의 형태이다.
image

# apply() -> 파생된 함수 lapply(), sapply() 등
# - apply( X = df, MARGIN = 1, FUN = "sum")
# apply()함수는 MARGIN인자가 계산 방향이다.
# MARGIN = 1 : 가로방향(행 방향)  #(파이썬은 세0가1 , R은 세2가1)
# MARGIN = 2 : 세로방향(칼럼 방향)

image

# sapply() : apply() + MARGIN = 2(세로방향) 의 함수다. (세2가1)
# 엄청 자주 사용하는 함수이다. 세로방향 s!
# - sapply(df, "sum")   : 칼럼별로 합계 확인
# - sapply(df, "class") : 세로방향(칼람별로) 속성확인


실 습


set.seed(1228)
df = data.frame(aa = 1:6,
                 bb = sample(c("a","b"),
                             size = 6,
                             replace = TRUE)) # 2개인데도 복원추출 시켜서 6개 뽑기
df

#### ifelse() - 기준칼럼을 가지고 조건을 걸어서--> 해당칼럼에 y/n선택적 대입 ####
df[,"col_1"] = ifelse( test = df$aa == 3, # test = 기준칼럼에 대한 조건
                        yes  = 33333,       # yes = 참일 경우 대입할 값
                        no   = "무관심")    # no  = 거짓일 경우 대입할 값
df
# 만약 for문으로 짠다면?
for( n in 1:nrow(df)){
   if(df$aa == 3 ){
     df[n,"col_1"] = 33333
   }else{
     df[n,"col_1"] = "무관심"
   }
}

# ifelse()중첩해서 사용해보기
df[,"col_2"] = ifelse( test = df$aa == 3, # test = 특정칼럼에 대한 조건
                        yes = 33333,       # yes = 참일 경우 대입할 값
                        no  = ifelse( test = df$aa == 4,
                                      yes  = 44444,
                                      no   = "무관심"))   
df

# 만약 yes부분(33333, 44444)가 동일한 상태라면, 중첩을 쓰지 않고
# 1. no부분을 먼저 값을 채운 뒤
df[, "col_3"] = "무관심"
# 2.행 자리에 <칼럼인덱싱 %in% 범위(3:4)> 를 통해 더 간단히 대입할 수 있다.
df[df$aa %in% 3:4, "col_3"] = "오..."
df



#### apply() - 칼럼별(세2) or 행별(1)로 계산시 빠르다.#####
data("iris")
head(iris)
# 1. colnames() + t(t()) 를 이용하여 칼럼명 쉽게보기
t(t(colnames(iris)))
# 2. apply()는 계산하는 함수이므로, 숫자데이터만 남긴다.
df = head(iris[1:ncol(iris)-1])
# 3. 가로방향 sum
apply(X = df, MARGIN = 1, FUN = "sum")
# 4. sum을 새로운 칼럼으로 추가
df[,"sum"] = apply(X = df, MARGIN = 1, FUN = "sum")
df
df[,"mean"] = apply(X = df, MARGIN = 1, FUN = "mean")
df
# 5. 칼럼별(세2) 평균
apply(X = df, MARGIN = 2, FUN = "mean")
# 6. 소수점이 길면 반올림
round(apply(X = df, MARGIN = 2, FUN = "mean"), 4)

#### sapply() - s는 세로방향 세2 Margin2 생략 ####
sapply(X = df, FUN = "mean")
# 가장 많이 쓰는 sapply() - FUN = "class" ****
sapply(X = df, FUN = "class")
# 칼럼명뿐만 아니라 칼럼 속성도 쉽게 보기
t(t(sapply(X = df, FUN = "class") ))
# 파라미터를 생략해도된다.
t(t(sapply(df,"class") ))

setwd('c:/users/is2js/R_da/')

#### Pivoting ####


# 1. reshape2 패키지 설치
install.packages("reshape2")

set.seed(123)
df = data.frame(Obs = 1:4,
                 A = sample(10:99, size = 4),
                 B = sample(10:99, size = 4),
                 C = sample(10:99, size = 4))
df
image


# 2. melt()함수를 통해 여러개의 칼럼을 --> 한칼럼에 세로로 늘어트린다.
# - melt(df, id.vars = "식별 칼럼명Obs", Variable.name = "여러개의 칼럼을 하나로 뭉친 칼럼명", value.name = "각 값들이 나올 칼럼명")
library("reshape2")
df_melt = melt(df, id.vars = "Obs",
                variable.name = "Group", value.name = "Count")
df_melt
image
# 만약 variable.name(뭉친칼럼명)과 value.name(값 칼럼명)을 안넣어주면 default한 칼럼명(variable칼럼 / value칼럼)이 생긴다.
df_melt_default = melt(df, id.vars = "Obs") # 식별 칼럼명도 안넣어주면, 그것까지 뭉친칼럼으로 들어간다.
image


# 3. dcast()와 acast()
# melt형태의 df를 값별로 여러개의 칼럼을 만드는데
# 추가적으로, melt된 형태의 데이터를 dcast()를 통해 여러개의 칼럼으로 흐트려 놓으면 각 칼럼별 NA값을 쉽게 확인할 수 있다.
# 게다가    , fill = 인자를 통해 결측값을 채울 수 도 있다.
# 게다가    , fun.aggregate = length(개수),sum(합) 등 요약 정보도 확인할 수 있다.
#  - dcast(df_melt, formula = 식별칼럼명 ~ 뭉친칼럼명, value.var = "값을 가진 칼럼명")
#  - acast(df_melt, formula = 식별칼럼명 ~ 뭉친칼럼명, value.var = "값을 가진 칼럼명")
#   > dcast와 동일하나, 식별칼럼Obs를 없앤 df를 생성
dcast(data = df_melt, formula = Obs ~ Group, value.var = "Count")
image
acast(data = df_melt, formula = Obs ~ Group, value.var = "Count")
image

# 데이터를 일부 뺀상태에서 dcast()하여 NA로 만들고 관찰하기
dcast(data = df_melt[-(2:5),], formula = Obs ~ Group, value.var = "Count")
image
# - 세로로 녹여진 df_melt의 2행~5행까지를 빼먹고 dcast()하면,
# - dcast()결과는 각 칼럼별로 결측값을 쉽게 확인할 수 있다.
dcast(data = df_melt[-(2:5),], formula = Obs ~ Group, value.var = "Count",
       fill="NA래요!")
image



# 4. t()함수 2번 감싸주기를 이용한 1차원 행렬(1,n) --대각선기준 접기--> n차원 행렬(n,1)로 나타내면
# - n행이 되므로 colnames()같은 정보를 한눈에 쉽게 볼 수 있다.
?t
data("CO2")
head(CO2)

df = cbind(CO2, CO2) # cbind()로 칼럼수가 여러개가 되도록 임의 조정
df
colnames(df)

# 그냥 colnames개수만큼(length(colnames(df)) or ncol(df))
# paste0() + letters를 이용하여 다른걸로 바꿔주자.
colnames(df) = paste0("CO2_", sample(LETTERS,  length( colnames(df) )     ))
colnames(df)
head(df)
ncol(df)
# *** 일반 원소에 t()를 2번 감싸면 세로로 쭈욱 생긴다.
t(colnames(df))
image
t(t(colnames(df)))
image

프로젝트를 통한 관리

#### 1. 캡슐화 ####
# 코드를 나누어서 덩어리로 관리
# 덩어리들이 따로 있으니까 기능 추가/보수도 쉽다.

#### 2. R Studio 기능 활용 ####
# 주석 4개로 접고 펴기 등 -> [ Ctrl+shift+O ]로 다시 메뉴 불러옴

#### 3. 사용자 정의함수 활용 ####
# source()를 활용하면, 다른 스크립트의 함수를 불러올 수 있다.
# 사용자 정의 함수 -> 스크립트로 저장 -> 다른데서 source()로 불러오기(사용자 정의함수 자동 등록됨)

#### 4. 파일을 목적별로 나누기 ####
# 용도에 따라 : 데이터 입출력 / 전처리 / 시각화/ 레포팅ppt, markdown 등
# 성질에 따라 : 환경설정 / 데이터 병합 / global option 등
# 특정 업무 처리
# ex>
# 01_env.r   : 패키지 로딩 / 옵션 설정 / DB연결
# 02_EDA.r   : 파일 불러오기 / 이상치/결측치 처리 / 데이터 분포 확인 / 상관계수, 행렬 등
# 03_model.r : Feature Engineering / 모델 성능비교
# 04_vis.r   : 시각화 공들여서 할 때,

#### 5.Project 생성 및 관리 ####
# 여러 스크립트 파일과 작업폴더를 한번에 관리
# 작업 폴더 관리가 매우 쉬워짐
# New Project > Empty Project 등


image

image

image
- New project를 선택해서 새로운 프로젝트 생성


image
- 윈도우에서 ~ 표시는 문서(Document)폴더를 의미한다.
- 나는 Browse를 통해 특정 폴더를 지정해주었다.

image

image
- getwd()결과 자동으로 해당 폴더의 directory가 working directory로 지정되어있다!


image
- 주석을 앞뒤로 # 4개씩 달고, 하위 주석일 경우 ...L 1) (엘 대문자) 식으로 만들자.
- [ Ctrl + Shift + O ]를 누르면 우측에 주석 메뉴가 뜬다.!

image

image
image
- row번호 우측에 화살표를 접고 펼수 있다.


사용자 정의함수로 스크립트 캡슐화 -> source()로 활용하기


image
- 사용자 정의 함수를 정의한 .r파일을 하나 작성하여 저장 한 뒤

image
- source(" .r")만 호출하여도 env창에 사용자 정의함수가 등록이 되는 것을 확인할 수 있다.

image
- 정상적으로 사용가능하다.

6. R Clean code 작성법

2018. 12. 29. 12:43

setwd('c:/users/is2js/R_da/')
# 1. 연산자 좌우 띄어쓰기
# 2. 쉼표 다음 띄어쓰기 or 줄바꿈
# 3. for문 길어질때 마지막 주석으로 표시해주기
# 4. 너무 많은 code는 Code > Reformat code [ Ctrl + Shift + A]

install.packages("ggplot2")
library("ggplot2")

data("iris")
df = iris

ggplot() +
   geom_point(data = df,
              aes(x= Sepal.Length,
                  y= Sepal.Width,
                  color = Species),
              size = 3)

5. 속성 확인 및 변환

2018. 12. 29. 12:42

setwd('c:/users/is2js/R_da/')
#### 원소<벡터<리스트 속성확인 ####
# class()
# if문에서 T/F 확인은 is.numeric() / is.character() / is.data.frame() / is.list()

#### 원소<벡터<리스트 속성확인 ####
# as.numeric() / character()
# 문자열 속에 숫자가 있다면 가능
# 문자열 속에 문자가 있다면 -> NA(에러)가 남.


#### 데이터 준비 ####
aa = 1234
bb = "test"
cc = TRUE
dd = NA


class(aa)
class(bb)
class(cc)
class(dd) # NA는 logical이다.
class("NA") # 문자열은 그냥 character

is.numeric(aa)
is.numeric(bb)
is.numeric(cc)
is.numeric(dd)

is.character(aa)
is.character(bb)
is.character(cc)
is.character(dd)

aaa = 1:5
bbb = letters[1:5]
ccc = data.frame(a = aaa, b = bbb)
ddd = list(asdf = aaa, qwer = bbb)

class(aaa)
class(bbb)
class(ccc)
class(ddd)

is.numeric(aaa)
is.integer(aaa)
is.data.frame(ccc)
is.matrix(ccc)
is.list(ddd)

#### 속성 변환하기 ####
aaa = 1:5
bbb = letters[1:5]
ccc = data.frame(a = aaa, b = bbb)
ddd = list(asdf = aaa, qwer = bbb)

as.character(aaa) # 전부 따옴표가 붙는다.
as.numeric(bbb) # 문자는 숫자로 못바꿈 -> 각각이 NA 처리
as.numeric(c(123, "345", "ddd")) # 1차원 combine에서는 문자가 우선이라서 character순서를 가지고 있다. 문자열속 숫자만 numberic으로 변형된다.

as.matrix(ccc) # data.frame은 사각형을 유지한 상태이므로 matrix로 변형된다.
# matrix는 행이 [1,] [2,] 형태 / 원소는 ""로 나타남.



#### factor ####
# 다루기 힘들며, 익숙하지 않으면 피해야한다.
# 통계처리 전에 사용된다.
#factor는 1차원 벡터와 함께 levels로 우선순위를 둔다
.
fac = factor(c(13, 22, 88), levels = c(88, 22, 13))
fac

#숫자로 구성되더라도 as.numeric()으로 변환하면, 우선순위만 표기된다.
as.numeric(fac) # 13, 22, 88 -> levels기반 우선순위 3, 2, 1 로 출력됨
# factor 숫자원소를 실제 숫자로 바꿀려면, as.character() -> as.numeric() 순으로 적용해야한다.
as.numeric(as.character(fac))

# 만약 levels를 주지 않는다 하더라도, 첫번째부터 우선순위가 적용되어, 1, 2, 3형태로 뽑아진다.
fac_2 = factor(c(13, 22, 88))
as.numeric(fac_2)


#### table #### - data.frame 칼럼 2개짜리에 대응하여 행/렬로 나타낸 뒤 빈도를 나타내준다.
# 2개 칼럼짜리 df 를 만들고 table()로 감싸주어 테이블을 만들자.
df = data.frame(var1 = rep(letters[1:2], 3),
                 var2 = rep(1:3, 2))
df
df_table = table(df)
df_table
class(df_table)

# 다시 data.frame으로 바꾸면 빈도칼럼이 생긴다.
as.data.frame(df_table)

setwd('c:/users/is2js/R_da/')


#### 데이터 준비하기 #####

data("iris") # R에 포함된 iris데이터를 가져온다. 자동으로 iris 변수에 들어가진다.
head(iris) # 따옴표 아님!

data() # R에 깔린 data 확인해보기
data( package = .packages(all.available = TRUE)) #패키지들에 깔린 모든 데이터셋 가져와보



#### 데이터 저장하기 ####


#### write.csv() #### - csv를 sep인자 없이 바로 저장
# csv load/save 고정!!!! #
# read.csv() : stringsAsFactors = FALSE      - 문자열 factor로 인식안하도록
# write.csv() : row.names = FALSE             - 행번호들 저장안하도록

write.csv(iris, "iris_csv.csv" , row.names = FALSE)
?write.csv #설명보기

#### write.table() #### - csv/tsv 등 다 가능 with 구분자
write.table(iris, "iris_tsv.tsv", row.names = FALSE,
             sep="\t")
# csv나 tsv가 아닌 파일들은 txt + 다른구분자로 저장
write.table(iris, "iris_txt.txt", row.names = FALSE,
             sep="@#$%")


#### jsonlite - write_json() ####
# json은 형식을 갖추고 있으므로, 용량이 큰 편이다.
library("jsonlite")
write_json(iris, "iris_json.json")

#### excel_link - xl.save.file() ####
# 현재 R 3.5.2버전에서는 설치가 안된다.
install.packages("excel_link")
library("excel_link")
xl.save.file(r.obj = iri, filename = "iris_xlsx.xlsx",
              row.names = FALSE)

데이터 불러오기


setwd('c:/users/is2js/R_da/')


#### CSV ####

#### 1. readLines()####
# readLines는 데이터가 매우 클 때, 일부 샘플 3줄 정ㄷ만 읽어볼 경우에 사용
#             확장자가 없거나 txt파일
readLines("./data/01_csv.csv", n=3)
# 지금은 데이터가 쉼표로 구분되어있지만
# 만약 구분자가 custom으로 구성(#, @@)되었다고 가정하고
# readLines를 이용하여 구분자 처리해보기
# ****큰 개요****
# -> readLines()로 읽어오기
# -> 기준칼럼obs와 함께 data.frame의 칼럼으로 집어넣기
# -> cSplit()을 이용하여 데이터칼럼의 구분자를 구분해주기
# -> 전체 data.table을 data.frame으로 바꾸기
# -> 전체 data.frame 중 obs제외 2열부터 for문을 돌면서  factor를 character로 바꾸기
# -> 첫행에 있는 칼럼명을 colname에 입혀주기
# -> 첫행(칼럼명 포함row)과 첫칼럼(obs-기준칼럼) 제외시키기 [-1,-1]


# 1. readLines()로 받아온 데이터를 df로 만들기
df = readLines("./data/01_csv.csv", n=3)
df = data.frame(obs = 1:3, # 기준이 될 obs라는 컬럼을 1,2,3로 채워줌
                 values = df,# values 칼럼을 readLines로 읽어온 데이터로 채워줌
                 stringsAsFactors = FALSE) #파일 읽어올때 기본적으로
df
# 2. values칼럼을 구분자로 나누어보자.
# (1) 기본함수 strsplit() 사용
strsplit(df$values, split=",") # 결과가 리스트로 나온다. **df가 깨저버림!!!
strsplit(df$values, split=",")[[1]]

# (2) splitstackshape 패키지의 cSplit()함수 사용해서 구분자 나누기
library("splitstackshape")
df_2 = cSplit(indt = df, splitCols = "values", sep="," )
df_2 # cSplit()의 결과는 행이 1:, 2:, 형태로 나타나는 data.table형태다.

class(df_2) #클래스 확인 -> data.table과 data.frame이 공존하는 상태 -> data.frame만 남겨야함.
str(df_2) # strucure 확인 -> 각 요소가 Factor로 되어있다 -> character로 바꿔야함.

# data.table을 data.frame으로 as.data.frame()을 이용하여 바꿈
df_2 = as.data.frame(df_2)
df_2
class(df_2)
str(df_2) #아직 factor

# 2번째 칼럼부터 for문으로 칼럼들을 돌면서, 각 칼럼들을 as.character()로 factor를 char로바꿈
for(n in 2:ncol(df_2)){
   df_2[,n] = as.character(df_2[,n])
}
str(df_2)

#이제 첫행에 있는 칼럼명들을 df의 칼럼명에 넣어야함.
colnames(df_2)
# 1차원도 끝=ncol(df_2)
colnames(df_2)[2:ncol(df_2)] = df_2[1,2:ncol(df_2)]
df_2
# 이제 첫번째 칼럼과 첫번째 row를 빼주자.
df_2[-1, -1] # R의 df에서는 -n을 통해 해당 row / col을 제외시키고 전체를 나타내는가보다.****


#### 2. read.csv() ####
df = read.csv("data/01_csv.csv")
df



#### TSV ####

#### 1. readLines()로 샘플 읽어서 구분자확인하기 ####
df = readLines("data/02_tsv.txt", n=3)
df # \" : 문자열 속 따옴표, \t : 탭 , \ : escape

#### 2. read.delim()로 구분시키기 ####
# 이번에는 readLines()로 해결안할 것임..
df = read.delim("data/02_tsv.txt", sep="\t")
head(df)



#### XML ####

install.packages("XML")
library("XML")
df = xmlTreeParse("data/03_xml.xml")
df
df = xmlRoot(df) #record 정보만 남김
df = xmlSApply(df, function(x){xmlSApply(x, xmlValue)}) # 가로로 record정보를 보여줌
df
df = data.frame(t(df), row.names = NULL) # 세로로 record정보를 나열해줌
df
head(df)


#### HTML table ####

library("XML")
df = readHTMLTable("data/04_html_table.html", header = TRUE)
head(df)



#### JSON ####

# 1. readLines()로 구경하기
readLines("data/05_json_simple.json", n=20)
# 2. jsonlite 패키지의 fromJSON()함수 사용
install.packages("jsonlite")
library("jsonlite")
df = fromJSON("data/05_json_simple.json")
head(df) # cols 와 data가 나눠져있다..

#데이터만 가져와서 data.frame에 넣자.****
df_2 = as.data.frame(df$data)
head(df_2, 2)

#df_2라는 data.frame에 df의 cols라는 컬럼명집합 컬럼을 넣어주자.
df$cols
colnames(df_2) = df$cols
head(df_2)


#### CUSTOM FORMAT #####

# 1. readLines로 맛보기
df = readLines("data/06_custom.csv", 3)
# 2. #으로 구분되어있으면 read.delim로 읽을 수 있다.
df = read.delim("data/06_custom.csv", sep = "#", stringsAsFactors = F)
head(df, 2)
str(df)


#### Excel - xlsx ####

install.packages("readxl")
library("readxl")
df = read_xlsx("data/07_xlsx.xlsx") # sheet = 인자로 원하는 시트를 가져올 수 있음.
df # data.frame보다 발전된 tibble형태로 읽어온다.

#만약 tibble을 쓰기 싫다면
df_2 = as.data.frame(df)
df_2



01_csv.csv

02_tsv.txt

03_xml.xml

04_html_table.html

05_json_simple.json

06_custom.csv

07_xlsx.xlsx


OS별 인코딩

image

  • Mac과 리눅스 : UTF-8
  • Windows : CP949 or Euc-kr


인코딩 문제 해결방법

  • 깨진 글자가 확인 될 경우, File > Reopen with encoding을 통해 아래와 같이 설정한다
    * R환경을 되도록 UTF-8로 고정시켜놓자.
    * windows의 경우, CP949가 default로 설정하기 때문에, 깨지는 것인 MaxOS와 linux에서 온 UTP-8 인코딩이 온 것이 문제임.

    image


문제가 발생한 이유

image

  • Max OS나 Linux에서는 UTF-8로 한글, 중국어, 일본어 등이 인코딩 되어있는 상태에서, 자료가 Windows로 건너오기 때문에 글자가 깨진다.
  • 이러한 것을 해결하기 위해서는 UTP-8로 인코딩을 풀어준 뒤 해결하자.
  • 코딩으로 해결하려면 아래와 같이, 파일을 읽어 들일 때, encoding = "UTF-8" 인자를 넣어주면 된다.

image



실습

setwd('c:/users/is2js/R_da/')

#### 데이터 준비 ####
df = data.frame(aa = 1:3,
                 bb = LETTERS[1:3],
                 cc = c("가나abc", "다라123", "!@마#$바"))
df


#### 인코딩별 저장하기 ####
write.csv(df, "encoding_test_default.csv", row.names = F)
# 윈도우
write.csv(df, "encoding_test_euc_kr.csv",  row.names = F,
           fileEncoding = "euc-kr")
write.csv(df, "encoding_test_cp949.csv",   row.names = F,
           fileEncoding = "cp949")
image
# 맥, 리눅스
# ***윈도우에서 utf8로 저장하게 되면, excel에서 여는 순간 깨진다.
write.csv(df, "encoding_test_utf8.csv",    row.names = F,
           fileEncoding = "utf8")
image


#### UTF-8로 인코딩된 파일을  window에서 읽어오기 ####
# utf8로 저장된 csv를 windows에서 read.csv로 읽으면,, 데이터가 없다고 뜬다.
read.csv("encoding_test_utf8.csv")
image


# 데이터가 존재함을 알기 때문에, readlins로 한줄씩 읽어보자
# 한줄씩은 읽어지나, 깨져서 나온다.
readLines("encoding_test_utf8.csv")
image

# 한줄씩 읽을 때, utf-8 인코딩으로서 읽어보자
# *** 저장시에는 fileEncoding = "uff8" / 읽을 시 encoding="UTF-8"
# 그러나 텍스트가... 구분자 등등이 엉망으로 나온다.
readLines("encoding_test_utf8.csv", encoding = "UTF-8")
image


#### data.table 패키지 - fread()를 이용한 utf8잘 읽어오기 ####
# 1. 설치
install.packages("data.table")
# 2. 사용하기 - data.table + encoding parameter
library("data.table")
fread("encoding_test_utf8.csv", encoding = "UTF-8")
image

# 3. data.table + encoding함수 로 깨진 칼럼 복구시키기
dd = fread("encoding_test_utf8.csv")
dd
Encoding(dd$cc) = "UTF-8"
dd

image


# utf-8 과 cp949/ euc-kr 이 섞여있는 경우 --> 포기하자...

1. R 패키지 설치

2018. 12. 28. 16:56

패키지 설치방법

  • R의 함수와 R명령어의 집합
  • 데이터가 포함되는 경우도 있다.
  • 패키지당 1MB 정도
  • 온라인 저장소 (Cran)에서 다운로드 가능 , 2017. 11 기준 11700개 이상 존재
    - 설치시 dependency : 다른 패키지도 필요하다는 의미, 자동 설치 됨. 만약 자동 설치 안된다면, 해당 패키지를 cran에서 찾아서 설치해야한다.
  • 인터넷이 안되는 경우 ( 망 분리, 큰 패키지 등)
    install.package( 패키지명, repo = NULL, type = "source")
    - cran.r-project.org > Packages > name정렬 > OS에 따라서 설치
    - 인터넷되서 설치한 PC에서 > (windows)문서 > R> win-library > 패키지폴더 > USB


패키지 종류별 설치

setwd('c:/users/is2js/R_da/')

#### 패키지 설치 ####


install.packages("beepr")
# 사용 / 따옴표를 안쓰면 에러 날 수 도 있다.(변수와 중복)
library("beepr")
# 다른 사용(library()안쓰고 바로 사용)
beepr::beep(sound=1)

beep(sound=1)
beep(sound=2)

for(n in 1:10){
   beep(sound = n)
   Sys.sleep(2)
}

#### 유용한 패키지 ####


# 1. dplyr : 파이프라인 관련 join, merge 등 함수 제공
# - Left join / right join 등 sql 비슷한 작업. 기본 R 함수는 어렵고 헤깔림
# - sqldf 패키지를 쓰면 sql과 동일하게 사용가능하기도 함.
# 2. reshape2 : melt <-> decast 함수 지원 -> 통계/시각화 전 피벗팅
# - melt(그림참고) / 반대는 decast
image
# 3. data.table : f.read() f.write() -> read.csv 등과 비교해서 5~10배 이상 빠르다. / data.frame을 발전시킨 형태의 data.table을 제공
# 4. ggplot2, ggmap, ggvis : 데이터 시각화
# 5. lattice : 데이터 시각화
# 6. plotly : 데이터 시각화를 반응형으로
# 7. 기계학습용 : CART, e1071, C50, DMwR
# 8. 시계열 데이터 처리 : lubridate(필수*), xtm
# 9. 텍스트 처리 : splitstackshape(cSplit이 가장 빠름*), KoNLP(한국자연처 처리)


#### 재미난 패키지 ####


# beepr, coinmarketcapr, Rfacebook : API 사용 -> 크롤링으로 대신하는 경우가 많음

+ Recent posts