한의대 생활/└ R studio 통계적 분석1

year <- c(2000:2004)
year

value <- c(2.3, 3.2, 5.6, 5.4, 5.8) # 약간 선형으로 증가하게 만듬

# 기본 plot
plot(year, value)

# 대략적인 2005년도 값 추정하기 위해 선을 그리는데, 오차범위(잔차, residual)가 존재한다
# 각 점들과 선의 오차가 최소로 되도록 선을 긋는 것을 선형모델 Linear Regression model이라고 한다.
lm(value ~ year) # y ~ X

# 오차를 최소로하는 선을 긋는 lm()의 결과값은  절편과 기울기 +@(가 생김
fit <- lm(value ~ year)
fit

# linear regression model의 선을 그래프에 추가
abline(fit)
image

# y가 잘리니까 그래프의 y축 범위 늘려주기
plot(year, value,
      ylim = c(0, 10))

# 선 추가 + 색 추가
abline(fit, col="red")
image

# *** 선<-> 점들 간에 차이인 잔차(residual)을 최소로 하는 선이 그어진다. ***

# *** lm()결과에서 성분들 뽑아보기***
fit$coefficients[[1]] # 1) 절편값
fit$coefficients[[2]] # 2) 기울기
fit$residuals # 3) x 5개의 y값에 대한 선들과의 잔차(y-선)

# *** lm()이후 결과값 fit에 대해 summary()를 하는 버릇을 가지자 ***
# *** 선형 모델이 말이 된다/안된다를 판단하는 대략 기준
# 1) summary()시 *가 찍혀있는지/없는지  2) p-value(선형모델이 우연히 나올 확률*)가 0.05이하인지
summary(fit)


#### 2005 - 100값으로 확 증가하는 1개의 점 추가하고 fit결과를 summary()해보기 ####
year <- c(2000:2005)
value <- c(2.3, 3.2, 5.6, 5.4, 5.8, 100) # 약간 선형으로 증가하게 만듬

fit <- lm(value ~ year)

plot(year, value,
      ylim = c(0, 150))


abline(fit, col="red")

summary(fit) # 1) *가 없어지고 2) p-value가 0.05보다 훨씬 큰 0.13이 나옴. --> 데이터를 설명 잘 못하는 모델이다.
image


#### 더 직선에 가깝게 y값을 조절해보자.
year <- c(2000:2004)
value <- c(2.3, 3.2, 4.9, 5.4, 5.8) # 2003의 값을 더욱 선형에 가깝게 조절

fit <- lm(value ~ year)

plot(year, value,
      ylim = c(0, 10))


abline(fit, col="red")

summary(fit) # 1) ** 2개 2) p-value : 0.006 => 이 선형모델은 우연x 데이터를 잘 설명하는 모델이며 받아들일 수 있다.
image


# ***받아들인 모델을 가지고 다음 값 추정해보기****
# 선형이므로 fit의 결과값 2개인 절편/기울기로  선형식만들어 대입한다( y = ax+b)
predict <- fit$coefficients[[2]] * (2015) + fit$coefficients[[1]]

plot(year, value,
      ylim = c(0, 20),
      xlim = c(2000, 2020))
abline(fit, col="red")


# 예측점 추가
points(2015, predict, col="blue")
image

A <- matrix(c(1, -1, 2, 3), nrow=2)
A
#      [,1] [,2]
#[1,]    1    2
#[2,]   -1    3

#### 2by2 matrix의 determinant 구하기 ####
# A(a b,c d)  D(A) = ad-bc

# 1. 사용자 정의 함수로 det() 흉내내기
det_f <- function(A){
   d <- A[1, 1] * A[2, 2]  -  (A[1, 2] * A[2, 1])
   return(d)
}
det_f(A)

# 2. 내장함수 쓰기 det()
det(A)


#### 2by2 matrix의 역행렬(inverse) 구하기 ####
# 앞에 1/(ad-bc) 곱하기
# a와 d 바꾸기 + b와 c에 - 달아주기

# 1. 사용자 정의함수
inv_f <- function(A){
   B = matrix(, nrow=2, ncol=2) # 빈행렬이지만, 2by2 폼 만들어놓기
   B[1, 1] <- A[2, 2]
   B[2, 2] <- A[1, 1]
  
   B[1, 2] <- -(A[1, 2])
   B[2, 1] <- -(A[2, 1])
  
   # 1/ad-bc 곱해주기
   B <- (1/det(A)) * B
   return( B )
}

inv_f(A)

# 2. 검산    A  %*%  A역행렬 = I (단위행렬)
  ( A %*% inv_f(A) )

# 3. 역행렬 내장함수 solve()와 검산
# ****1.1234134214 e-16같은게 나오면, 전체를 반올림 해주면 된다.
solve(A)
A %*% solve(A)
#             [,1] [,2]
#[1,] 1.000000e+00    0
#[2,] 1.110223e-16    1

round( A %*% solve(A) , 10)
#     [,1] [,2]
#[1,]    1    0
#[2,]    0    1

R markdown

  • 패키지 설치
    image

  • 아래와 같이 생성
    -  title + HTML선택만 해준다.
    image

    image
    image


  • 아래 스크린샷 부분은 설치 방법 & 주석이므로 제거한다.
    image


  • R코드는 ```{r} 으로 시작  ```으로 끝을 낸다.
    image


  • 기본 제공되어있는 코드로 상단의 Knit - Knit to HTML를 눌러보자.
    image


  • 저장시 아무 확장자도 안주어야지 .Rmd로 저장된다. html로 하면 안됨. -. 알아서 .html도 생성된다.
    image


  • 생성된 R markdown - html양식
    - echo = FALSE 라는 인자가 들어간 부분은 -> 코드( plot(pressure) )없이 결과값만 뜬다.
    image
    image


연습해보기

연습한 Rmarkdown.html 코드 복사해넣기

Now we are going to practice matrix functions!! (그냥 글자)

글자 크게(샵 1개)

작은 제목(샵 2개)

nrow = 인자 없이 matrix 생성 -> n by 1 (1열로 나옴)

A <- matrix(c(1, -1, 2, 0, 3, 4))
A
##      [,1]
## [1,]    1
## [2,]   -1
## [3,]    2
## [4,]    0
## [5,]    3
## [6,]    4

nrow = 인자 설정한 matrix 와 단순array

byrow = TRUE 옵션을 주지 않으면, 열을 하나씩 채운다.

A <- matrix(c(1, -1, 2, 0, 3, 4), nrow = 2)
A
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]   -1    0    4
B <- array(1:3)
B
## [1] 1 2 3
is.matrix(A)
## [1] TRUE
is.matrix(B)
## [1] FALSE

array에 2번째 인자인 dimension인자 (c(n,m))을 입력하면 matrix가 된다.

2 by 3에서 모자란 것은 1열씩 차례대로 채운다. array()로 생성하는 matrix에는 byrow옵션이 없다.

A = matrix(c(1, -1, 2, 0, 3, 4), nrow = 2, byrow = TRUE)
A
##      [,1] [,2] [,3]
## [1,]    1   -1    2
## [2,]    0    3    4
C = array(1:3, c(2, 3))
C
##      [,1] [,2] [,3]
## [1,]    1    3    2
## [2,]    2    1    3
is.matrix(C)
## [1] TRUE

