write

[Fastcampus] RDC 강의 내용 정리 - 이부일 강사님

상관분석(Correlation Analysis)

When?
두 양적 자료 간에 관련성(직선의 관계 = 선형의 관계)이 있는지를 통계적으로 검정하는 방법

예제 데이터 : cars(speed, dist), attitude


1. 산점도(Scatter Plot)

(1) 기본

plot(x - data$variable, y - data$variable)
plot(cars$speed, cars$dist)

# 한 화면에 여러개 plot 출력
par(mfrow = c(2, 3))
for(i in colnames(attitude)[2:7]){
    plot(attitude[ , i], attitude$rating,
         main = paste("rating vs ", i),
         xlab = i,
         ylab = "rating",
         col = "blue",
         pch = 12)
}
par(mfrow = c(1, 1))


(2) 산점행렬도(SMP : Scatter Matrix Plot)

plot(iris[ , 1:4])


(3) 3D 산점도 : rgl, car package

with(iris,
     plot3d(Sepal.Length,
            Sepal.Width,
            Petal.Length,
            type="s",
            col=as.numeric(Species)))


scatter3d(x = iris$Sepal.Length,
          y = iris$Petal.Length,
          z = iris$Sepal.Width,
          groups = iris$Species,
          surface=FALSE,
          grid = FALSE,
          ellipsoid = TRUE,
          axis.col = c("black", "black", "black"))

(4) corrplot package

corrplot::corrplot(cor(iris[ , 1:4]), method = "circle")




2. 상관계수(Coefficient of Correlation)

두 양적 자료의 관련성(직선의 관계 = 선형의 관계) 정도를 수치로 알려줌
cor(datavariable,datavariable, datavariable, method = c("pearson", "spearman", "kendall"))

> cor(cars$speed, cars$dist, method = "pearson")
[1] 0.8068949

> cor(attitude, method = "pearson")
              rating complaints privileges  learning    raises  critical   advance
rating     1.0000000  0.8254176  0.4261169 0.6236782 0.5901390 0.1564392 0.1550863
complaints 0.8254176  1.0000000  0.5582882 0.5967358 0.6691975 0.1877143 0.2245796
privileges 0.4261169  0.5582882  1.0000000 0.4933310 0.4454779 0.1472331 0.3432934
learning   0.6236782  0.5967358  0.4933310 1.0000000 0.6403144 0.1159652 0.5316198
raises     0.5901390  0.6691975  0.4454779 0.6403144 1.0000000 0.3768830 0.5741862
critical   0.1564392  0.1877143  0.1472331 0.1159652 0.3768830 1.0000000 0.2833432
advance    0.1550863  0.2245796  0.3432934 0.5316198 0.5741862 0.2833432 1.0000000

> round(cor(attitude, method = "pearson") , digits = 3)
           rating complaints privileges learning raises critical advance
rating      1.000      0.825      0.426    0.624  0.590    0.156   0.155
complaints  0.825      1.000      0.558    0.597  0.669    0.188   0.225
privileges  0.426      0.558      1.000    0.493  0.445    0.147   0.343
learning    0.624      0.597      0.493    1.000  0.640    0.116   0.532
raises      0.590      0.669      0.445    0.640  1.000    0.377   0.574
critical    0.156      0.188      0.147    0.116  0.377    1.000   0.283
advance     0.155      0.225      0.343    0.532  0.574    0.283   1.000

