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에서 제공해주는 hflights 패키지 사용
# 예제 데이터 : hflights::hflights
# 패키지::데이터 : 괄호가 없으면 데이터 불러오기

자료의 종류 : 통계적인 관점

  # 질적 자료 vs 양적자료

  # 질적 자료 : 글자(문자), 숫자(의미가 없는 숫자)

  # 양적 자료 : 숫자(의미가 있는 숫자 - 사칙연산이 가능)


일변량(Uni-variate) 질적 자료의 분석

  # 일변량 => 하나의 열


1. 표 = 빈도표 

  # 빈도(frequence), 백분율(percent)


  (1) 빈도 : table(데이터명$변수명)

# R에서 table은 질적자료의 빈도를 구할 때 많이 사용

1
2
3
4
5
> sort(table(hflights$Month),
+      decreasing = TRUE)
 
    7     8     6     3     5    12     1    10     4     9    11     2 
20548 20176 19600 19470 19172 19117 18910 18696 18593 18065 18021 17128
cs


  (2) 백분율 = (빈도/합계) * 100

# prop.table(빈도결과) * 100

# prop = proportional(비율)

# 비율 : 0~1 / 백분율 : 0~100

# 백분율은 소수점 한 자리 까지만 보고서에 작성 

1
2
3
4
5
6
> round(sort(prop.table(table(hflights$Month))*100,
+            decreasing = TRUE),
+       digits = 1)
 
  7   8   6   3   5  12   1  10   4   9  11   2 
9.0 8.9 8.6 8.6 8.4 8.4 8.3 8.2 8.2 7.9 7.9 7.5
cs


     ## prettyR 패키지

# prettyR::freq(데이터명$변수명)

1
2
3
4
5
6
7
> prettyR::freq(hflights$Month)
 
Frequencies for hflights$Month 
        7    8    6      3     5    12    1     10     4     9    11     2    NA
     20548 20176 19600 19470 19172 19117 18910 18696 18593 18065 18021 17128  0
%       9  8.9  8.6  8.6  8.4  8.4  8.3  8.2  8.2  7.9  7.9  7.5    0 
%!NA    9  8.9  8.6  8.6  8.4  8.4  8.3  8.2  8.2  7.9  7.9  7.5
cs

# 결과는 백분율과 유효백분율이 나타남

# 유효백분율 : 실질적으로 응답한 사람(NA제외)

# display.na = FALSE : 유효백분율이 출력되지 않음



2. 그래프 : 막대그래프(세로, 가로), 원그래프

  (1) 막대그래프

# barplot(빈도결과) - 기본 세로 막대그래프

# 그래프에 다양한 arguments를 추가

1
2
3
4
5
6
barplot(sort(table(hflights$Month), decreasing = TRUE),
        col  = "skyblue",
        main = "월별 운항의 현황",
        ylab = "운항 횟수",
        ylim = c(025000)
)
cs

   # 막대 색깔 : col = "color"

# 그래프 제목 : main = "제목"

# y축 제목 : ylab = "축제목"

   ylab = y label의 약자

   y축 제목은 꼭 써야한다.

# y축 눈금 : ylim = c(최소값, 최대값)

   ylim = y limit의 약자

   y축의 최소값은 0으로 해야된다.

   * 절단효과 : 최소값을 올리게 되면 전체적인 차이가 더 크게 보일 수 있기 때문


# 가로 막대 그래프 : horiz = TRUE

1
2
3
4
5
6
7
barplot(sort(table(hflights$Month), decreasing = TRUE),
        col   = "skyblue",
        main  = "월별 운항의 현황",
        xlab  = "운항 횟수",
        xlim  = c(025000),
        horiz = TRUE
) 
cs

가로 막대 그래프로 변경 했기에 xlab, xlim 으로 바꿔야 함

젤 위에 가장 큰 값을 주어야 한다. => 내림차순


  

(2) 원그래프

# pie(빈도)

# 원 그래프는 조각이 5개 이하인 경우에만 사용