행렬의 합, 차, 곱(각 성분들의 곱이 되어버림.) vs 외적%*% ( 양식 맞춰줘야함!** )

A
##      [,1] [,2] [,3]
## [1,]    1   -1    2
## [2,]    0    3    4
C
##      [,1] [,2] [,3]
## [1,]    1    3    2
## [2,]    2    1    3
A+C
##      [,1] [,2] [,3]
## [1,]    2    2    4
## [2,]    2    4    7
A-C
##      [,1] [,2] [,3]
## [1,]    0   -4    0
## [2,]   -2    2    1
A*C # 각 성분들의 곱이 되어버림
##      [,1] [,2] [,3]
## [1,]    1   -3    4
## [2,]    0    3   12
#A %*% C # a by b  외적 b by c 형태여야함.

t(C) # 형태변환(대각선기준 접기!)
##      [,1] [,2]
## [1,]    1    2
## [2,]    3    1
## [3,]    2    3
A %*% t(C)
##      [,1] [,2]
## [1,]    2    7
## [2,]   17   15
A == C # logical 결과(mask)
##       [,1]  [,2]  [,3]
## [1,]  TRUE FALSE  TRUE
## [2,] FALSE FALSE FALSE
t(t(A)) == C
##       [,1]  [,2]  [,3]
## [1,]  TRUE FALSE  TRUE
## [2,] FALSE FALSE FALSE

#### Windows10 MySQL 설치를 위한 APMSETUP7 설치 ####
# APM : Apache, Php, MySQL을 한번에 설치해준다.----> localhost를 치면 웹서버가 보여야 정상.
# http://kldp.net/apmsetup/release/ 에서 최신버전 다운로드
# 3221-APMSETUP7_2010010300.exe
# 관련 사항 확인 : http://nittaku.tistory.com/375

#### MySQL monitor ####
참고페이지 : http://nittaku.tistory.com/375?category=764930
# cmd 켬
# database server 접속 : mysql -uroot -p
# database 확인 : show databases;
# database 사용 : use [해당 db명];
# 해당db속 table 확인 : show tables;
# 해당table속 모든칼럼(*) 가져오기 : select * from 테이블명;


#### 샘플 데이터 다운로드 ####
# cmd로 설명한 페이지
: http://mystyle1057.tistory.com/272
# sample db다운 : http://www.mysqltutorial.org/mysql-sample-database.aspx
# cmd에서 압축을 푼 뒤 해당폴더에 진입mysql monitor에 접속 : 해당폴더 > mysql -uroot -p
# cmd에서 해당폴더에 <source 파일명.sql;> 을 통해 설치 : 해당폴더 > source mysqlsampledatabase.sql
# 기본폴더에서도 목록 보이게 됨 : cmd > mysql -uroot -p > show databases;
image

# *** classicmodel 이라는 db에서 table 중 employees table을 불러올 것임 : use classicmodels; > show tables; > select * from employees;
image



#### DB 확인하기 ####
# cmd > mysql -uroot -p >
# show databases;
# use classicmodels;
# show tables;
# select * from employees;
+-#---------------+-----------+-----------+-----------+---------------------------------+------------+-----------+----------------------+
   #| employeeNumber | lastName  | firstName | extension | email                           | officeCode | reportsTo | jobTitle             |
   #+----------------+-----------+-----------+-----------+---------------------------------+------------+-----------+----------------------+
   #|           1002 | Murphy    | Diane     | x5800     | dmurphy@classicmodelcars.com    | 1          |      NULL | President            |
   #|           1056 | Patterson | Mary      | x4611     | mpatterso@classicmodelcars.com  | 1          |      1002 | VP Sales             |
   #|           1076 | Firrelli  | Jeff      | x9273     | jfirrelli@classicmodelcars.com  | 1          |      1002 | VP Marketing         |
   #|           1088 | Patterson | William   | x4871     | wpatterson@classicmodelcars.com | 6          |      1056 | Sales Manager (APAC) |
   #|           1102 | Bondur    | Gerard    | x5408     | gbondur@classicmodelcars.com    | 4          |      1056 | Sale Manager (EMEA)  |
   #|           1143 | Bow       | Anthony   | x5428     | abow@classicmodelcars.com       | 1          |      1056 | Sales Manager (NA)   |
   #|           1165 | Jennings  | Leslie    | x3291     | ljennings@classicmodelcars.com  | 1          |      1143 | Sales Rep            |
   #|           1166 | Thompson  | Leslie    | x4065     | lthompson@classicmodelcars.com  | 1          |      1143 | Sales Rep            |
   #|           1188 | Firrelli  | Julie     | x2173     | jfirrelli@classicmodelcars.com  | 2          |      1143 | Sales Rep            |
   #|           1216 | Patterson | Steve     | x4334     | spatterson@classicmodelcars.com | 2          |      1143 | Sales Rep            |
   #|           1286 | Tseng     | Foon Yue  | x2248     | ftseng@classicmodelcars.com     | 3          |      1143 | Sales Rep            |
   #|           1323 | Vanauf    | George    | x4102     | gvanauf@classicmodelcars.com    | 3          |      1143 | Sales Rep            |
   #|           1337 | Bondur    | Loui      | x6493     | lbondur@classicmodelcars.com    | 4          |      1102 | Sales Rep            |
   #|           1370 | Hernandez | Gerard    | x2028     | ghernande@classicmodelcars.com  | 4          |      1102 | Sales Rep            |
   #|           1401 | Castillo  | Pamela    | x2759     | pcastillo@classicmodelcars.com  | 4          |      1102 | Sales Rep            |
   #|           1501 | Bott      | Larry     | x2311     | lbott@classicmodelcars.com      | 7          |      1102 | Sales Rep            |
   #|           1504 | Jones     | Barry     | x102      | bjones@classicmodelcars.com     | 7          |      1102 | Sales Rep            |
   #|           1611 | Fixter    | Andy      | x101      | afixter@classicmodelcars.com    | 6          |      1088 | Sales Rep            |
   #|           1612 | Marsh     | Peter     | x102      | pmarsh@classicmodelcars.com     | 6          |      1088 | Sales Rep            |
   #|           1619 | King      | Tom       | x103      | tking@classicmodelcars.com      | 6          |      1088 | Sales Rep            |
   #|           1621 | Nishi     | Mami      | x101      | mnishi@classicmodelcars.com     | 5          |      1056 | Sales Rep            |
   #|           1625 | Kato      | Yoshimi   | x102      | ykato@classicmodelcars.com      | 5          |      1621 | Sales Rep            |
   #|           1702 | Gerard    | Martin    | x2312     | mgerard@classicmodelcars.com    | 4          |      1102 | Sales Rep            |
   #+----------------+-----------+-----------+-----------+---------------------------------+------------+-----------+----------------------+#



#### RMySQL 설치 및 사용 ####
# R은 아주 큰 DB분석에 좋지 않다. 미리 sql에서 추출해서 분석하는 용도로 사용하는게 좋다.