> round(cor(iris[ , 1:4], method = "pearson") , digits = 3)
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length        1.000      -0.118        0.872       0.818
Sepal.Width        -0.118       1.000       -0.428      -0.366
Petal.Length        0.872      -0.428        1.000       0.963
Petal.Width         0.818      -0.366        0.963       1.000```


3. 상관분석

  • 귀무가설 : speed와 dist 간에는 관련성이 없다.
  • 대립가설 : speed와 dist 간에는 관련성이 있다.
    cor.test(datavariable,datavariable, datavariable, method = "pearson")
> cor.test(cars$speed, cars$dist, method = "pearson")

	Pearson's product-moment correlation

data:  cars$speed and cars$dist
t = 9.464, df = 48, p-value = 1.49e-12
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.6816422 0.8862036
sample estimates:
      cor
0.8068949

유의확률이 0.000이므로 유의수준 0.05에서 speed와 dist 간에는 통계적으로 유의한 양의 상관관계가 있는 것으로 나타났다.
즉, speed가 증가하면 dist도 증가하는 경향을 보인다.



  • 귀무가설 : rating과 complaints 간에는 관련성이 없다.
  • 대립가설 : rating과 complaints 간에는 관련성이 있다.
> cor.test(attitude$complaints, attitude$rating, method = "pearson")

	Pearson's product-moment correlation

data:  attitude$complaints and attitude$rating
t = 7.737, df = 28, p-value = 1.988e-08
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.6620128 0.9139139
sample estimates:
      cor
0.8254176

유의확률이 0.000이므로 유의수준 0.05에서 complaints와 rating 간에는 통계적으로 유의한 매우 높은 양의 상관관계가 있는 것으로 나타났다.



Quiz.

rating과 나머지 6개 변수 간의 관련성 검정을 해 보세요.

# for문 활용
for(i in colnames(attitude)[2:7]){
    print(cor.test(attitude[ , i], attitude$rating, method = "pearson"))
}

# corr.test 패키지 활용
> psych::corr.test(attitude, method = "pearson")

Call:psych::corr.test(x = attitude, method = "pearson")
Correlation matrix
           rating complaints privileges learning raises critical advance
rating       1.00       0.83       0.43     0.62   0.59     0.16    0.16
complaints   0.83       1.00       0.56     0.60   0.67     0.19    0.22
privileges   0.43       0.56       1.00     0.49   0.45     0.15    0.34
learning     0.62       0.60       0.49     1.00   0.64     0.12    0.53
raises       0.59       0.67       0.45     0.64   1.00     0.38    0.57
critical     0.16       0.19       0.15     0.12   0.38     1.00    0.28
advance      0.16       0.22       0.34     0.53   0.57     0.28    1.00
Sample Size
[1] 30
Probability values (Entries above the diagonal are adjusted for multiple tests.)
           rating complaints privileges learning raises critical advance
rating       0.00       0.00       0.19     0.00   0.01     1.00    1.00
complaints   0.00       0.00       0.02     0.01   0.00     1.00    1.00
privileges   0.02       0.00       0.00     0.07   0.15     1.00    0.51
learning     0.00       0.00       0.01     0.00   0.00     1.00    0.03
raises       0.00       0.00       0.01     0.00   0.00     0.36    0.01
critical     0.41       0.32       0.44     0.54   0.04     0.00    0.90
advance      0.41       0.23       0.06     0.00   0.00     0.13    0.00

 To see confidence intervals of the correlations, print with the short=FALSE option


Quiz.

housing data : price와 관련성이 있는 상위 6개의 변수명, 상관계수, t값, p-value를 출력하시오.

houseDF <- readxl::read_excel(path      = "kc_house_data.xlsx",
                              sheet     = 1,
                              col_names = TRUE)
View(houseDF)
houseDF$year <- 2018 - houseDF$yr_built
remove.variables <- c("id", "date", "floors", "waterfront", "view",
                      "condition", "yr_built", "yr_renovated",
                      "zipcode", "lat", "long")

houseDF2 <- houseDF %>%
    select(-one_of(remove.variables))
    #psych::corr.test()

corr.result <- psych::corr.test(houseDF2)
str(corr.result)
corr.result$r[ , 1]
str(corr.result$r)
top6.r <- round(sort(corr.result$r[, 1], decreasing = TRUE)[2:7], digits = 3)
top6.t <- round(sort(corr.result$t[, 1], decreasing = TRUE)[2:7], digits = 3)
top6.pvalue <- round(sort(corr.result$p[, 1], decreasing = TRUE)[2:7], digits = 3)
top6.variables <- names(round(sort(corr.result$r[, 1], decreasing = TRUE)[2:7], digits = 3))
plot(houseDF2[ , c(top6.variables, "price")])

corrDF <- data.frame(Variables = top6.variables,
                     r = top6.r,
                     t = top6.t,
                     pvalue = top6.pvalue)
writexl::write_xlsx(corrDF, path = "correlationResult.xlsx")


01Basic

[Fastcampus] RDC 강의 내용 정리 - 이부일 강사님

분산분석(ANOVA : Analysis of Variance)

When?
세 개 이상의 집단 간에 양적 자료에 차이가 있는지를 통계적으로 검정하는 방법

Use library & data

require("readxl")
require("nortest")
require("nparcomp")
require("PMCMR")
require("PMCMRplus")
require("writexl")

houseDF <- readxl::read_excel(path      = "kc_house_data.xlsx",
                              sheet     = 1,
                              col_names = TRUE)
View(houseDF)
str(houseDF)
table(houseDF$condition)
houseDF$condition <- as.factor(houseDF$condition)


1. 질적 자료 1개, 양적 자료 1개

질적 자료는 3개 이상의 유한 집단으로 구성되어 있어야 함.

  • 귀무가설 : condition에 따라 price에 차이가 없다.
  • 대립가설 : condition에 따라 price에 차이가 있다.

1단계 : 정규성 검정

  • 귀무가설 : 정규분포를 따른다.
  • 대립가설 : 정규분포를 따르지 않는다.
by(houseDF$price, houseDF$condition, ad.test)

2단계 : 정규성 가정이 만족이 되었다면

분산분석 : ANOVA
분산분석 결과 <- aov(양적자료 ~ 질적자료, data = dataname)

anova.result <- aov(price ~ condition, data = houseDF)
summary(anova.result)

<결과>
               Df           Sum Sq       Mean Sq F value       Pr(>F)    
condition       1    3851399435634 3851399435634   28.61 0.0000000894 ***
Residuals   21611 2909065362485666  134610400374                         
---
Signif. codes:  0***0.001**0.01*0.05 ‘.’ 0.1 ‘ ’ 1

유의확률이 0.000이므로 유의수준 0.05에서 condition에 따라 price에 통계적으로 유의한 차이가 있는 것으로 나타났다.


3단계 : 2단계의 결론이 대립가설이면

다중비교(Multiple Comparison) = 사후분석(Post-Adhoc)
Duncan, Tukey, Scheffee, Bonferroni, Dunnett

TukeyHSD(anova.result)

2단계 : 정규성 가정을 만족하지 않으면

Kruskal - Wallis Test
kruskal.test(양적자료 ~ 질적자료, data = dataname)

> kruskal.test(price ~ condition, data = houseDF)

	Kruskal-Wallis rank sum test

data:  price by condition
Kruskal-Wallis chi-squared = 260.85, df = 4, p-value < 2.2e-16

유의확률이 0.000이므로 유의수준 0.05에서 condition에 따라 price에 통계적으로 유의한 차이가 있는 것으로 나타났다.


3단계 : Kruskal-Wallis Test의 결론이 대립가설이면

다중비교 = 사후분석을 실시함
nparcomp::nparcomp(양적자료 ~ 질적자료, data = dataname)

> PMCMR::posthoc.kruskal.nemenyi.test(price ~ condition, data = houseDF,
+                                     dist="Tukey")

	Pairwise comparisons using Tukey and Kramer (Nemenyi) test
                   with Tukey-Dist approximation for independent samples

data:  price by condition

  1                 2                 3                 4                
2 0.99908           -                 -                 -                
3 0.000025063186814 < 2e-16           -                 -                
4 0.00023           0.000000000000046 0.000000544539610 -                
5 0.000000126256704 < 2e-16           0.000000000002318 0.000000000000046

P value adjustment method: none


Quiz

condition에 따라 price, bedrooms, bathrooms, sqft_living, sqft_lot, sqft_above, sqft_basement, year(2018 - yr_built)에 통계적으로 유의한 차이가 있는지를 검정하시오.

Variable Normaility Method F/Chisqaure pvalue
price No Krukal-Wallis 260.850 0.000
bathrooms Yes ANOVA 100.000 0.012
houseDF$year <- 2018 - houseDF$yr_built
analysis.variable <- c("price", "bedrooms", "bathrooms",
                       "sqft_living", "sqft_lot", "sqft_above",
                       "sqft_basement", "year")
Normality  <- c()
Method     <- c()
FChiSquare <- c()
PValue     <- c()
for(i in analysis.variable){
    normality.result <- by(unlist(houseDF[ , i]), houseDF$condition, ad.test)
    if(normality.result$`1`$p.value < 0.05 |
       normality.result$`2`$p.value < 0.05 |
       normality.result$`3`$p.value < 0.05 |
       normality.result$`4`$p.value < 0.05 |
       normality.result$`5`$p.value < 0.05){
        kruskal.result <- kruskal.test(unlist(houseDF[ , i]) ~ houseDF$condition)
        Normality  <- c(Normality, "No")
        Method     <- c(Method, "kruskal-Wallis")
        FChiSquare <- c(FChiSquare, kruskal.result$statistic)
        PValue     <- c(PValue, kruskal.result$p.value)
    }else{
        aov.result <- aov(unlist(houseDF[ , i]) ~ houseDF$condition)
        aov.result <- summary(aov.result)
        Normality  <- c(Normality, "Yes")
        Method     <- c(Method, "ANOVA")
        FChiSquare <- c(FChiSquare, unlist(aov.result)[7])
        PValue     <- c(PValue, unlist(aov.result)[9])
    }
}

anovaDF <- data.frame(Variables = analysis.variable,
                      Normality,
                      Method,
                      FChiSquare,
                      PValue)
writexl::write_xlsx(anovaDF, path = "anovaResult.xlsx")
01Basic

[Fastcampus] RDC 강의 내용 정리 - 이부일 강사님

Two Sample t-test

When?
두 개의 독립적인 집단의 평균이 같은지 다른지를 달라졌는지를 통계적으로 검정하는 방법
질적 자료(1개) : 두 집단
양적 자료(1개) :


  • 귀무가설 : 비졸업과 졸업 간에 용돈에 차이가 없다(mu1 = mu2).
  • 대립가설 : 비졸업과 졸업 간에 용돈에 차이가 있다(mu1 is not equal to mu2).

1단계 : 정규성 검정(Normality Test)

by(twosampleDF$money, twosampleDF$group, shapiro.test)

<결과>
twosampleDF$group: 비

	Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.83701, p-value = 0.02885

----------------------------------------------------------------------------------
twosampleDF$group: 졸

	Shapiro-Wilk normality test

data:  dd[x, ]
W = 0.57538, p-value = 6.737e-05

두 집단 모두 정규성 가정이 깨짐 => 2단계로 Wilcoxon's rank sum test를 실시


2단계 : 정규성 가정이 만족이 되면

등분산성 검정(Equality of Variance Test)

  • 귀무가설 : 등분산이다.
  • 대립가설 : 이분산이다.

var.test(datavariable datavariable ~ datavariable)
var.test(양적 자료 ~ 질적 자료)

> var.test(twosampleDF$money ~ twosampleDF$group)

	F test to compare two variances

data:  twosampleDF$money by twosampleDF$group
F = 0.22298, num df = 10, denom df = 11, p-value = 0.02499
alternative hypothesis: true ratio of variances is not equal to 1
95 percent confidence interval:
 0.06324512 0.81720812
sample estimates:
ratio of variances
         0.2229815

> by(twosampleDF$money, twosampleDF$group, var)
twosampleDF$group:[1] 1280.455
----------------------------------------------------------------------------------
twosampleDF$group:[1] 5742.424

결론 : 유의확률이 0.025이므로 유의수준 0.05에서 이분산이다.


3단계 : 이분산이 가정된 독립 2표본 t검정

t.test(data$variable ~ data$vairable,alternative = c("greater", "less", "two.sided"), var.equal = FALSE)

> t.test(twosampleDF$money ~ twosampleDF$group,
         alternative = "two.sided",
         var.equal   = FALSE)

<결과>
Welch Two Sample t-test

data:  twosampleDF$money by twosampleDF$group
t = -0.21741, df = 15.963, p-value = 0.8306
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -57.02012  46.41406
sample estimates:
mean in group 비 mean in group 졸
        76.36364         81.66667

유의확률이 0.831이므로 유의수준 0.05에서 비졸업자과 졸업자의 용돈에는 통계적으로 유의한 차이는 없는 것으로 나타났다.


3단계 : 등분산이 가정된 독립 2표본 t검정

t.test(data$variable ~ data$vairable, alternative = c("greater", "less", "two.sided"), var.equal = TRUE)

> t.test(twosampleDF$money ~ twosampleDF$group,
         alternative = "two.sided",
         var.equal   = TRUE)

	Two Sample t-test

data:  twosampleDF$money by twosampleDF$group
t = -0.21122, df = 21, p-value = 0.8348
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -57.51554  46.90948
sample estimates:
mean in group 비 mean in group 졸
        76.36364         81.66667

유의확률이 0.835이므로 유의수준 0.05에서 비졸업자과 졸업자의 용돈에는 통계적으로 유의한 차이는 없는 것으로 나타났다.


2단계 : 윌콕슨의 순위합 검정(Wilcoxon's rank sum test)

wilcox.test(data$variable ~ data$variable, alternative = c("two.sided", "greater", "less"))

> wilcox.test(twosampleDF$money ~ twosampleDF$group,
              alternative = "two.sided")

	Wilcoxon rank sum test with continuity correction

data:  twosampleDF$money by twosampleDF$group
W = 78, p-value = 0.4594
alternative hypothesis: true location shift is not equal to 0

유의확률이 0.459이므로 유의수준 0.05에서 비졸업자과 졸업자의 용돈에는 통계적으로 유의한 차이는 없는 것으로 나타났다.



Quiz 1.

  • yr_built : 1900이상 ~ 2000미만 : group = "old"
  • yr_built : 2000이상 : group = "new"
  • 귀무가설 : old와 new 간에 price에 차이가 없다.
  • 대립가설 : old가 new보다 price가 작다.
# 사용 데이터
houseDF <- readxl::read_excel(path      = "kc_house_data.xlsx",
                              sheet     = 1,
                              col_names = TRUE)

houseDF$group <-  cut(houseDF$yr_built,
                      breaks = c(1900, 2000, 2020),
                      right  = FALSE)
levels(houseDF$group) <- c("old", "new")
by(houseDF$price, houseDF$group, ad.test)
wilcox.test(houseDF$price ~ houseDF$group,
            alternative = "less")

result <- var.test(houseDF$price ~ houseDF$group)
result$p.value


Quiz 02.

id, date, yr_built를 제외한 모든 변수에 대해서 아래 가설검정을 실시

  • 귀무가설 : old와 new는 같다.
  • 대립가설 : new와 old는 같지 않다.

최종 결과 형태

variableName Normaility Method Equality TW pvalue
price yes t.test yes 1.234 0.123
bedrooms no wilcox.test non 1.234 0.123
houseDF <- read_excel(path      = "path/kc_house_data.xlsx",
                      sheet     = 1,
                      col_names = TRUE)
houseDF <- data.frame(houseDF)
# 분석에 사용하지 않는 변수 제거
# 1) dplyr (전처리에 많이 활용되는 라이브러리입니다.)
# select(변수 벡터)          => 지정벡터(열)만 추출
# select(-one_of(변수 벡터)) => 지정벡터(열)   제거
exceptVariable <- c("id", "date", "yr_built")
analysis.variable <- houseDF %>%
  select(-one_of(exceptVariable))

# 2) grep(base library)
analysis.variable <- colnames(houseDF)[-grep("^id|^date|^yr_built|^group",
                                             colnames(houseDF))]


# group 변수 생성
# ifelse를 활용하여 group - new/old 변수 생성 => 가설검정에서는 old를 기준으로 분석해야한다.
# default는 factor에서 new, old순서이기 때문에
# factor 형태 변환시 levels와 labels를 사용해서 old, new순서로 변경
# *주의) 데이터 형 변환시 as.factor와 factor는 동일한 기능을 수행하지만
#        levels와 lables를 argument로 가질 수 있는 것은 factor
houseDF$group <- ifelse(houseDF$yr_built >= 2000, "new","old")
str(houseDF$group)
table(houseDF$group)
houseDF$group <- factor(houseDF$group,
                        levels = c("old", "new"),
                        labels = c("old", "new"))
table(houseDF$group)

# 최종 결과를 저장하기 위한 빈 벡터 생성
Normality <- c()
Method    <- c()
Equality  <- c()
TW        <- c()
PValue    <- c() 

# for문(반복 횟수는 in (조건)에 들어간 벡터의 길이로 결정됩니다.)
# analysis.variable에서 변수를 한개씩 가져와서 실행
# for문의 반복 횟수는 19번(length(anaylsis.variable))
# 19번 동안 i에는 각각의 char타입의 열이름이 들어가서 실행
for(i in analysis.variable){

  # 1) 정규성 검정
  # 왜 unlist를 사용해야 하는가?
  # 우측 houseDF의 타입 : data.frame vs tbl_df
  # data.frame의 경우 houseDF[,i] 결과가 numveric vector입니다.
  # tbl_df의 경우 houseDF[,i] 결과가 tbl_df, data.frame형태의 class입니다.
  # 따라서, tbl_df형태를 가지는 houseDF는
  # 1) unlist를 통해서 벡터형태로 변환해주거나
  # 2) houseDF[, i]$변수명 형태로 한번더 슬라이싱을 해줘야 하는 문제가 있습니다.
    result.normality <- by(unlist(houseDF[ , i]), houseDF$group, ad.test)
    # result.normality <- by((houseDF[ , i]$i), houseDF$group, ad.test)
    # houseDF를 data.frame으로 변경하고 사용할 시
    # result.normality <- by(houseDF[ , i], houseDF$group, ad.test)

  # 2) 정규성 검정 결과를 통해 모수적 방법과 비모수적 방법 구분
  # 2-1) old와 new의 p-value가 둘중 하나라도 0.05 미만일 경우 정규성이 깨진다.
  #      => 비모수적행 방법 : wilcox.test
    if( (result.normality$old$p.value < 0.05) | (result.normality$new$p.value < 0.05)){
      # wilcox.test 결과 저장
        Normality <- c(Normality, "No")
        Method    <- c(Method, "wilcox.test")
        Equality  <- c(Equality, "Non")

        # 위의 unlist 설명과 동일
        # 대립 가설이 `old와 new가 같지 않다`이기 때문에 양측검정(two.sided)
        result.wilcox <- wilcox.test(unlist(houseDF[ , i])~ houseDF$group,
                                     alternative = "two.sided")

        # 필요한 부분만 추출하여 저장
        # str(result.wilcox)를 통해 wilcox 결과가 가지는 데이터의 구조를 확인 할 수 있습니다.
        TW     <- c(TW, result.wilcox$statistic)
        PValue <- c(PValue, result.wilcox$p.value)


  # 2-2) old와 newd의 p-value가 둘 모두 0.05 이상일 경우 정규성을 따른다.
  #     => 모수적 방법 : t-test
    }else{
        Normality <- c(Normality, "Yes")
        Method    <- c(Method, "t.test")

        # 3) 등분산성 검정
        # 귀무가설 : 등분산이다.
        # 대립가설 : 이분산이다.
        result.equality <- var.test(unlist(houseDF[ , i])~ houseDF$group)

        # p-value가 0.05 미만일 경우 이분산 (var.equal = FALSE)
        if(result.equality$p.value < 0.05){
            Equality  <- c(Equality, "No")
            result.ttest <- t.test(unlist(houseDF[ , i])~ houseDF$group,
                                   alternative = "two.sided",
                                   var.equal   = FALSE)
            TW     <- c(TW, result.ttest$statistic)
            PValue <- c(PValue, result.ttest$p.value)

        # p-value가 0.05 이상일 경우 등분산 (var.equal = TRUE)
        }else{
            Equality  <- c(Equality, "Yes")
            result.ttest <- t.test(unlist(houseDF[ , i])~ houseDF$group,
                                   alternative = "two.sided",
                                   var.equal   = TRUE)
            TW     <- c(TW, result.ttest$statistic)
            PValue <- c(PValue, result.ttest$p.value)
        }
    }
}

# for문을 6개의 벡터가 생성되었습니다.
# 하나의 결과로 저장
outputTest <- data.frame(Variable = analysis.variable,
                         Normality,
                         Method,
                         Equality,
                         TW,
                         PValue)
# 결과 내보내기
writexl::write_xlsx(outputTest, path = "outputTest.xlsx")
02Data

[Fastcampus] RDC 강의 내용 정리 - 이부일 강사님

One Sample t-test

When?
하나의 모집단의 양적 자료의 평균이 기존에 알고 있던 것보다
커졌는지, 작아졌는지, 달라졌는지를 통계적으로 검정하는 방법



1. 일표본 검정

  • 귀무가설 : 성인들의 평균 키는 170cm이다.
  • 대립가설 : 성인들의 평균 키는 170cm보다 크다.

1단계 : 정규성 검정(Normality Test)

  • 귀무가설 : 정규분포를 따른다.
  • 대립가설 : 정규분포를 따르지 않는다.

Shapiro-Wilk test : shapiro.test(data$variable)

height <- c(180, 175, 170, 170, 165, 184, 164, 159, 181, 167, 182, 186)
shapiro.test(height)

<결과>
Shapiro-Wilk normality test
data:  height
W = 0.93844, p-value = 0.4781

유의확률이 0.478이므로 유의수준 0.05에서 height는 정규분포를 따른다고 가정할 수 있다.


2단계 : 일표본 T검정(One sample t-test)

t.test(data$variable, mu = , alternative = )
mu : 귀무가설의 모평균
alternative : 대립가설, "greater", "less", "two.sided"

height.test <- t.test(height, mu = 170, alternative = "greater")
height.test

<결과>
One Sample t-test

data:  height
t = 1.3887, df = 11, p-value = 0.0962
alternative hypothesis: true mean is greater than 170
95 percent confidence interval:
 168.9492      Inf
sample estimates:
mean of x
 173.5833

유의확률이 0.096이므로 유의수준 0.05에서 성인들의 키는 통계적으로 유의하게 커지지 않았다. 성인들의 키는 변화가 없다.

str(height.test)
height.test$statistic    # t
height.test$parameter    # df
height.test$p.value      # p-value
height.test$conf.int     # 95% Confidence Interval, 신뢰구간
height.test$estimate     # 추정치, x bar, 표본의 평균
height.test$null.value   # 귀무가설의 모평균
height.test$alternative  # 대립가설
height.test$method       # One sample t-test
height.test$data.name    # height

2단계 : 윌콕슨의 부호 순위 검정(Wilcoxon's signed rank test)

wilcox.test(data$variable, mu = , alernative = )

wilcox.test(height, mu = 170, alternative = "greater")


Quiz 1.가설검정

귀무가설 : 성인들의 평균 용돈은 200만원이다.
대립가설 : 성인들의 평균 용돈은 200만원보다 작다.
유의수준 : 0.05

money <- c(45, 40, 40, 50, 50, 50, 40, 100, 50)

# 1단계 : 정규성 검정(Normality Test)
options(scipen = 100) # 지수 표현식 사용하지 않음
shapiro.test(money)
# 결론 : 유의확률이 0.000이므로 유의수준 0.05에서
# money는 정규분포를 따르지 않는다. 즉 정규성 가정을 만족하지 않음

# 2단계 : Wilcoxon's signed rank test
wilcox.test(money, mu = 200, alternative = "less")
# 결론 : 유의확률이 0.004이므로 유의수준 0.05에서
# 성인들의 용돈은 200만원보다 작다라는 대립가설을 채택
# 통계적으로 유의하게 성인들의 용돈이 줄어 들었다.


Quiz 2. 가설검정 결과 자동화 코드 작성

bedrooms", "bathrooms", "floors", "waterfront", "view", "condition", "grade" 변수에 대한 가설검정 결과를 엑셀 파일에 저장하시오.
귀무가설은 평균은 5이다로 함.

houseDF <- readxl::read_excel(path = "d:/da/kc_house_data.xlsx",
                              sheet = 1,
                              col_names = TRUE)

analysis.varibles <- c("bedrooms", "bathrooms", "floors", "waterfront", "view", "condition", "grade")


tv        <- c()
pvalue    <- c()
test.type <- c()

for(i in analysis.varibles){
    print(i)
    norm.test <- ad.test(unlist(houseDF[ , i]))
    if(norm.test$p.value > 0.05){
        result.t <- t.test(unlist(houseDF[ , i]), mu = 5, alternative = "two.sided")
        tv       <- c(tv, result.t$statistic)
        pvalue   <- c(pvalue, result.t$p.value)
        test.type <- c(test.type, "ttest")

    }else{
        result.wilcox <- wilcox.test(unlist(houseDF[ , i]), mu = 5, alternative = "two.sided")
        tv            <- c(tv, result.wilcox$statistic)
        pvalue        <- c(pvalue, result.wilcox$p.value)
        test.type <- c(test.type, "wilcox")
    }
}

resultDF <- data.frame(analysis.varibles, tv, pvalue, test.type)
writexl::write_xlsx(resultDF, path = "d:/da/resultDF.xlsx")

[ R studio project ] 

  • File - New project
  • 별도의 Directory 설정이 필요없다. ( R project 파일이 위치한 곳으로 자동으로 경로 지정됨)
  • Encoding 1회 설정
  • History 관리
  • Packrat : Package 관리 (과거 프로젝트 및 코드 관리 용이)

  packrat::init() -> 프로젝트 내 packrat 폴더 생성 및 해당 패키지 설치

  packrat::snapshot() -> 현재 사용 중인 패키지 버전을 확인

  remove.packages("패키지명") -> 설치된 패키지 삭제



[ Code Pipeline 제작 ]

 - 현재 진행중인 프로젝트 데이터 수집부터 최종 결과까지 진행되는 프로세스


텍스트 마이닝 프로젝트 예시

1) Web Review Data

2) Data Filtering

3) train / test data

4) Document Term Matrix

5) Delete Sparse terms

6) Delete Neutral terms

7) Modeling

8) ANOVA

[ Fastcampus Mini-project ] House Sales in King County, USA (Predict house price using Linear regression) - kaggle 


통계를 배운지 3주 정도 지나고, 배운 내용을 바탕으로 하여 미니 프로젝트를 진행

집값에 영향을 미치는 요인을 찾고 가격을 예측

데이터 셋 : kaggle에서 제공하는 House Sales in King County 

프로젝트 기간 : 08.03 ~ 08.09




rm(list=ls())

#' @title parallel coding

#' @author Jungchul HA

#' @version 1.0, 2017.08.21

#' @description 집값 예측 미니 프로젝


# 01. setting -------------------------------------------------------------


# import use library

library(dplyr)

library(readxl)

library(ggplot2)

library(ggmap)

library(DT)

library(maps)

library(corrplot)

library(caret)

library(car)


## King County

## 원본 데이터

House = readxl::read_excel("fs/house/kc_house.xlsx",

                           sheet = "data",

                           col_names = TRUE)

House$date<-(substr(House$date, 1, 8))

House$date = as.numeric(House$date)

House$per.price = House$price / House$sqft_living


# train / test 데이터 셋 분류

set.seed(1708)

ratio = sample(1:nrow(House), size = 0.30*nrow(House))

test = House[ratio,] #Test dataset 30% of total

train = House[-ratio,] #Train dataset 70% of total


# 분류된 모델을 바탕으로 분석 진행

# write.csv(train,

#           file      = "fs/house/train.csv",

#           row.names = FALSE)

# write.csv(train,

#           file      = "fs/house/test.csv",

#           row.names = FALSE)

# train = read.csv("fs/house/train.csv",

#                  header = TRUE)

# test = read.csv("fs/house/test.csv",

#                 header = TRUE)




# 02. EDA ----------------------------------------------------------------


summary(House)

View(House)

str(House)

colSums(is.na(House)) # 결측값은 0



# 02-1. 상관관계 분석 ---------------------------------------------------


train.num <- cor(train) ## House_num 생성 후 상관관계 분석치 할당

round(train.num, 3) ## 소수점 셋째자리까지 출력 

corrplot::corrplot(train.num, 

                   method = "number", 

                   shade.col = NA, 

                   tl.col = "black", 

                   tl.srt = 50,

                   order = "hclust",

                   diag = FALSE)


pairs(train, 

      pch = 19, 

      bg = c("red", "green", "blue"))  # 행렬모양 산점도


# 상관원계수가 클수록 크기가 크고 색깔이 진하다

# 양수면 파란색, 음수면 붉은색

corrplot(train)

corrplot(train, method = "number")    # 수와 색깔로 표현

corrplot(train, 

         method = "color",      # 색깔로 표현

         col    = col(200),     # 색상 200개 선정

         type   = "lower",      # 왼쪽 아래 행렬만 표기

         order  = "hclust",     # 유사한 상관계수끼리 군집화

         addCoef.col = "black", # 상관계수 색깔

         tl.col = "black",      # 변수명 색깔  

         tl.srt = 45,           # 변수명 45도 기울임

         diag   = F)


round(cor(test),3)

test = train %>% 

  select(price, sqft_living, grade ,sqft_above, sqft_living15,

         bathrooms, view, sqft_basement, bedrooms)


# 결과 : 5개의 변수가 price와 높은 상관관계를 보여줌

# price ~ sqft_living   0.702

# price ~ grade         0.667

# price ~ sqft_above    0.606

# price ~ sqft_living15 0.585

# price ~ bathrooms     0.525

# ------------------------- #

# price ~ view          0.397

# price ~ sqft_basement 0.324

# price ~ bedrooms      0.308

# price ~ waterfront    0.266

# price ~ floors        0.257

# price ~ yr_renovate   0.126

# price ~ sqft_lot      0.0897

# price ~ sqft_lot15    0.0824

# price ~ yr_built      0.054

# price ~ condition     0.0364


# per.price 와 나머지는 선형관계를 보이지는 않는다.


train1 = train


analysis = train %>% 

  select(price, zipcode, sqft_living, grade, bathrooms, long, lat, bedrooms)


# 양의 상관관계를 보이는 변수들 중 집을 보러 왔을때 신경쓰는 요소들을 

# 변수로 사용

# waterfront의 경우 163개의 데이터가 있지만 전역에 퍼져있으며 

# 집값의 경우도 비싼편은 아니라서 제외




# 02-2. zipcode를 바탕으로 파생변수 생성 ---------------------------------


## zipcode는 5자리로 구성되어 있으며,

## 주, 카운티, 도시 단위의 광범위한 지역을 나타내준다.

## 미국인들에게는 zipcode 자체가 '부와 명예'를 상징한다.(출처:LA중앙일보)

## zipcode(각 도시)마다 단위면적 당 가격(per.price)이

## 비슷한 가격대를 형성하고 있지 않을까?

## zipcode grouping 하여 파생변수로 활용해보자.

## 단위면적 당 price 계산 => per.price

analysis$per.price = analysis$price / analysis$sqft_living

# 최소 87.59 / 최대 810.14


## zipcode 별로 grouping

zipcode.price = analysis %>% 

  select(zipcode, per.price) %>% 

  group_by(zipcode) %>%  

  summarise(mean.price = mean(per.price),

            max.price = max(per.price),

            min.price = min(per.price),

            median.price = median(per.price),

            n = n())


head(zipcode.price, n=10)

## zipcode = 70개

## zipcode 별로 데이터의 개수 최소 34개 ~ 430개



# zipcode별 평균 - 중위수 차이 

zipcode.price$dif.price = round(zipcode.price$mean.price - zipcode.price$median.price, digits = 2)

zipcode.price = zipcode.price[order(zipcode.price$dif.price),]

## 평균과 중위수의 차이가 많이 나면 

## 해당 zipcode내에는 outlier로 예상되는 값이 존재 할 수도 있다 라고 생각.

## 단위 면적 가격 mean - median를 구해보니 

## 나머지 -0.6 ~ 21

## 결론) zipcode별로 평당 가격이 큰 차이를 보이는 집은 별로 없다.

DT::datatable(zipcode.price)


## 100단위로 dummy변수 대입

zipcode.price$median.price = round(zipcode.price$median.price)

zipcode.price$dummy.median = as.numeric(substr(zipcode.price$median.price,1,1))*100

## zipcode.price에서 zipcode, dummy.median를 추출하여 mg데이터 생성

mg = zipcode.price %>% 

  select(zipcode, dummy.median)


## train과 mg를 zipcode 기준으로 left outer join 

analysis1 = merge(analysis, mg, by = "zipcode", all.x=TRUE)

analysis1$dummy.median = as.factor(analysis1$dummy.median)


KingCounty = ggmap::get_map(location = c(lon=-122.3, lat=47.4),

                            zoom = 9)

KingCounty1 = ggmap(KingCounty) + geom_point(data = analysis1, aes(x = long, y = lat, colour = dummy.median))

KingCounty1


## 단위 면적 가격이 200이지만 상대적으로 가격대가 높은 지역과

## 붙어있는 3곳을 추가로 확인


## median.price 가 200~300 사이인 데이터만 추출

zipcode.price1 = zipcode.price %>%

  filter(median.price >= 200 & median.price <300) %>% 

  select(zipcode, median.price)


## 나머지를 구해서 10의자리 계산

zipcode.price1$dummy.median = as.numeric(substr(zipcode.price1$median.price,1,2))%%10

DT::datatable(zipcode.price1)


analysis2 = merge(analysis, zipcode.price1, by = "zipcode", all.x = TRUE)

analysis2$dummy.median = as.factor(analysis2$dummy.median) 

KingCounty2 = ggmap(KingCounty) + geom_point(data = analysis2, aes(x = long, y = lat, colour = dummy.median))

KingCounty2


## per.price 가 200대인 집들을 시각화 시켜봄.

## 200초반대 까지는 100에 

## 200 중반은 200으로

## 200 후반 값을 가지는 8,9는 300에 같이 그룹핑

zipcode.price2 = zipcode.price

zipcode.price2 = within(zipcode.price2,{

  dummy.median = numeric(0)

  dummy.median [ median.price < 220] = 1

  dummy.median [ median.price >= 221 & median.price <= 279 ] = 2

  dummy.median [ median.price >= 280 & median.price <= 399 ] = 3

  dummy.median [ median.price >= 400 & median.price <= 499 ] = 4

  dummy.median [ median.price >= 500 & median.price <= 599 ] = 5

  dummy.median [ median.price >= 600] = 6

})

DT::datatable(zipcode.price2)


mg1 = zipcode.price2 %>% 

  select(zipcode, dummy.median)

analysis3 = merge(analysis, mg1, by = "zipcode", all.x=TRUE)

analysis3$dummy.median = as.factor(analysis3$dummy.median)


KingCounty3 = ggmap(KingCounty) + geom_point(data = analysis3, aes(x = long, y = lat, colour = dummy.median))

KingCounty3


# 비싼 지역만 확대

KingCounty.zoom = ggmap::get_map(location = c(lon=-122.3, lat=47.6), zoom=11)

KingCounty4 = ggmap(KingCounty.zoom) + geom_point(data = analysis3, aes(x = long,  y = lat, colour = dummy.median))

KingCounty4

## 가격을 재분류 하여 찍어주었고

## 가격대가 높은 지역만 확대!




# 03. Modeling(회귀분석) -------------------------------------


## 다중선형회귀분석

## 집값에 영향이 있다고 생각되는 변수 추출

result = analysis3 %>% 

  select(price, bedrooms, bathrooms, grade, sqft_living, dummy.median)


## price와 sqft_living 은 숫자 단위가 크므로 log를 취함

model.1 = lm(log(price) ~ bedrooms + bathrooms + grade + log(sqft_living) + factor(dummy.median), data = result)

summary(model.1)

## bathrooms 은 0.063로 변수 제외


model.2 = lm(log(price) ~ bedrooms + grade + log(sqft_living) + factor(dummy.median), data = result)

summary(model.2)

vif(model.2)

lm.beta::lm.beta(model.2)

## bedrooms  : -0.040로 변수 제외


model.3 = lm(log(price) ~ grade + log(sqft_living) + factor(dummy.median), data = result)

summary(model.3)

vif(model.3)

lm.beta::lm.beta(model.3)

## 각 변수들간에 영향도도 있고

## Adjusted R-squared : 0.800

## waterfront는 163개 뿐인데 굳이 넣어야 될 필요성이 있을까?

## waterfront를 보유한 집들은 지도 전역에 골고루 퍼져있음




# 04. 모델 검증 ----------------------------------------------


vif(model.3)

## 다중공선성 문제도 없고

## 해당 모델을 최종 모델로 결정해서 test셋을 예측해보자


## 기존에 zipcode별로 그룹핑한 mg1 과 test 데이터를 merge 해서

## test 데이터에 dummy.median을 만들어주고

test = merge(test, mg1, by = "zipcode", all.x=TRUE)

test$log.price = log(test$price)


## test를 예측해보자

pred = predict(model.3, 

               newdata = test,

               interval = "predict")

pred

## 예측된 값고 test데이터의 log.price와 비교해보면

## 둘 사이의 관계가 0.89 정도

pred = as.data.table(pred)

pred$fit.price = 10^(pred$fit)

### log n복구

colnames(pred)

pred.final = pred 

test.final = test %>% 

  select(price, log.price)


final = cbind(test.final, pred.final)

final$result = ifelse( final$lwr<=final$log.price & final$log.price<=final$upr ,1,0)

table(final$result)



# 05. 기타(잔치 그래프) 확인 ----------------------------------------


analysis3[hatvalues(model.3) >= 0.025 , ]

# zipcode가 98039인 곳 가장 비쌈

out = train[c(11745,11812),]

DT::datatable(out)

out$per.price = out$price / out$sqft_living

## 다른 조건들에 비해 grade가 높아서 이상치로 판별됨


rm(list=ls())


train.out1 = train %>% 

  filter(zipcode == 98070)

mean(train.out1$per.price)


train.out2 = train %>% 

  filter(zipcode == 98146)


mean(train.out2$per.price)

zipcode.price3 = zipcode.price

zipcode.price = within(zipcode.price,{

  dummy.mean = numeric(0)

  dummy.mean [ mean.price < 220] = 1

  dummy.mean [ mean.price >= 221 & mean.price <= 279 ] = 2

  dummy.mean [ mean.price >= 280 & mean.price <= 399 ] = 3

  dummy.mean [ mean.price >= 400 & mean.price <= 499 ] = 4

  dummy.mean [ mean.price >= 500 & mean.price <= 599 ] = 5

  dummy.mean [ mean.price >= 600] = 6

})

DT::datatable(zipcode.price3)


mg1 = zipcode.price3 %>% 

  select(zipcode, dummy.mean)

train3 = merge(train, mg1, by = "zipcode", all.x=TRUE)

train3$dummy.mean = as.factor(train3$dummy.mean)


model4 = lm(log(price) ~ grade + log(sqft_living) + factor(dummy.mean), data = train)

summary(model4)

lm.beta::lm.beta(model4)

vif(model4)

plot(model4)

names(model4)

out = train3[c(4827,6475,13894,14499),]


water = train3 %>% 

  filter(waterfront == 0)


model5 = lm(log(price) ~ grade + log(sqft_living) + factor(dummy.mean), data = water)

summary(model5)

lm.beta::lm.beta(model5)

vif(model5)

par(mfrow = c(2,2))

plot(model5)



[Fast campus] Data Science with R 1기 - 이부일 강사님

공부하면서 배운 내용 복습 겸 정리하는 곳입니다.


# R.utils 패키지를 통해 printf() 사용 가능

install.packages("R.utils")

library(R.utils)


1. 반복문 : for

  # 동일한 일을 여러 번 하거나

  # 비슷한 일을 여러 번 할 때

1
2
3
4
5
6
7
8
9
10
11
12
13
> for(i in 1:10){
+   cat("hello,", i, "\n")
+ }
hello, 1 
hello, 2 
hello, 3 
hello, 4 
hello, 5 
hello, 6 
hello, 7 
hello, 8 
hello, 9 
hello, 10
cs

  # in은 대입, 할당하는 역할

  # 1:10 => 데이터의 개수(10개) 만큼 for문이 시행된다.

  # cat 대신 printf("hello, %d \n", i) 를 사용해도 동일한 결과 출력


  # 구구단

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> for(i in 1:9){
+   cat(i, "단 이에요!""\n")
+   for(j in 1:9){
+     cat(i, "x", j, "=", i*j, "\n")
+   }
+   cat("\n")
+ }
 
1 단 이에요! 
1 x 1 = 1 
1 x 2 = 2 
1 x 3 = 3 
1 x 4 = 4 
1 x 5 = 5 
1 x 6 = 6 
1 x 7 = 7 
1 x 8 = 8 
1 x 9 = 9 
...
cs

  # 2~9단도 동일한 결과로 출력됨



2. 조건문

  (1) if( 조건 ){ 실행문 } - 조건이 TRUE면 실행문을 실행

1
2
3
4
5
6
7
8
9
> x = c(1003060)
> for(i in 1:3){
+   if(x[i] > 50){
+     printf("%d Very large number!!! \n", x[i])
+   } 
+ }
 
100 Very large number!!! 
60 Very large number!!!
cs


  (2) if (조건문) { 조건이 참일 때 실행문 1} 
       else{ 조건이 거짓일 때 실행문 2}

1
2
3
4
5
6
7
8
> y  = 10
> if(y > 5){
+   print("Large!!")
+ } else{
+   print("Small!!")
+ }
 
[1"Large!!"
cs


  (3) if( 조건문1) { 실행문 1 }

      else if( 조건문 2) { 실행문 2}

      else{ 실행문 3 }

# else if 조건 추가 가능

1
2
3
4
5
6
7
8
9
10
> z = 7
> if(z>10){
+   print("Large")
+ } else if(z>5){
+   print("medium")
+ } else{
+   print("small")
+ }
 
[1"medium"
cs



3. 사용자 함수

  # 함수명 = function( ) { 실행문 }

1
2
3
4
5
6
7
8
9
10
11
12
> hello = function(){
+   print("hello, world")
+   return("hello, fastcampus")
+ }
 
> hello()
[1"hello, world"
[1"hello, fastcampus"
 
> x = hello()
> x
[1"hello, world"
cs

  # return 의 의미를 생각


  # 숫자 x를 입력받으면 x*3 을 해주는 함수 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> triple = function(x){
+   if(mode(x) == "numeric"){
+  #if(is.numeric(x)) 을 사용해도 된다
+     tmp = 3*x
+     return (tmp)
+   } else{
+     print("숫자를 넣어주세요")
+   }
+ }
 
> triple(10)
[130
 
> triple("10")
[1"숫자를 넣어주세요"
cs


  # 구구단 : 해당 숫자의 구구단을 출력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> gugudan = function(x){
+   if(is.numeric(x)){
+     printf("%d단 \n", x)
+     for(i in 1:9){
+       printf("%d x %d = %d \n", x,i,x*i)
+     }
+   } else{
+     print("숫자를 넣어주세요")
+   }
+ }
 
> gugudan(3)
3단 
3 x 1 = 3 
3 x 2 = 6 
3 x 3 = 9 
3 x 4 = 12 
3 x 5 = 15 
3 x 6 = 18 
3 x 7 = 21 
3 x 8 = 24 
3 x 9 = 27
cs


[Fast campus] Data Science with R 1기 - 이부일 강사님

공부하면서 배운 내용 복습 겸 정리하는 곳입니다.


6. 새로운 변수 만들기

  # 데이터$변수명 = 연산(수식)

  # bmi 수치를 계산해서 새로운 변수로 추가

1
student$bmi = student$weight / ((student$height/100)^2)
cs


  # ifelse(조건, 참일 때 표현식, 거짓일 때 표현식)

  # 30대 이상 / 20대 이하를 나타내는 새로운 변수(age_group)를 추가

1
student$age_group = ifelse(student$age >= 30"30대 이상""20대 이하")
cs


  # 20대 초반, 20대 중반, 30대 이상으로 나뉘는 age_group2를 만들어라

1
2
student$age_group = ifelse(student$age >= 30"30대 이상",
                            ifelse(student$age >= 25"20대 중반""20대 초반")

cs


  # cut(데이터명$변수명, breaks = 구간정보) => numeric data에 적용

   경도 비만(1단계 비만) : 25 - 30

   과체중 : 23 - 24.9

   정상 : 18.5 - 22.9

   저체중 : 18.5 미만

1
2
student$bmi_group = cut(student$bmi, 
                        breaks = c(018.5232530))
cs

  # 데이터의 결과를 보면 ( ] 와 같이 소괄호 괄호로 표현된다

  # (18.5, 23] => 18.5 초과 23이하

  # ( ) 소괄호는 초과

  # [ ] 대괄호는 이하

  # 0과 30 초과 값들은 NA로 입력이됨

  # 위 코드에 right = FALSE 라는 argument 를 추가해보자

1
2
3
student$bmi_group = cut(student$bmi, 
                        breaks = c(018.5232530), 
                        right  = FALSE)
cs

  # right = FALSE 를 하게되면 괄호의 위치가 바뀌게 됨

  # [18.5, 23) => 18.5 이상 23미만

  # 30 이상의 값들은 NA로 표시됨


  # 각 행들의 평균 구하기

1
score$avg = rowMeans(score[ , 2:6])
cs

  # 각 열들의 평균은 colMeans( ) 



7. 데이터의 값을 수정하기

  # home 이라는 데이터

1
2
3
4
5
6
7
8
9
10
11
> home
# A tibble: 7 x 4
     id  room price  area
  <dbl> <dbl> <dbl> <dbl>
1     1     1    40     13
2     2     4 50000    55
3     3     3 20000    35
4     4     3 50000    35
5     5     1    43     2
6     6     4 50000    45
7     7     1   500    15
cs
  
  # 500이라는 값을 변경
1
2
3
4
5
6
7
8
9
10
11
12
> home[home$price == 500"price"] = 50
> home
# A tibble: 7 x 4
     id  room price  area
  <dbl> <dbl> <dbl> <dbl>
1     1     1    40     1
2     2     4 50000    55
3     3     3 20000    35
4     4     3 50000    35
5     5     1    43     2
6     6     4 50000    45
7     7     1    50    15 
cs



8. 데이터 정렬하기

  (1) 벡터를 정렬하기 : sort(벡터, decreasing = )

      # 기본값 = 오름차순

1
2
3
4
5
6
> money = c(455040505030500)
> sort(money)
[1]  30  40  45  50  50  50 500
 
> sort(money, decreasing = TRUE
[1500  50  50  50  45  40  30
cs

 

  (2) order(데이터명$변수명, decreasing = )

  # sort는 벡터에서만 사용가능

  # data.frame에서는 order 함수를 사용

1
2
> order(money)
[16 3 1 2 4 5 7
cs

  # order는 정렬될 인덱스를 알려준다.

  # data.frame에서 데이터 정렬은 행이 바뀌는 것

  # 슬라이싱의 행 자리에 order가 들어간다.


# 성별 내림차순

1
student[ order(student$height, decreasing = TRUE) , ]
cs


# 성별 내림차순 / 키 내림차순

1
student[ order(student$gender, student$height, decreasing = TRUE ) , ]
cs


# 성별 오름차순 / 키 내림차순

# 조건이 다르니 -를 사용

1
student[ order(student$gender, -student$height) , ]
cs


# 성별 내림차순 / 키 오름차순

# - 는 numeric에만 적용 가능

1
student[ order(student$gender, -student$height, decreasing = TRUE ) , ]
cs


# 성별 오름차순 / 거주지 내림차순

# character 타입의 데이터를 따로 정렬하려면? 

# - 는 numeric에만 적용된다 => 기본 기능에서는 불가능

# data.table 패키지를 사용하여 데이터를 data.table로 변경

1
studentDT = as.data.table(student), ]
cs
# str(studentDT)를 통해 확인해보면 data.frame, data.table 2가지 형태를 모두 인식하는 것을 볼 수 있다.

1
studentDT[ order(gender, -address) , ]  
cs

# 데이터의 column에 바로 접근 가능

# 결과를 콘솔 화면에 보여주기만 함

 

1
setorder(studentDT, gender, -address)  
cs

# setorder( ) 를 사용하면 데이터를 정렬해서 결과 저장


※ data.frame vs data.table 참고

http://using.tistory.com/81 

# data.table()_cheet sheet 확인

# setkey(), J(), fread() 공부



9. 데이터 합치기

  (1) rbind(데이터1, 데이터2, ... ) => 위, 아래로 데이터 합치기


  (2) merge(데이터1, 데이터2, ..., by=, all=, all.x=, all.y=)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> df4 = data.frame(id  = c(1247),
+                  age = c(10204070))
> df5 = data.frame(id = c(123610),
+                  gender = c("M""M""F""M""F"))
> df4;df5
  id age
1  1  10
2  2  20
3  4  40
4  7  70
  id gender
1  1      M
2  2      M
3  3      F
4  6      M
5 10      F
cs


# merge 4가지 방법

① inner join(교집합)

# inner join은 2가지 데이터만, 3가지 이상은 다른 기능으로

# by는 PK(Primary Key) => 데이터를 구분해주는 값 

# PK 예) 사람-주민등록번호, 회사직원-사원

1
2
3
4
> merge(df4, df5, by="id")
  id age gender
1  1  10      M
2  2  20      M
cs


# outer join

② full join(합집합) - all=TRUE

1
2
3
4
5
6
7
8
9
> merge(df4, df5, by="id", all=TRUE)
  id age gender
1  1  10      M
2  2  20      M
3  3  NA      F
4  4  40   <NA>
5  6  NA      M
6  7  70   <NA>
7 10  NA      F
cs

# R에서 숫자는 NA / 문자는<NA>로 표시해서 구분해준다.


③ left join - all.x=TRUE

1
2
3
4
5
6
> merge(df4, df5, by="id", all.x=TRUE)
  id age gender
1  1  10      M
2  2  20      M
3  4  40   <NA>
4  7  70   <NA>
cs


④ right join - all.y=TRUE

1
2
3
4
5
6
7
> merge(df4, df5, by="id", all.y=TRUE)
  id age gender
1  1  10      M
2  2  20      M
3  3  NA      F
4  6  NA      M
5 10  NA      F
cs



10. R데이터 저장하기

  (1) 외부 데이터로 저장하기

1
2
3
write.csv(student,
          file      = "fs/data/student.csv",
          row.names = FALSE)
cs

# row.names = FALSE 를 주게되면 행 이름은 저장하지 않음


  (2) R데이터로 저장하기

1
save(R데이터, file = "파일위치/파일명.RData")
cs


  (3) R데이터 불러오기

1
load(file = "파일위치/파일명.RData") 
cs


[Fast campus] Data Science with R 1기 - 이부일 강사님

공부하면서 배운 내용 복습 겸 정리하는 곳입니다.


Data Handling = Data Pre-processing


## 사용할 데이터 읽어오기

# 외부 데이터를 읽어오면 data.frame 형태로 저장된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> student = readxl::read_excel(path = "fs/data/student.xlsx",
+                              sheet = "data",
+                              col_names = TRUE)
> student
# A tibble: 12 x 8
      id gender   age height weight  address
   <dbl>  <chr> <dbl>  <dbl>  <dbl>    <chr>
 1     1   남자    29    188     80   구파발
 2     2   남자    28    185     63     강동
 3     3   남자    25    172     63 압구정동
 4     4   여자    24    160     48     수원
 5     5   남자    26    180     80     용인
 6     6   남자    26    188     77     성수
 7     7   남자    59    170     63     수원
 8     8   여자    25    160     45     분당
 9     9   남자    27    178     78     강동
10    10   남자    31    181     95     의왕
11    11   여자    27    167     58     길동
12    12   남자    40    175     70     부산
# ... with 2 more variables: major <chr>,
#   company <chr>
cs


1. 데이터 전체보기

  (1) View(데이터) 

View(student)

# 별도의 팝업 창으로 데이터를 볼 수 있음

  

  (2) 데이터 : 콘솔(Console)에 출력

student



2. 데이터 구조(Structure) 보기

  (1) str(데이터)

str(student)

1
2
3
4
5
6
7
8
9
10
> str(student)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':    12 obs. of  8 variables:
 $ id     : num  1 2 3 4 5 6 7 8 9 10 ...
 $ gender : chr  "남자" "남자" "남자" "여자" ...
 $ age    : num  29 28 25 24 26 26 59 25 27 31 ...
 $ height : num  188 185 172 160 180 188 170 160 178 181 ...
 $ weight : num  80 63 63 48 80 77 63 45 78 95 ...
 $ address: chr  "구파발" "강동" "압구정동" "수원" ...
 $ major  : chr  "경영정보학" "산업경영학" "경영학" "수학" ...
 $ company: chr  "NC소프트" "구글" "아마존" "SK" ...
cs

# student의 id만 보고 싶다면 => str(student$id)



3. 데이터의 일부 보기

  (1) head(데이터) 

# 상위 6개의 데이터를 보여줌

1
2
3
4
5
6
7
8
9
10
11
12
> head(student)
# A tibble: 6 x 8
     id gender   age height weight  address
  <dbl>  <chr> <dbl>  <dbl>  <dbl>    <chr>
1     1   남자    29    188     80   구파발
2     2   남자    28    185     63     강동
3     3   남자    25    172     63 압구정동
4     4   여자    24    160     48     수원
5     5   남자    26    180     80     용인
6     6   남자    26    188     77     성수
# ... with 2 more variables: major <chr>,
#   company <chr>
cs

# head(student, n = 3)

# 출력 데이터 개수 지정 가능

  

  (2) tail(데이터)

# 하위 6개의 데이터를 보여줌

# head와 동일한 출력 형태

# tail(student)

# tail(student, n = 3)



4. 데이터 프레임의 속성

  (1) 행의 개수 : nrow(데이터)

1
2
> nrow(student)
[112
cs


  (2) 열의 개수 => 변수의 개수 : ncol(데이터)

1
2
> ncol(student)
[18
cs


  (3) 행의 이름 : rownames(데이터)

# 결과는 character

1
2
3
> rownames(student)
 [1"1"  "2"  "3"  "4"  "5"  "6"  "7"  "8" 
 [9"9"  "10" "11" "12"
cs

  

  (4) 열의 이름 => 변수의 이름 : colnames(데이터)

# 결과는 character

1
2
3
> colnames(student)
[1"id"      "gender"  "age"     "height" 
[5"weight"  "address" "major"   "company"
cs


  (5) 차원(dimension) : 행, 렬 : dim(데이터)

1
2
3
4
5
6
7
8
> dim(student)
[112  8
 
> dim(student)[1
[112
 
> dim(student)[2
[18
cs


  (6) 차원의 이름 : 행의 이름, 열의 이름 : dimnames(데이터)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
> dimnames(student)
[[1]]
 [1"1"  "2"  "3"  "4"  "5"  "6"  "7"  "8" 
 [9"9"  "10" "11" "12"
 
[[2]]
[1"id"      "gender"  "age"     "height" 
[5"weight"  "address" "major"   "company"
 
> dimnames(student)[1#리스트
[[1]]
 [1"1"  "2"  "3"  "4"  "5"  "6"  "7"  "8" 
 [9"9"  "10" "11" "12"
 
> dimnames(student)[[1]] #벡터
 [1"1"  "2"  "3"  "4"  "5"  "6"  "7"  "8" 
 [9"9"  "10" "11" "12"
 
> dimnames(student)[[1]][3#벡터(dimnames(student)[[1]]) 의 3번 째 값
[1"3"
cs


5. 데이터(data.frame)의 슬라이싱

  # 데이터[행index, 열index] => data.frame은 행,열의 2차원 구조

  # Vectorization 이 적용됨, for문 없이 연산이 끝까지 수행


  (1) 열(column) 

# 데이터[ , index]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> student[ , 2]
# A tibble: 12 x 1
   gender
    <chr>
 1   남자
 2   남자
 3   남자
 4   여자
 5   남자
 6   남자
 7   남자
 8   여자
 9   남자
10   남자
11   여자
12   남자
cs


문제. 짝수번째 열 가져오기

1
2
3
student[ , seq(from = 2,
               to   = ncol(student),
               by   = 2)] 
cs

# vector 에서는 length

# data.frame 에서는 nrow, ncol


문제. weight, height의 데이터를 가져오기

1
student[ , c("weight""height")
cs

# index가 character 이므로 c( )를 사용


# 변수명에 특정한 패턴이 있는 것을 추출

# grep("패턴", 문자열)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 변수명 중에서 'e'라는 글자를 포함하고 있는 변수명의 위치
grep("e"
     colnames(student))
 
# 'e'라는 글자를 포함하고 있는 변수명
grep("e"
     colnames(student), 
     value=TRUE
 
# 'e'라는 글자를 포함하고 있는 데이터를 추출
student[ , grep("e"
                colnames(student), 
                value=TRUE)]
 
# 'a'라는 글자로 시작하는 데이터를 추출 => ^a
student[ , grep("^a"
                colnames(student), 
                value=TRUE)]
 
# 't'라는 글자로 끝나는 데이터를 추출 => t$
student[ , grep("t$"
                colnames(student), 
                value=TRUE)]
 
# 't'라는 글자로 끝나거나, 'a'라는 글자로 시작하는 데이터를 추출
student[ , grep("t$|^a"
                colnames(student), 
                value=TRUE)]
cs

# 정규표현식을 익히자

# https://wikidocs.net/1669 

# http://www.nextree.co.kr/p4327/


  (2) 행(row)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 성별이 여자인 데이터만 가져오기
student.female = student[student$gender == "여자"]
 
# 거주지가 수원이 아닌 사람들의 데이터
student[student$address != "수원"]
 
# 몸무게가 50 이하인 사람들의 데이터
student[student$weight <= 50]
 
# 나이가 30대 이상이고, 키는 175 이상인 사람
student[(student$age >= 30& (student$height >= 175), ]
 
# 나이가 30대 이상이거나 키는 175 이상인 사람
student[(student$age >= 30| (student$height >= 175), ]
cs


  (3) 행, 열

1
2
3
4
# 키가 170cm 이상이고, 몸무게가 60kg 이상인 사람들 중에서 
# 변수명에 'e'라는 글자가 들어가는 데이터
student[(student$height >= 170& (student$weight >= 60), 
        grep("e", colnames(student))]
cs








[Fast campus] Data Science with R 1기 - 이부일 강사님

공부하면서 배운 내용 복습 겸 정리하는 곳입니다.


외부 데이터 : txt, csv, excel(xls, xlsx) 


1. 텍스트 데이터 : txt

  (1) 구분자(Separator) : 공백 하나(blank, white space)

1
2
3
데이터명 = read.table(file  = "파일위치/파일명.txt",
                     header = TRUE,
                     sep    = " "
cs


  (2) 구분자(Separator) : comma(,)

1
2
3
데이터명 = read.table(file   = "파일위치/파일명.txt",
                     header = TRUE,
                     sep    = ","
cs


  (3) 구분자(Separator) : 탭(tab)

1
2
3
데이터명 = read.table(file   = "파일위치/파일명.txt",
                     header = TRUE,
                     sep    = "\t"
cs



2. CSV(Comma Separated Value)

# 엑셀의 특수한 형태

1
2
3
데이터명 = read.table(file   = "파일위치/파일명.txt",
                     header = TRUE,
                     sep    = "\t"
cs


3. 엑셀 : xls, xlsx

# R의 기본 기능에서는 못 읽어 옴

# 추가 기능(패키지(Package))을 설치 - install.packages("패키지명")

# 패키지 로딩하기, 구동하기 - library(패키지명)

1
2
3
4
5
6
> install.packages("readxl")
package ‘readxl’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\JungChul\AppData\Local\Temp\RtmpG8Gy4u\downloaded_packages
> library(readxl)
cs

  # 패키지 설치 명령어 후 successfully 메시지가 나오면 설치 완료

  # 패키지는 항상 코드 가장 위( 다른 pc에서 실행 할 수도 있으니 install.packages명령어도 같이 적어두기 )

  # 패키지 내 함수를 사용할 때는 '패키지명::함수' 형태로 사용하자

1
2
3
데이터명 = readxl::read_excel(path="파일위치/파일명.xlsx",
                             sheet=index or "시트명",
                             col_names=TRUE)
cs


+ Recent posts