1
2
3
pie(sort(table(hflights$Month), decreasing = TRUE),
    radius     = 1.0,
    init.angle = 90)
cs

# 반지름 : radius = 0.8 (기본값)

# 첫 번째 조각의 각도 : init.angle = 



  일변량(Uni-variate) 양적 자료의 분석


1. 표

  # 구간의 빈도, 백분율

  # 최소값, 최대값

1
2
3
> range(hflights$ArrDelay,
+       na.rm = TRUE)
[1-70 978
cs

  

  # 구간의 개수 구하는 법

1. Sturge's : 1+3.3*log10(데이터의 개수)

1
2
> 1 + 3.3*log10(length(hflights$ArrDelay))
[118.67801
cs


2. sqrt(데이터의 개수) 

1
2
> sqrt(length(hflights$ArrDelay))
[1476.9654
cs

... 기타 등


  # 구간의 폭 = 계급의 폭

  # (최대값 - 최소값) / 구간의 개수

  # 첫 번째 구간에는 최소값 포함, 마지막 구간에는 최대값이 포함되어야 함    

1
2
3
4
5
> range(hflights$ArrDelay, na.rm = TRUE)
[1-70 978
 
> diff(range(hflights$ArrDelay, na.rm = TRUE))
[11048
cs

  # diff(숫자)

  # diff( c(1, 3, 5) ) => 3-1 / 5-3 => 2개씩 짝 지어서 계산됨

1
2
> diff( c(135)
[12 2
cs


  # cut을 통해 내가 원하는 구간별로 나눌 수 도 있다.

1
2
3
4
5
hflights$ArrDelay.group = cut(hflights$ArrDelay,
                              breaks = seq(from = -120,
                                           to = 1020,
                                           by = 60),
                              right = FAㅣSE
cs


2. 그래프

  (1) 히스토그램(Histogram)

i. hist(데이터명$변수명) : Sturge 공식 적용

1
hist(hflights$ArrDelay)
cs


ii. hist(데이터명$변수명, breaks = 구간의 개수)

1
2
hist(hflights$ArrDelay,
     breaks = 100)
cs


iii. hist(데이터명$변수명, breaks = 구간의 정보)

1
2
3
4
5
6
hist(hflights$ArrDelay,
     breaks = seq(from = -120,
                  to = 1020,
                   by = 60),
     xlim = c(-1201020))
 
cs

  

  (2) 상자그림(Boxplot) : 이상치 유무 판별

i. boxplot(데이터명$변수명)

1
boxplot(hflights$ArrDelay)
cs


ii. 집단별 상자그림

# boxplot(데이터명$변수명 ~ 데이터명$변수명)

# boxplot(     양적자료        ~      질적자료      )

# R의 관점에서 factor형태로 되어 있어야 한다.

1
2
boxplot(hflights$ArrDelay ~ hflights$Origin)
boxplot(hflights$ArrDelay ~ hflights$Month)
cs

# boxplot을 통해 각 이상치를 제거할까? 변환할까? 등을 판별


3. 기술통계량 = 요약통계량 => 숫자

  # Descriptive Statistics = Summary Statistics


  # 모수(Parameter)       vs  통계량(Statistics)

  # 모집단(Population)   vs  표본(Sample)


  # 기술통계량, 요약통계량 => 표본에서 나온 것

  # 모수는 모집단이 어떻게 형태인지 알려주는 수많은 숫자들

  # 모집단의 평균, 표준편차, 최소값, 최대값... 등 => 모수 (하지만 현실에서는 대부분 알 수 없다.)

  # 표본에서 나온 평균, 표준편차, 최소값, 최대값... 등 => 통계량

  # 양적 자료를 바탕으로 다양한 숫자를 만들어내는 것 = 통계량

  # 통계적 추론 : 표본으로 부터 나온 통계량을 바탕으로 모집단의 모수들을 추측


  (1) 중심 = 대표값

# 평균, 절사평균, 중위수(중앙값), 최빈수(최빈값)

# 절사평균 : 평균은 이상치(Outlier)에 영향을 많이 받는다. -> 이상치를 뺀 평균

# 최빈수 : 동일한 값이 많이 나타난 수


i. 평균

# mean(데이터명$변수명, na.rm = TRUE)

1
2
> mean(hflights$ArrDelay, na.rm = TRUE)
[17.094334
cs

# 하지만 이 평균을 가지고 분석을 시행하기에는 위험하다.

# 이상치(Outlier)의 존재 때문


ii. 5% 절사평균(Trimmed Mean)

# mean(데이터명$변수명, trim = 0.05, na.rm = TRUE)

# 작은쪽, 큰쪽 각 5%씩 절사해서 90%의 평균을 계산하여 분석

# 5%는 바꿔도 되는 기준

1
2
3
4
5
> mean(hflights$ArrDelay, trim = 0.05, na.rm = TRUE)
[13.121585
 
> mean(hflights$ArrDelay, trim = 0.1, na.rm = TRUE)
[11.847091
cs


iii. 중위수

# median(데이터명$변수명, na.rm = TRUE)

1
2
> median(hflights$ArrDelay, na.rm = TRUE)
[10
cs

# 중위수 0을 기준으로 일찍 오거나 늦게 온 비행기가 50%씩 존재한다.


iv. 최빈수(Mode)

  1) which.max(table(데이터명$변수명)

1
2
> which.max(c(1053200))
[14
cs

  # 벡터의 가장 큰 값 200의 index를 알려준다.


1
2
3
> which.max(table(hflights$ArrDelay))
-4 
54 
cs

  # -4가 54번째 있었다.

  # ArrDelay 데이터에서 4분 일찍 도착한 게 가장 많았다.


  2) prettyR::Mode()

1
2
> prettyR::Mode(hflights$ArrDelay)
[1"-4"
cs


  (2) 퍼짐 = 산포 = '다름' 

# 통계는 '다름'이 존재하기에 분석한다. 이 다름의 차이를 수치화 하여 나타냄

# 이 '다름'은 왜 발생했을까?

# 범위, 사분위수범위, 분산

# 표준편차(평균과의 차이), 중위수 절대편차(중위수와 차이)

# 범위와 표준편차는 이상치(Outlier)에 영향을 많이 받는다.

# 중위수 절대편차는 이상치(Outlier)의 영향을 적게 받는다.


i. 범위(Range)

1
2
> range(hflights$ArrDelay, na.rm = TRUE)
[1-70 978
cs

# R에서 range()는 최소값, 최대값 2개를 알려준다.

# diff()를 통해 2개의 차이를 계산

1
2
> diff(range(hflights$ArrDelay, na.rm = TRUE))
[11048
cs

# 범위는 이상치의 영향을 많이 받는다.

# 그래서 나온게 사분위수 범위


ii. 사분위범위 = 사분위수범위 = IQR(Inter Quartile Range)

# IQR(데이터명$변수명, na.rm = TRUE)

1
2
> IQR(hflights$ArrDelay, na.rm = TRUE)
[119
cs

# 범위(1048) , 사분위범위(19) 의 차이는 다르다.

# 사분위범위를 보고 항공기들은 19분정도 늦거나 일찍 도착하네 라고 생각 할 수 있음.


iii. (표본) 분산(Variance)

# 모든 데이터에서 평균을 빼고 제곱을 한다.

# 데이터 - 평균 : 편차(Deviation) => 편차를 다 더하면 0 => 따라서 제곱한 값을 사용

# 통게는 데이터의 합계가 아닌 '자유도'로 나눈다

# df : degree of freedom

# var(데이터명$변수명, na.rm = TRUE)

1
2
> var(hflights$ArrDelay, na.rm = TRUE)
[1943.013
cs

# 분산은 각 데이터 제곱을 통해 계산하므로 ArrDelay의 결과는 '분의 제곱'이다.


iv. (표본) 표준편차(SD : Standard Deviation)

# sd(데이터명$변수명, na.rm = TRUE)

1
2
> sd(hflights$ArrDelay, na.rm = TRUE)
[130.70852
cs

# 평균은 7분 정도 늦는데, 각 데이터들마다 평균과의 차이가 다름

# 여기서 평균과의 차이는 약 30분(표준편차)

# 즉, -27분 ~ 37분 범위 안에서 대부분 도착한다.

# 표준편차가 작다 - 평균이랑 가까운 데이터들

# 표준편차가 크다 - 평균이랑 먼 데이터들


v. 중위수 절대편차(MAD : Median Absolute Deviation)

# mad(데이터명$변수명, na.rm = TRUE)

1
2
> mad(hflights$ArrDelay, na.rm = TRUE)
[113.3434
cs

# 중위수 절대편차를 기준으로 비행기들이 13분 늦거나 일찍오는구나 라고 생각


  (3) 분포의 모양

# 데이터는 하나가 아니라 여러개다.

# R의 기본 기능에서는 못 구함 - 왜도, 첨도

i. 왜도(Skewness) : 대칭여부

# 왜도가 0에 가까운 값이라면 '데이터들이 대칭이다' 라고 볼 수 있다.

# 왜도가 0에서 멀어진다면 ' 데이터들이 비대칭이다'라고 볼 수 있다.

# 왜도 > 0 : 이상하게 큰 애가 있다면 오른쪽으로 긴 곡선

# 왜도 < 0 : 이상하게 작은 애가 있다면 왼쪽으로 긴 곡선


ii. 첨도(Kurtosis) : 중심이 얼마나 뾰족한가?

# 첨도가 0에 가까운 값이라면 중심이 보통높이

# 첨도 > 0 : 중심이 높아진다 -> 비슷한 데이터가 많이 있다.

# 첨도 < 0 : 중심이 낮아진다 -> 비슷한 데이터가 적다.


# psych::describe(), describeBy()

# R에서 by가 있다면 항상 집단별로 무엇을 한다는 의미

1
2
3
> psych::describe(hflights$ArrDelay)
   vars      n mean    sd median trimmed   mad min max range skew kurtosis   se
X1    1 223874 7.09 30.71      0    1.85 13.34 -70 978  1048 5.04    55.57 0.06
cs

# 결과 중 se : standard error(표준오차) : 0.06

# 지금 표본에서 평균이 7.09분이 나왔는데,

# '다른 표본'을 뽑으면 평균이 지금 표본의 평균과 달라질 것이다.

# 그렇다면 얼마나 달라질까를 알려주는 값 -> 표준오차


# psych::describeBy(데이터명$변수명, 데이터명$변수명)

# psych::describeBy(양적자료, 질적자료)

1
2
3
4
5
6
7
8
9
10
> psych::describeBy(hflights$ArrDelay, hflights$Origin)
 
 Descriptive statistics by group 
group: HOU
   vars     n mean    sd median trimmed   mad min max range skew kurtosis   se
X1    1 51309 7.49 31.95     -1    1.77 11.86 -44 822   866 4.98    46.08 0.14
---------------------------------------------------------------- 
group: IAH
   vars      n mean    sd median trimmed   mad min max range skew kurtosis   se
X1    1 172565 6.98 30.33      0    1.87 13.34 -70 978  1048 5.05    58.88 0.07
cs


# summary(데이터명$변수명)

# 질적 자료 = 빈도, 백분율 / 만약에 factor라면 빈도만 알려줌

# 양적 자료 = 6개(최소값, 최대값, 평균, 123사분위수)


# by(양적자료, 질적자료, 함수명)

1
2
3
4
5
6
> by(hflights$ArrDelay, hflights$Origin, mean, na.rm = TRUE)
hflights$Origin: HOU
[17.487946
---------------------------------------------------------------- 
hflights$Origin: IAH
[16.977301
cs

# 공항이 2개가 있는데 각 공항에 대하서 ArrDelay에 대한 평균을 구해줘

# 질적자료를 기준으로 양적자료에 함수를 적용한 결과를 알려줌

[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








+ Recent posts