# 1. RMySQL 패미지 설치 및 사용
install.packages("RMySQL")
library(RMySQL)


# 2. database server에 연결하기
# - mysql server가 돌아가는 상태여야 한다.
image

mydb <- dbConnect(MySQL(), user='root', password='rkqhwk12', dbname = 'classicmodels')
mydb


# 3. 쿼리문으로 db에서 테이블들 확인하기
# - 쿼리문을 날릴 때는, 연결된 database를 첫번째 인자로 주고 날린다.

result <- dbGetQuery(mydb, 'show tables;')
result

# 4. 쿼리문으로 table속 row개수 다 세기
dbGetQuery(mydb, 'select count(*) from employees;') # 32

# 5. 쿼리문으로 db속 table 가져오기
tbl <- dbGetQuery(mydb, 'select * from employees;')
tbl


# 여기서부터는 R 문법
# 6. paste()로  2개의 문자열 컬럼을 합친 것을 새로운 칼럼으로 생성하기기***
tbl$name <- paste(tbl$firstName, tbl$lastName)

# 7. 합쳐졌던 2개 칼럼 버리기***(버릴 때는, 인덱싱에서 제외하여 새로운 df를 만들어서 버림)
# 이름을 제일 처음으로 + 2개(2, 3번칼럼) 버리기
newdf <- tbl[c( ncol(tbl), 1, 4:(ncol(tbl)-1)  )]
newdf

# 8. ***gsub(, , 칼럼명)을 이용하여 특정 문자(NA 등) 치환하기***
# NA가 문자열로 포함된 reportsTo 칼럼에서 NA을 치환해준다.
newdf$reportsTo <- gsub('NA', '', newdf$reportsTo) # 문자열 NA만 있던 경우, ''로 대체하면  <NA>의 진짜 결측값을 가진다.
newdf

# 9. nuemeric/factor가  character로 되어있다면 바꿔주기 --> *** summary()에서 통계정보가 안나오기 때문에
# factor화는 factor()도 있었는데, 칼럼단위로으로... 해주려면... as.factor()*** /
# 칼럼단위라도 a$b <- factor(a$b)사용하기도 했었다. ( ggvis - http://nittaku.tistory.com/369)
str(newdf)
summary(newdf)

newdf$officeCode <- as.factor(newdf$officeCode)
str(newdf)
summary(newdf) # office의 범주중 1이 가장 많다..

# 10. 날짜 정보(2018-1-1)같은 정보가 character로 되어있다면  as.Date()로 바꿔주자.***
# 여기에는 없음


#### 11. database 서버와 연결 끊어주기 #### ****
# mysql서버와의 연결만 끊코, db객체는 살아있다.
dbDisconnect(mydb)

# 데이터 준비
mtcars
str(mtcars)
head(mtcars)

# aggregate()를 이용한,  cyl칼럼에 따른, mpg칼럼의 평균값들
aggregate(mtcars$mpg, by=list(mtcars$cyl), mean)

#### ***사용자 정의함수 + if문을 이용해서 aggregate()흉내내기*** ####
# udf의 ()인자에 cyl칼럼이 들어갈 것임...
# 그값이 4, 6, 8일 때,, 그 row들을 인덱싱해서  mpg의 평균
# 만약 함수안에서 변수에 안담기고 함수식만 있다면 -> R은 알아서 return을 해주는 기능이 있다.   변수에 담그면 반드시 return()
mean_by_cyl <- function(x){
   if(x == 4){
     # aggregate로 쓸 경우 : aggregate(mtcars$mpg, by=list(mtcars$cyl), mean)  [1, 2]
     return(    mean( mtcars[ mtcars$cyl == 4, "mpg"] )    )
   }else if(x == 6){
     return(    mean( mtcars[ mtcars$cyl == 6, "mpg"] )    )
   }else if(x == 8){
     return(    mean( mtcars[ mtcars$cyl == 8, "mpg"] )    )
   } else{
     print("잘못 입력되었습니다. 4 or 6 or 8 중에 입력해주세요")
   }
} # if문 끝

mean_by_cyl(4)
mean_by_cyl(6)
mean_by_cyl(8)

mean_by_cyl(7)


# 4, 6, 8은 들어오는 값이니 x로 대체하기
# my) 4 or 6 or 8 인 경우를,,, %in% 으로 대체하기***
mean_by_cyl <- function(x){
   if(x %in% c(4, 6, 8)){
     return(    mean( mtcars[ mtcars$cyl == x, "mpg"] )    )
   }else{
     print("잘못 입력되었습니다. 4 or 6 or 8 중에 입력해주세요")
   }
} # if문 끝

mean_by_cyl(4)
mean_by_cyl(6)
mean_by_cyl(8)
mean_by_cyl(7)

#### **** if문을 써서 aggregate()를 흉내낼 때의 장점 -> 경우의 수별로 문자열 띄울 수 있다.####
# *** return( '문자열', 변수, '문자열') 처첨 섞인 경우에는
# 바로 return 안되므로 paste로 묶어서 하나로 return한다 ***
# *** round( a, 2) --> 소수점 2번째 자리**까지** 표시

mean_by_cyl <- function(x){
   if(x == 4){
     a <- round(mean( mtcars[ mtcars$cyl == 4, "mpg"] ), 2)
     return( paste0('The avg mile per gallon of ', x, ' cylinder car is ', a))
   }else if(x == 6){
     a <- round(mean( mtcars[ mtcars$cyl == 6, "mpg"] ), 2)
     return( paste('The avg mile per gallon of ', x, ' cylinder car is ', a, sep=''))
   }else if(x == 8){
     a <- round( mean( mtcars[ mtcars$cyl == 8, "mpg"] ) , 2)
     return( paste('The avg mile per gallon of ', x, ' cylinder car is ', a, sep=''))
   } else{
     print("잘못 입력되었습니다. 4 or 6 or 8 중에 입력해주세요")
   }
} # if문 끝

mean_by_cyl(4)
mean_by_cyl(6)
mean_by_cyl(8)

#### "MASS" package 와 Aids2 데이터 ####
Aids2 # 패키지가 안깔리면 object를 찾을 수 없다고 뜬다.

install.packages("MASS") # 1. MASS 패키지 설치
library(MASS) # 2. MASS 패키지 사용
data(Aids2) # 3. MASS패키지 속의 Aids2 data사용

Aids2
str(Aids2) # 4. Aids2 데이터 구조 확인
?Aids2 # 5. 데이터 설명보기

head(Aids2) # 6. 데이터 간략하게 보기


#### summary() ####
summary(Aids2)

# age가 0세인 사람도 있는지 위치 확인
Aids2[ Aids2$age == 0, ]
Aids2[ which(Aids2$age == 0), ]


# 살아있는 사람 명수 확인
Aids2[ Aids2$status == "A", ]
length(Aids2[ Aids2$status == "A", ]) # df의 length는 칼럼수가 나와버림..
nrow(Aids2[ Aids2$status == "A", ])


#### aggregate( df$칼럼인덱싱, by=***list(df$기준칼럼인덱싱1, 2) ~에 따른, 통계함수 mean) ####
# *** 살아있는 사람들 중, 성별에 따른, age의 평균
# - sum은 해봤자 의미가없음.. 나이라서

# 1) 살아있는 사람만 인덱싱으로 일단 뽑는다.***
Alive <- Aids2[ Aids2$status == "A", ]

# 2) aggregate()함수를 이용해 ***기준칼럼에 따른 특정칼럼의 평균을 구한다.***
aggregate(Alive$age, by=list( Alive$sex ), mean)

# 3) 죽은사람들 중 성별에 따른 age의 평균 도 마찬가지
Dead <- Aids2[ Aids2$status == "D", ]
aggregate(Dead$age, by=list( Dead$sex ), mean)

####  ***살/죽은 사람을 인덱싱으로 뽑는 과정 없이, 기준칼럼2로 등록하여 한방에 aggregate()로 뽑아보기*** ####
# *** 기준을 2개를 넣는 방법 *** my)2개이상 들어갈 수 있어서,,,미리 by=에 기본적으로 list()를 적어주었구나..
aggregate(Aids2$age, by = list(Aids2$sex, Aids2$status), mean)


#### 1. binomial distribution ####
# 이항분포 : 독립적인 확률을 가진 상태에서, 여러번 던진 경우 앞면이 나오는 확률
# 동전 10번 던져서 3번 앞면이 나올 확률
# - dbinom(성공 횟수, 전체횟수, 각 확률)

dbinom(3, 10, 0.5)
# 4번
dbinom(4, 10, 0.5)
# 5번 째에 peak
dbinom(5, 10, 0.5)
# 6번 부터 다시 작아짐
dbinom(4, 10, 0.5)

#### 2. hypergeometric distribution ####
# populartion size가 있고 -> 추출한 sample size가 따로 있다.
# 10개 공 중의 3개는 빨간색공 / 7개는 흰색공 일 때,
# 추첨을 해서 5개를 뽑았을 때, 빨간공이 2개일 확률
# ex> 한 반에 남자70% 여자30% 총 20명 -> 10명 선발시 남자가 3명일 확률
# - dhypter(남자의 확률, populartion에서 남자의 size, population size에서 여자의 size, 추출한 sample size)

#이항분포( 10번을 뽑아서 3명이 남자일 확률 )
# - dbinom(3명이 남자일 확률, 10명을 뽑았을 때, 각 뽑힐 확률은 0.4)
dbinom(3,10,   0.4)

#**** 초기하 분포 (남+여 10명 중에 남자가 4명 여자가 6명 있다, 여기서 10명을 뽑았을 때, 남자가 3명일 확률은?)
# ->  성공횟수 10중 3 +  이항분포의 확률(0.4)과 같은 population 4 / 10 을 유지하자. 나중 증명을 위해 ***
# -> 10명을 다뽑았는데 남자가 3명일 수없다. 다 뽑혀서 남자4 여자6이다. -> 확률0

# - dhyper(3명이 남자일 확률,    남자size 4명, 여자size 6명,     추출한 사람 10명)
dhyper(3,   4,6,   10) # 0

# 남4 여자6 중에 10명을 뽑았을 때 남자가 4명일 확률? -> 100% = 1
dhyper(4,   4,6,   가10) # 1

# *** 좀 의미있게 문제 바꾸기위해 전체size를2배 늘려보자.(이항분포 확률 0.4 + 성공횟수 10 중 3 유지)
# - 이항분포에서의 남자의 확률과 같은  0.4 + 성공횟수3 을 유지할 수 있도록,
# - 남8여12 중 10명을 뽑았을 때, 남자가 3명일 확률

dhyper(3,  8,12,   10) # 0.24


#### 3. ***이항분포의 확률(0.4)와 같은 확률+ 성공횟수(10중3)을 가진 초기하분포(dhyper)는 전체(population) size가 커지면---> 이항분포(dbinom)과 같아진다. ####

dbinom(3, 10, 0.4) #0.214

dhyper(3,   4,6,     10) # 처음시작 0
dhyper(3,   8,12,    10) # 전체size 2배 0.24
dhyper(3,   12,18,   10) # 전체size 3배 0.233
dhyper(3,   20,30,   10) # 전체size 5배 0.225

#*** 프로그래밍적으로 코드 작성***
# 이항분포의 횟수 4+6 중 3   에서 시작해서
# 전체 size를 100배까지 늘려줄 때,( population size를 4*100 + 6*100 까지 늘임)
# 그릇에 담아서 확률이 이항분포와 같아지는지 확인


a = 100
approx <-numeric(length=a) # a개의 개수(length)를 숫자형 자료벡터(확률이 들어갈 그릇)

for( i in 1:a){
   approx[i] <- dhyper(3,    4*i,6*i    , 10)
}
approx
image


# ***100개의 확률이 어디로 근접하는지 plot으로 확인하자
# approx[1]은 확률이 0이라서,, 그래프가 안그려지더라...?  2부터..
plot(approx[2:100])
image


# *** 초기하분포 확률 plot에다가  이항분포의 확률을 선으로 그려주자.
# *abline( h = 값) - 직선을 그려주는데 h(수평선)을 그려준다.
abline(h = dbinom(3, 10, 0.4), col="red")
image


# 값 차이
approx - dbinom(3, 10, 0.4) # 마지막 100번째엔 0.0005 차이

기존 방식

기준칼럼의 각 값별로 인덱싱 -> 3개의 df에서 특정칼럼만 뽑기 -> 3개의 칼럼을 cbind()로 묶어주기(matrix로 나옴) -> 관찰


#### tapply() : 빠르게 인덱싱하여, 통계(합or평균) 구하기 ####
#  기준칼럼의 각 값별로 쪼개서 -> 특정한 칼럼의(남자 or 여자의 평균, 합)을 얻고 싶을 때
# cyl컬럼의 각 값별로 milages의 평균 구하기

# 데이터 준비
mtcars



#### 기존의 방법으로 구해보기 ####
class(mtcars)
str(mtcars)

# 필요한 1번째, 2번째 칼럼만 뽑아 새로운 데이터프레임 생성
newdata <- mtcars[, 1:2] #*** mtcars[1:2] 1차원형태로 인덱싱해도 df의 칼럼이 뽑힌다.
newdata

# cyl 의 각 값별로 mpg데이터 따로 가져오기
cyl_4 <- newdata [ newdata$cyl == 4, "mpg"]
newdata [ which(newdata$cyl == 4), "mpg"] # 위에 것과 동일한 결과

cyl_6 <- newdata [ newdata$cyl == 6, "mpg"]
cyl_8 <- newdata [ newdata$cyl == 8, "mpg"]

# cyl의 각 값별 mpg 평균구하기
mean(cyl_4)
mean(cyl_6)
mean(cyl_8)

# **** cbind()로 칼럼방향으로 묶어주기
# **** cbind()의 결과값을 보니 [1,] 형태의 1 by 3 matrix!***
cbind(mean(cyl_4), mean(cyl_6), mean(cyl_8))


#### tapply(df$특정칼럼, df$기준범주컬럼, 통계함)을 통한 기준(범주)칼럼의 값 별로 특정칼럼의 통계빠르게 구하기 ####
# - tapply()
tapply(mtcars$mpg, mtcars$cyl, mean)
tapply(mtcars$mpg, mtcars$gear, sum)

대충 정리한 것.

두 변수(2 그룹, matrix의 row들)들이 독립(귀무가설 참)이면 나와야하는 예상값을 가지고, 실제값과 차이를 제곱한 것을   다시 예상값으로 나눈 뒤  -> 각 요소 다 더해주기 -> 그 카이검정 결과값을 가지고 p-value 구해서 귀무가설 거짓 = 변수들 독립을 유의미하다고 확정하기  = 대립가설 채택하기

#### chi-square 카이제곱 검정 ####
# 변수(남/녀- matrix의 행들)들이 독립이냐? 아니면 각 변수들이 결과에 영향을 미치느냐
# ex> 남/녀 그룹이 영향을 줘서 yes/no가 나타났느냐 아니면 우연히 나타났느냐
#     2번째 여자그룹은 no가 훨씬 많으므로, 먼가 영향(유의미한 관계성, 그룹만의 관계성)이 있다?

#### 1. 데이터 준비 - 2by2 matrix ####
# 카이제곱 검정은 각 그룹의 합과 각 대답(yes / no)의 합이 필요하므로 matrix형태의 데이터를 준비한다.
# 1번째 남자 그룹의 yes 42 / no 30,    2번째 여자 그룹의 yes 50, no 87이라고 가정
data <- matrix( c(42, 30,
                             50, 87), nrow = 2, byrow = FALSE)
data


#### 2. 사용자 정의 함수를 일부만 완성시켜 chisq 검정함수의 귀무가설 참인지 알아보기.*** ####
# H0 귀무가설 : 남/녀는 차이가 없다. = 변수들 독립
# chisq 검정 중간 결과의 예상값 matrix : 귀무가설이 참이라면 <나와야 하는 예상된 값 matrix>

# Obs : Observer : 눈에 보이는 값, 여기서는 2by2 matrix
# 예상되는 값 : c(남자그룹 yes/no의 합 , 여자그룹 yes/no의 합) 외적%*% (남+여의 yes의 합, 남+여의 no의합)   /  matrix 전체의 합
# outer(a, b) : 외적, (a %*% b)와  동일
image
# rowSums(), colSums() : matrix의 (각 행, 각 열)별  합  벡터로 반환해주는 함수

rowSums(data) # 72 137
colSums(data) # 92 117
outer(rowSums(data), colSums(data)) # [1,] 6624 12604, [2,]8824 16029
outer(rowSums(Obs), colSums(Obs)) / sum(Obs) #[1,] 6624 12604 [2,] 8424 16029

#*** chisq 검정 사용자 정의 함수 일부만 보기(귀무가설 참인지)***
# 함수에서 나오는 예상 값이   실제값과 유사하면   귀무가설참=남녀독립
chisq <- function(Obs){
   Expected <- outer(rowSums(Obs), colSums(Obs)) / sum(Obs)
   return (Expected)
}

chisq(data) # [1,] 31.69378 60.30622 [2,] 40.30622 76.69378

#### 3. 카이검정 귀무가설에 대한 해석 ####
# 1) 만약 두 그룹(남/녀)가 대답(y/n)에 차이가 없다(=귀무가설 참= 남녀 독립 = 변수들 독립)면 나와야하는 예상 값
# chisq(data)
#       [,1]     [,2]
#[1,] 31.69378 60.30622
#[2,] 40.30622 76.69378

# 2) 실제 값 -> 카이검정 예상값과는 전혀 다른 값을 나타내므로 귀무가설 거짓 -> 남/녀라는 변수(그룹)은 y/n에 영향을 준다!!!!***

# data
#    [,1]   [,2]
# [1,]   42   50
# [2,]   30   87

#### 4. 사용자 정의 함수 완성 : 카이제곱 검정 : 두 변수(그룹)이 독립(귀무가설 참)이면 나와야하는 예상값을 가지고, 실제값과 차이를 제곱한 것을  /  다시 예상값으로 나눠준 뒤,각 요소들을 다 더해주기.####
# sum(  (실제값 - 예상값)^2 / 예상값  )
chisq <- function(Obs){
   Expected <- outer(rowSums(Obs), colSums(Obs)) / sum(Obs)
   return( sum( (Obs - Expected)^2 / Expected ))
}

chisq(data) # [1] 9.132947


#### 5. 카이제곱 검정 결과가 유의미한지 알기 위해 p-value값 구하기 ####
# p-value : 전체 값 - pchisq( 카이제곱 검정 결과, 자유도 )
# 자유도 : n by m matrix에서는 (n-1)*(m-1)로 구한다.
# pchisq( chisq , 자유도 )는 R에서 기본제공되는 함수, 카이제곱 검정결과, 자유도를 대입하면 넓이(%)가 나온다.

1 - pchisq(9.132947, (2-1)*(2-1)) # 0.00251047

#*** p-value 값이 0.0025 로 0.05보다 작으므로 --> 귀무가설 거짓(=예상값과 실제값차이 많이 남 = 변수들 독립)이 유의미하다 라는 결론을 내릴 수 있다.
# > 귀무가설H0를 파기하고 독립x 차이가 있다. -> 대립(대체) 가설을 채택 함.


#### 6. 간단하게 존재하는 함수 ####

# Pearson's Chi-squared test with Yates' continuity correction
chisq.test(data) # X-squared = 8.2683, df = 1, p-value = 0.004034
# correction 이 들어가기 때문에, 원조 카이제곱 검정과 값이 차이난다.

#Pearson's Chi-squared test
chisq.test(data, correct = FALSE) # X-squared = 9.1329, df = 1, p-value = 0.00251

#### normal distribution ( mean=80, sd=10 ) ####
# 1. x의 범위 정하기 **** 많이 빼먹는다**** sd가 10이면, 평균 80좌우로 3~4배 왔다리 갔다리 면 충분하다.
x <- seq(40, 120, length = 300) # ***연속 정수는 c(40:120) 겠지만, 연속실수범위는 seq(from=,to=, by=증감도, length = 구간 개수 )
x
# 2. dnorm(구간속 x값, mean, sd) :  x구간 속 300개의 각 값들에 대한 정규분포 만들어주기
y <- dnorm(x, mean = 80, sd = 10)
# 3. 단순 plot(x, y)그리기
plot(x, y) # 동그라미들은 x에 대응하여 300개..
plot(x, y, type = "l") # 동그라미를 type="l"로 라인으로
plot(x, y, type = "l", col = "red") # 색도..

image

# plot(type="l") 대신 lines()함수로 바로 그릴 수 있다.
# sd 5
#lines(x, dnorm(x, mean = 80, sd = 5), col = "blue")

image


# 1. dnorm() : x범위에 대해 해당 정규분포의 <전체 분포>를 그릴 때 y값
# 2. pnorm() : x범위에 대해 해당 정규분포의 <넓이 = percentage>를 구할 때
#   - %는 왼쪽끝에서 시작한 영역이 반환됨. (lower.tail = TRUE 가 default)
# 3. qnorm() : 정규분포의 영역에 대해, x값(cutoff)를 구할 때
#   - %, 넓이를 인자로 넣을 땐, 1보다 작은 소수점으로 대입

# 4. rnorm() : 임의의 정규분포


#### 문제1. 65 ~ 75까지는 몇 확률(% ->pnorm, 넓이*100)에 해당할까? ####
# 참고) 정규분포의 일부영역을 그래프로 그리기
x_cf <- seq(65, 75, length = 200) # 해당영역 x범위 정하기
y_cf <- dnorm(x_cf, mean = 80, sd = 10) # y에 똑같은 정규분포 그리기
polygon( c(65, x_cf, 75), c(0, y_cf,0 ), col="gray") # polygon(c( 아래변 ), c(덮는 윗변), col="배경색")

image

# ***정규분포의 %, 넓이를 구하는 문제이므로 pnorm()을 사용한다.
# pnorm( %(넓이*100), mean, sd)
# 큰 면적 - 작은면적의 원리이다.

pnorm(75, mean = 80, sd = 10) # 0.308
pnorm(65, mean = 80, sd = 10) # 0.066
pnorm(75, mean = 80, sd = 10) - pnorm(65, mean = 80, sd = 10) # 0.2417



#### 문제2. x=92보다 클 때의 확률(%->pnorm)은?
# -> 92일의 pnorm을 구한 다음, 1에서 빼자.
pnorm(92, mean = 80, sd = 10) # 0.884
1 - pnorm(92, mean = 80, sd = 10) # 0.1150697
# *** 오른쪽끝에서 92까지의 면적을 구하고 싶다면 lower.tail = FALSE로 준다)
pnorm(92, mean = 80, sd = 10, lower.tail = FALSE) # 0.1150697



#### 문제3. x가 68보다 작을때의 확률은? ####
pnorm(68, mean = 80, sd = 10) # 0.115069


#### 문제4. 하위 30%를 잘라내는 cutoff( % -> x구하기 : qnorm)는?
# *** 정규분포 영역에 대한 -> x값을 구할때는 qnorm()을 사용한다.
# *** 첫번째 인자에서는 영역의 %-> /100 이므로 1보다 작은 소수점으로 넣어줘야한다.

qnorm(0.3, mean = 80, sd = 10) # 30% -> 0.3으로 대입할 것!**** : 74.75


#### 문제5. 하위 80% 자르는 지점은?
qnorm(0.8, mean = 80, sd= 10) # 88.41


#### 문제6. 중간 60%를 자르는 지점은?
# 하위20%, 상위20 **= 하위80% 을 찾는다...
qnorm(0.2, mean = 80, sd= 10) # 71.58
qnorm(0.8, mean = 80, sd= 10) # 88.41


#검산해보기*** 2개의 값이 대칭(하위20, 상위20)인가?
# 평균은 80에서 하위20%의 x값을 빼면,, 그 절대값이 똑같아야함.
80 - qnorm(0.2, mean = 80, sd= 10) # 8.416
80 - qnorm(0.8, mean = 80, sd= 10) # -8.416

strsplit( , split="") + paste( , collaspe ="")를 이용해 문자열 역순으로 반환하기


#### strsplit() - 결과는 [[1]] 리스트인 것 유의! ####
#*** 실제로 띄워쓰기가 있는 경우 많이 쓰인다.
strsplit("adfawwsfwwdsfwa", split="w") # 기준이되는 w는 사라진다.
# 띄워쓰기를 쪼개기g
strsplit("how are you?", split=" ")


# *** 모든 단어 쪼개기 , split="" ***
strsplit("how are you?", split="")
a <- strsplit("how are you?", split="")
a #a를 확인해보니, [[1]]형태의 리스트이다.****
class(a)


# 다시 합치기
paste(a) # ***strsplit()으로 쪼개면, list형태의 [[]]로 반환되기 때문에 바로 못붙힌다.***
class(a[[1]]) #character 벡터
paste(a[[1]]) # 붙은 것 같으나 따옴표로 연결되어있다.
paste(a[[1]], collapse = "") # strsplit()으로 쪼갠 문자열 리스트는, [[1]]해도 바로 안붙고, collapse인자로 큰따옴표를 붕괴시켜야 제대로 붙는다.


#### 실전 ####
# 글자가 앞뒤가 바뀌도록 하는 함수 만들기***
# 1. strsplit( , split = "") 로 모든 단어 다 쪼개기
splited <- strsplit("I love you, daisy Kim!", split="")

# 2. 쪼개진 단어들 역순시키기기
#  - ***원소들의 인덱싱을 역순으로 해주면 된다.***
length(splited[[1]]) # 리스트 속 쪼개진 문자열 데이터의 개수
#  - ***만약 원래 String을 가져올 수 있다면 nchar(string)으로 하면된다.
#  - 끝:1로 역순으로 인덱싱하여 역순으로 바꾸자.
splited[[1]] [ length(splited[[1]]) : 1]
reversed <- splited[[1]] [ length(splited[[1]]) : 1]
# 3. paste(, collapse=="")로 쪼개진 단어들 붙히자.
paste(reversed, collapse = "")



#### 글자 역순으로 바꾸는 사용자 함수 정의 ####
reverse_char <- function(string){
   splited <- strsplit(string, split="")
   # 원본 문자열전체를 string으로 알고 있으니, nchar(string)만 해주면, 쪼개진 단어의 끝 번호를 알 수 있다.
   reversed <- splited[[1]] [nchar(string):1]
   result <- paste(reversed, collapse = "")
   return(result) # return과 for 다음에 바로 ()가 필요하다!***
}


reverse_char("안녕하세요")
reverse_char("how are you?")



strsplit( , split=" ") + paste( , collaspe =" ")를 이용해 단어 역순(reverse)으로 반환하기

# 지난시간 모든 글자 쪼개기
a <- strsplit("how are you?", split="") #split = ""를 통해 모든글자 쪼개기


#### 단어를 역순으로 배열하기 ####
# 1. 단어별로 쪼개기
splited <- strsplit("how are you?", split=" ") #split = " "를 통해 단어별로 쪼개기
splited


# 2. 쪼개진 단어들의 갯수 끝번호 : 1  -> 반대로 인덱싱하여 역순으로 배열하기
reversed <- splited[[1]] [length(w[[1]]) : 1]
reversed


# 3. 합치기
paste(reversed, collapse = " ") # collapse = " "를 통해 단어별로 합치기


# 4. 함수로 만들기
reverse_word <- function(string){
   splited <- strsplit(string, split=" ")
   reversed <- splited[[1]] [length(splited[[1]]) : 1] # 글자쪼개기와 다르게 nchar(string)는 글자 총 몇개 <---> 여기서는 쪼개진 단어가 몇개의 데이터인지 알아야한다.
   return(paste(reversed, collapse = " "))
}


reverse_word("안녕 하세용!")

mtcars
cars <- rownames(mtcars)
which(nchar(cars) == max(nchar(cars)))
cars[which(nchar(cars) == max(nchar(cars)))]

#### grep() ####
# 특정 문자열을 포함하는 데이터의 < 1) index  2) <문자열 전체>(value=TRUE)>를 반환한다.
# *** 주소에서 성북동을 포함한 주소를 검색하는 경우 등에서 사용된다.

# grep("문자열", data)
# grep("문자열", data, value = TRUE)
# ***대소문자 구분해버리므로 둘다 불러오고 싶다면 ***
# 1) grep("[vV]", data, value = TRUE)
# 2) 데이터 자체를 소문자나 대문자로 변환시킨 뒤 -> grep()을 쓴다.

# ***my)   cars %in% c("z") 는 포함관계가 아니라, 특정값 자체를 <or연산 : | | |>여러개 대신 연속(1:3)or이산(c(1, 3, 5)으로 쉽게 필터링에 쓸 수 있다. http://nittaku.tistory.com/352?category=764233

cars
grep("z", cars) # 1 2 --> 1번째 데이터, 2번째 데이터에서 가진다.
grep("z", cars, value = TRUE) # 실제 전체문자열을 보려면 value = TRUE 인자를 넣어준다.

grep("rd", cars, value = TRUE)

# ***대소문자 모두 포함된 문자열을 가져올 경우***
grep("[vV]", cars, value = TRUE)
# ***데이터 자체를 대문자 or 소문자로 바꾼 뒤 grep()하기 ****
grep("v", tolower(cars), value = TRUE)

grep("toyota", cars, value = TRUE )
grep("toyota", tolower(cars), value = TRUE )
grep("TOYOTA", toupper(cars), value = TRUE )


#### stringr 패키지 ####
#### ...L 1) str_count(df, "문자열") ####
# 문자열데이터 각각에 대해, 특정 문자열을  <몇개> 포함하고 있는지를 각 문자열데이터에 대한 벡터 반환해준다.
# *** 전체 자동차 리스트에서 sum()을 씌워, 해당 모델이 몇개 포함되어있는지 알 수 있다. ***
# *** 조씨 성을 가진 사람이 <몇명>인지 알 수 있다.

# str_count(df, "문자열")
# grep("문자열", df, value = TRUE)와는 인자가 순서가 다르다.

install.packages("stringr")
library(stringr)

cars
str_count(cars, "t") # (df, "문자열") -> 0 0 1 1 3 1 1 1 식으로 문자열 포함개수를 알려줌
str_count(cars, "o")

# 실전 - sum()을 마지막에 씌워, 전체 문자열데이터에서, 해당 브랜드 자동차모델이 몇개 가지고 있는지 알 수 있다.
str_count(toupper(cars), "TOYOTA") # 2개 발견
sum( str_count(toupper(cars), "TOYOTA") )

#### paste(,sep=" "), paste0( ) 함수 - 깨진 데이터, 끊긴 데이터를 합칠 때 ####
hi <-paste("hi", "Jack") # paste()함수는 붙혀넣기다.

# 끊킨 데이터를 붙혀주는 2가지 함수
# my) 구분자를 넣어서 붙히고 싶다면 paste(), 구분자 없이 바로 붙히려면 paste0()
paste("jac", "k") # "jac k"   ***paste()의 sep의 default는 " " 띄워쓰기 1칸이 있다.
paste("jac", "k", sep = "") # "jack"
paste0("jac", "k") # "jack"

paste("Hi", "jack", sep = ", ") # "Hi, jack"

#### 실전 응용 ####
#*** 1-1반부터 1-10반까지 붙혀넣어보자.
# 만약 모른다면,,,
c("1-1", "1-2", "1-3") #...
#my)...
global_object <<- character(10) # 전역변수는 생성시만 <<-      함수안이라도  대입은 <-
for(n in 1:10) {
   global_object[n] <- paste0("1-", as.character(n))
   }
global_object
#### *** paste() + 연속변수로 생성하면 ####
# "1"고정 / sep= "-" 구분자 / 나머지는 1:10까지 연속변수 생성
paste("1", 1:10, sep="-" )


# 따옴표를 제거하고 출력하기
a <- paste("The value of 'pi' is ", pi, ", endless!")
noquote(a) # 문자열에서 따옴표 제거하고 출력방법 1 ***
print(a, quote=FALSE) # 문자열에서 따옴표 제거하고 출력방법 1 ***



# rownames() 데이터에서 행이름만 가져오기
data("mtcars")
rownames(mtcars) # colnames는 자주썼었다.
#my) 행을 쉽게 보는 방법 t()
t(t(rownames(mtcars)))
colnames(mtcars) # colnames()

#nchar() 문자열 길이 확인( 문자열 벡터도 한번에 확인가능 )
nchar("조재성")  # nchar() 문자열 길이를 벡터로 나타내준다. -> 3
length("조재성") # length() 데이터(문자열 벡터)의 개수다.     -> 1
nchar(rownames(mtcars))

# which( 조건문 )로 가장 긴 이름 찾기 ********
# - which( 칼럼인덱싱 조건문 )으로 해당row를 반환하여 확인했었다. http://nittaku.tistory.com/336
# - which(sample[,1] == "ccd")
# 1) ncha()를 이용하여 문자열 길이를 벡터로 반환받기
# 2) nchar() == max( nchar() )를 조건문으로 해서
# 2) 문자열길이 벡터에 which( 조건문 )를 써서 가장 큰 값 받환하기

cars <- rownames(mtcars)
which( nchar(cars) == max(nchar(cars)) ) #16
cars[16]
# 한 문장으로 뽑아내기 - 인덱싱자리에서 넣기
cars[ which( nchar(cars) == max(nchar(cars)) )] # 1차원...

x <- 'what is your name?'
x <- "what's your name?" #작은따옴표를 안에 쓰려면 큰따옴표로

# character() 인자에 빈값을 넣으면?
y <- character() # my) character()를 사용하면 문자열 1차원 벡터가 생성
y #***character(0) = 빈값의 character 벡터라고 뜬다.
class(y) # 속성은 character
length(y) #길이(=데이터의 개수) 0인 character

# 케릭터 객체에 ""을 넣으면?
y2<-""
y2 # ""
class(y2) #속성은 character
length(y2) # ***length는 문자열 데이터의 개수... 문자열 길이 아님!***

length("1") # "1"도 길이가 1이지만,  ""도 길이가 1이다!! length는 문자열의 데이터의 개수 <---> nchar() 문자열 길이

y3 <- c("e", "12", "2") # 문자임

y4 <- character(10)
y4 # *** 큰따옴표가 10쌍이다.
# 3번째에다가 값을 넣어보자.
y4[3] <- "third"
y4 # "" "" "third" "" ...

# 10개까지만 있는 문자열 벡터에다가 12번째에 값을 넣어보면?
y4[12] <- "twelveth"
y4 # ***11번째에는 NA(결측치)가 차고,  12번째에 값이 들어간다
length(y4) # 길이는 12가 된다.

y4[11] <- "11"
y4


# 문자열인지 확인하기
n = 3
m = "3"
# 아래 부분이 필요한 것은 함수 속 if문...에서... 문자열/숫자 확인할 때!
is.character(n) # FALSE
is.character(m) # TRUE

class(n)
class(m)

#아래부분이 필요한 것은, 엑셀 등에서 가져온 자료가 숫자가 아니라 문자열일 경우 바꿔주기
n2 = as.character(n)  # 3 -> "3"
class(n2)

# 문자열은 1차원 벡터에 있어서, 자료형이 우선순위
t <- c(1:5) # 1, 2, 3, 4, 5

# 1차원 벡터에 있어서, 하나라도 문자열이 들어가면 모두 따옴표가 붙어 문자열이 되어버린다.
t2 <- c(1:5, "a")
t2 # "1", "2", "3", "4", "5", "a"

# 숫자 + logical을 섞는다면?
t3 <- c(1:5, TRUE, FALSE)
t3 # ***logical도 컴퓨터는 1, 0으로 알아듣는 숫자다
class(t3)


t4 <- c(1:5, TRUE, FALSE, "a")
t4 #문자열이 하나라도 섞이면 전부다 따옴표가 붙고, 문자열이 된다.
#***이 때, TRUE는 "1"이 아니라 "TRUE"로 바뀐다.


df1 <- data.frame( n       = c(1:5), #df는 각 요소의 개수가 딱맞는 사각형이어야한다.
                    letters = c("a", "b", "23", "1", "24") )
df1
# **** data.frame에서는 문자열을 "따옴표"로 표시해주지 않는다! ****
# ***data.frame의 형식을 문자열 따옴표를 보는 방법은 str()을 이용하는 것이다 ***
str(df1) # factor도 문자열을 포함한다?

df2 <- data.frame( n       = c(1:4, "a"), #df는 각 요소의 개수가 딱맞는 사각형이어야한다.
                    letters = c("a", "b", "23", "1", "24") )
str(df2) # data.frame도 칼럼별로 문자열이 자료형 우선순위를 가진다.

# my)***
df2 <- data.frame( n       = c(1:4, "a"), #df는 각 요소의 개수가 딱맞는 사각형이어야한다.
                    letters = c("a", "b", "23", "1", "24"),
                    stringsAsFactors = FALSE)
# 이전에 배운 sapply()로 칼럼별로 class를 본다.
apply(df2, MARGIN = 2, FUN = "class")
sapply(df2, "class")

install.packages("tidyr") # 정리할 때 좋은 패키지
install.packages("dplyr")# 자료를 빨리 찾아볼 때 좋은 패키지 (필터링 패키지)


library(dplyr)

# 데이터 준비
# 3가족이 사는데, f여자, m남자에 대한 이름과 나이 정보

member = data.frame(family = c(1, 2, 3),
                     namef  = c("a", "b", "c"),
                     agef   = c(30, 40, 23),
                     namem  = c("d", "e","f"),
                     agem   = c(44, 53, 25))
member
# data.frame의 현재형태는 각 가족에 대해서 보기 편할 수 도 있다.
# 예를 들어, 1번 가족에 a(30세), d(44세)가 있다. 이런식이다.
# 하지만, 데이터 분석에 있어서는 안좋다.
# 예를 들어, 여자멤버는 누가 있고, 나이에 따른 분포 등을 알기 어렵다
# 즉, 그래프를 그리기 쉽지 않다.

image


### 문제 : 데이터에서 namef, namem이 아닌 f/m를 따로 표시해서 알아보기 ###

#### 1. tidyr(타이디 r)을 이용해서 정리하기 ####
library(tidyr)
#### ...L 1) gather() ####
# 여러칼럼들을 칼럼들을 --> 1개의 칼럼key - value 값을 형태로 모아주는 함수
# gather( df, key*칼럼명 모을칼럼명, value*모을값의 칼럼명, 식별칼럼제외 모을 칼럼범위a:b)
# *** 이 때, 식별칼럼에 해당하는 family칼럼은 제외하고 모아준다. 만약 식별칼럼까지 모아버리면, 모으기전 같은 라인에 있던 이름-나이 의 연관성이 사라져버린다.

# *** reshape2패키지의 melt()와 매우 유사함.(http://nittaku.tistory.com/349)
# gather(membe(df), key(칼럼명모은 칼럼명), value(값 모은 칼럼명), family:agem) : 식별칼럼family까지 모으면, 모이기전의 값들이 연관성이 없어져버린다.
# ex> 1-namef-a / 1-agef-30 ==> namef-a 와 agef-30의 이름과 나이의 연관성이 사라져버림
gather(member, key, value, namef:agem)
a <- gather(member, key, value, namef:agem)
image

#### ...L 2) separate() ####
# 특정 칼럼의 값 -> 2개로 쪼개면서 2개의 칼럼 생성
# - gater로 모아진 데이터를 이용해서, 특정칼럼의 값을 쪼갠다.
# separte(값을 쪼갤df, 쪼갤칼럼명, c("쪼갠칼럼1", "쪼갠칼럼2"), 쪼갠위치)
b <- separate(a, key, c("variable", "type"), -1) # 뒤에서

image

#### ...L 3) spread() ####
# key-value형태의 칼럼을 --> key값을 기준으로 여러칼럼으로 생성 + value은 각각에 따라붙음
# ***reshape2의 dcast()와 비슷한 듯 : http://nittaku.tistory.com/349
# 여러칼럼들을 모아서 필요한 처리이후, 다시 name과 age를 분리하기
# spread(칼럼명/ 값 칼럼을 <칼럼명의 값의 이름으로> 2개칼럼으로 나눌df, 나눌 칼럼명, 따라붙을 값 칼럼)
new <- spread(b, variable, value)
image

### *** my) gather()와 spread()는 값은 따라이동하기만 하고, 칼럼을 뭉치고/나눈다. ***


#### 2. dplyr패키지의 filter()함수로 여자만 필터링하기 ####
## dyplr패키지의 filter함수는 벡터연산의 [df$칼럼명 , ]과 달리
## filter(df, 칼럼명 == )으로 바로 인덱싱 but 자동완성x http://nittaku.tistory.com/352
filter(new, type == "f")
filter(new, age >= 30)

image


#### 3. 만약, tidyr로 정리한 데이터가 아니라면?  ####
# (1) select( df, 가져올칼럼1, 가져올칼럼2, 가져올칼럼3)함수를 통해,
#     df에서 f붙은 특정칼럼들만 가져온다.
select(member, family, namef, agef)
# (2) 벡터연산[,]을 통해 열만 인덱싱해준다.
member[,c("family", "namef", "agef")]
# 그러나 특정나이 이상인 모든 사람들을 가져오게할 때.. 쉽지가 않다.
# agef, agem 칼럼이 2개이기 때문...
image


#### 4. 파이프라인(%>%)을 통한 tidyr 함수3개 연속 사용하기 ####
# 파이프라인을 사용할 때는, 아래와 같은 형식이며
# 각 함수에서 df는 생략된다.

new2 <- member %>%
         gather(key, value, namef:agem) %>%              #칼럼들을 key-value로뭉치기
         separate(key, c("variable", "type"), -1) %>%    #값을 2개 칼럼으로 나누기
         spread(variable, value)                         #key-value를 key값별로 칼럼나누
new2

image

+ Recent posts