반응형

 

[R] 기술 통계 (평균, 표준편차, 표준오차, 최댓값, 최솟값, 중위수, 분위수 등)

 

 1,000명으로 어떤 연구를 했다고 하자. 그들의 키, 몸무게 등 지표들은 서로 다를 것이다. 논문의 저자가 이 모든 것을 독자들에게 보여주고자 한다면 행이 1,000인 표를 제시해야 할 것이다. 그렇게 큰 표를 실어줄 저널이 없기도 하거니와, 독자들이 보기에도 한눈에 들어오지 않는다. 그 대신 키의 '평균', 몸무게의 '평균'을 제시하면 한눈에 들어오니 보기가 좋다. 연속 변수는 평균, 표준편차 등으로 요약을 하여 보여주고, 범주형 자료 (흡연 여부, 음주 여부 등)는 도수분포표 혹은 분할표로 제시하게 된다. 분할표를 작성하는 방법은 다음 링크에서 확인할 수 있다.

2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - table(), prop.table(), xtabs(), margin.table()

2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - CrossTable()

 

어떤 지표로 요약해줄 것인가?

1) 정규성을 따를 때: 평균 및 표준편차

 어떤 변수가 정규 분포를 따른다고 할 수 있다면, 평균과 표준편차만 알면 된다. 단 두 개의 지표만 있으면 전체 분포를 알아낼 수 있기 때문이다. (정규성을 따르는지는 정규성 검정으로 확인할 수 있으며 정규성 검정을 하는 방법은 다음 링크에서 확인할 수 있다.)

2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (1) : Q-Q plot - qqnorm(), qqline()

2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (2) : 히스토그램 - hist(), dnorm()

2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (3) : 정량적 검정 (Shapiro-Wilk, Kolmogorov-Smirnov) - shapiro.test(), ks.test()

2022.08.12 - [기술 통계/R] - [R] 정규성 검정 (4) : 정량적 검정 (Lilliefors test) - lillie.test()

 

2) 정규성을 따르지 않을 때: 중위수, 최댓값, 최솟값, 분위수, 사분위 범위 등

 정규성을 따르지 않는다면 평균과 표준편차를 안다고 해도 전체 분포를 알아낼 수는 없다. 따라서 분포에 대한 직접적인 정보를 주는데, 예를 들어 '하위 25%에 위치하는 사람의 ALT값은 얼마인가?' 등을 제시하는 것이다. 그런 지표로는 중위수, 최댓값, 최솟값, 분 위수, 사분위 범위 등이 있다.

 

이번 포스팅에서는 이 모든 지표들 (평균, 표준편차, 표준오차, 중위수, 최댓값, 최솟값, 분위수, 사분위 범위 등)을 구하는 법에 대해 소개할 것이다.

 

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.29)

 

분석용 데이터 (update 22.08.29)

2022년 08월 29일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법 1) 엑셀 파일 2) CSV 파일 3) 코드북

medistat.tistory.com

 

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/SAS] - [SAS] 라이브러리 만들기 - LIBNAME

setwd("C:/Users/user/Documents/Tistory_blog")

 

데이터를 불러와 df에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 저장하기 : CSV 파일 - write.csv(), write_csv()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

install.packages("readr")
library("readr")
df<-read_csv("Data.csv")

 

코드

이번 포스팅을 일일이 이해하기는 귀찮고 코드만 가져가고 싶은 사람은 다음 코드를 사용하면 된다. :

#기술통계 함수 작성
univariate<-function(x){
  n<-length(x)-sum(is.na(x))
  missing<-sum(is.na(x))
  mean<-mean(x)
  sd<-sd(x)
  var<-var(x)
  se<-sqrt(var/n)
  min<-min(x)
  max<-max(x)
  median<-median(x)
  mode <- function(x) {
    nodup <- unique(x)
    if (length(which(tabulate(match(x, nodup))==max(tabulate(match(x, nodup)))))>=2 )
    {NA}
    else{nodup[which.max(tabulate(match(x, nodup)))]}
  }
  mode<-mode(x)
  lclm<-mean-qt(0.975, n-1)*se
  uclm<-mean+qt(0.975, n-1)*se
  
  P25<-data.frame(quantile(x)[2])[1,1]
  P50<-data.frame(quantile(x)[3])[1,1]
  P75<-data.frame(quantile(x)[4])[1,1]
  qrange<-data.frame(quantile(x)[4])[1,1]-data.frame(quantile(x)[2])[1,1]
  name<-c("N", "N of missing","Mean", "Standard Deviation", "Variation", "Standard Error", "Minimum", 
          "Maximum", "Median", "Mode", "95% Lower limit of mean (two-sided)", "95% Upper limit of mean(two-sided)", "P25", "P50", "P75", "Quantile Range")
  value<-c(n, missing, mean, sd, var, se, min, max, median, mode, lclm, uclm, P25, P50, P75, qrange)
  result<-cbind(name, value)
  print(result)
}

#기술 통계량 계산: "df$ALT"자리에 원하는 변수를 넣으면 된다.
univariate(df$ALT)

 

결과

      name                                  value              
 [1,] "N"                                   "1000"             
 [2,] "N of missing"                        "0"                
 [3,] "Mean"                                "35.11593830339"   
 [4,] "Standard Deviation"                  "5.00643005419849" 
 [5,] "Variation"                           "25.0643418875819" 
 [6,] "Standard Error"                      "0.158317219175875"
 [7,] "Minimum"                             "19.61781834"      
 [8,] "Maximum"                             "49.03881459"      
 [9,] "Median"                              "35.13945912"      
[10,] "Mode"                                NA                 
[11,] "95% Lower limit of mean (two-sided)" "34.8052658601898" 
[12,] "95% Upper limit of mean(two-sided)"  "35.4266107465902" 
[13,] "P25"                                 "31.7559160525"    
[14,] "P50"                                 "35.13945912"      
[15,] "P75"                                 "38.5879822725"    
[16,] "Quantile Range"                      "6.83206622"

"N" : 분석 대상의 수

"N of missing" : 결측치 수

"Mean" : 평균

"Standard Deviation" : 표준 편차

"Variation" : 분산

"Standard Error" : 표준 오차

"Minimum" : 최솟값
"Maximum" : 최댓값

"Median" : 중위수

"Mode" : 최빈값 (최빈값이 여러개인 경우 NA로 표기됨)

"95% Lower limit of mean (two-sided)" : 평균의 95% 신뢰구간의 하한

"95% Upper limit of mean(two-sided)" : 평균의 95% 신뢰구간의 상한

"P25" : 1사분위수

"P50" : 2사분위수 (중위수)

"P75" : 3사분위수

"Quantile Range" : 사분위 범위
 

 

코드 (분석 대상의 수, 결측치 수, 평균, 표준 편차, 분산, 표준 오차)

코드를 하나씩 뜯어 살펴보면 다음과 같다.

univariate<-function(x){
  n<-length(x)-sum(is.na(x))
  missing<-sum(is.na(x))
  mean<-mean(x)
  sd<-sd(x)
  var<-var(x)
  se<-sqrt(var/n)
  }

univariate<-function(x){ :입력되는 값이 x인 함수를 만들건데 함수의 내용은 { }안에 들어있으니 살펴봐라. 그리고 함수의 이름은 univariate이다. 
  n<-length(x)-sum(is.na(x)) : 분석 대상의 수[n]는 전체 개체의 수[length(x)]에서 결측치의 개수 [sum(is.na(x))]를 뺀 값이다.
  missing<-sum(is.na(x)) : 결측된 것을 TRUE로, 결측되지 않은 것을 FALSE로 반환한다 [is.na(x)]. TRUE인 것을 모두 합친다 [sum(is.na(x))]. 그 값이 결측치의 개수이다.
  mean<-mean(x) : 평균은 mean() 함수를 이용한다.
  sd<-sd(x) : 표준편차는 sd() 함수를 이용한다.
  var<-var(x) : 분산은 var() 함수를 이용한다.
  se<-sqrt(var/n) : 표준오차(se)는 분산(var)을 분석 대상의 수(n)로 나눈 뒤 루트를 씌운 값이다.

 

  min<-min(x)
  max<-max(x)
  median<-median(x)
  mode <- function(x) {
    nodup <- unique(x)
    if (length(which(tabulate(match(x, nodup))==max(tabulate(match(x, nodup)))))>=2 )
    {NA}
    else{nodup[which.max(tabulate(match(x, nodup)))]}
  }
  mode<-mode(x)

  min<-min(x) : 최솟값은 min() 함수를 이용한다.
  max<-max(x) : 최댓값은 max() 함수를 이용한다.
  median<-median(x) : 중앙값은 median() 함수를 이용한다.
  mode <- function(x) { : 최빈값은 구하는 함수가 R에 내장되어있지 않으므로 함수를 따로 만들어야 한다. 데이터(x)를 입력받아 최빈값을 구하는 함수를 만들 것이고 그 함수의 이름은 mode이다.
    nodup <- unique(x) : 중복되는 값을 모두 삭제하고 한 개씩만 대표적으로 남긴다. 대표들로 이루어진 벡터를 nodup이라고 하자.
    if (length(which(tabulate(match(x, nodup))==max(tabulate(match(x, nodup)))))>=2 ) 
    {NA}
    else{nodup[which.max(tabulate(match(x, nodup)))]}

여기까지의 내용이 복잡하니 하나씩 코드를 살펴보기로 한다.

(1) 큰 구성은 if (A) {B} else {C} 이다. A라는 조건이 만족하면 B를 반환하고, A를 만족하지 않으면 C를 반환한다는 것이다.

(2) match(x, nodup):  x가 nodup에서 몇 번째 데이터와 일치하는지를 반환하는 함수다.

Example) 예를 들어 x가 (1,5,2,3,3,4,2)라고 하자.

nodup은 중복되는 값을 삭제했을 터이니 (1,5,2,3,4)일 것이다.

그렇다면 match(x,nodup)은 (1,2,3,4,4,5,3)이 된다.

(3) tabulate(match(x,nodup)): tabulate는 각 정수가 나타난 횟수를 세준다. (1,2,3,4,4,5,3)에서 1은 1개, 2는 1개, 3은 2개, 4는 2개, 5는 1개다. 따라서 tabulate(match(x,nodup))은 (1,1,2,2,1)이 된다. 

최빈값은 가장 흔한 단 한 개의 값이어야 하는데, 여기에서 3과 4는 2개, 나머지는 1개이므로 이 데이터의 최빈값은 없다. 즉, tabulate(match(x,nodup))인 (1,1,2,2,1)의 최댓값(2)이 tabulate(match(x,nodup))인 (1,1,2,2,1)에 2개 이상 존재한다면 최빈값이 없다고 반환해야 한다. 

(4) tabulate(match(x, nodup))==max(tabulate(match(x, nodup))): tabulate(match(x,nodup))인 (1,1,2,2,1)이 tabulate(match(x,nodup))인 (1,1,2,2,1)의 최댓값(2)과 같은지를 확인해주는 코드다 결과는 (FALSE, FALSE, TRUE, TRUE, FALSE)이다. 

(5) which(tabulate(match(x, nodup))==max(tabulate(match(x, nodup))))는 TRUE인 위치를 반환하므로 (3,4)를 보여준다. 

(6) length(which(tabulate(match(x, nodup))==max(tabulate(match(x, nodup)))))는 (3,4)에 있는 숫자의 개수, 즉 2를 반환한다. 

이렇게 함으로써 최빈값'같은' 값이 2개 이상 존재할 때 NA를 반환하도록 하였다.

 

그렇지 않을 때 (즉, 단 한 개의 최빈값이 존재할 때)는 다음과 같은 로직에 의해 구해진다고 생각하면 된다.

Example) x가 (1,5,2,2,3)이라고 하자.

nodup은 (1,5,2,3)이 된다.

match(x,nodup)은 (1,2,3,3,4)이 된다.

tabulate(match(x,nodup))는 (1,1,2,1)이 된다. 여기에서 횟수가 가장 많아 '2'라고 표현된 값의 근원을 찾아가야 한다.

which.max(tabulate(match(x, nodup)))는 (1,1,2,1)에서 최댓값이 존재하는 위치를 반환하므로 3이 된다.

(1,1,2,1)의 2는 match(x,nodup)인 (1,2,3,3,4)에서 온 것이다. 1이 1개, 2가 1개, 32개, 4가 1개. 즉, tabulate는 개수를 세어주므로 중복된 값을 빼는 효과가 있다. 즉 23번째에 위치한 이유는 nodup (1,5,2,3)의 2가 nodup에서 3번째에 위치해있기 때문이다. 따라서 nodup의 3번째 값을 반환해야 최빈값을 구할 수 있다. 그러므로 nodup[which.max(tabulate(match(x, nodup)))]이라는 코드를 쓰게 된다.

  }
  mode<-mode(x)

 

  lclm<-mean-qt(0.975, n-1)*se
  uclm<-mean+qt(0.975, n-1)*se
  
  P25<-data.frame(quantile(x)[2])[1,1]
  P50<-data.frame(quantile(x)[3])[1,1]
  P75<-data.frame(quantile(x)[4])[1,1]
  qrange<-data.frame(quantile(x)[4])[1,1]-data.frame(quantile(x)[2])[1,1]
  name<-c("N", "N of missing","Mean", "Standard Deviation", "Variation", "Standard Error", "Minimum", 
          "Maximum", "Median", "Mode", "95% Lower limit of mean (two-sided)", "95% Upper limit of mean(two-sided)", "P25", "P50", "P75", "Quantile Range")
  value<-c(n, missing, mean, sd, var, se, min, max, median, mode, lclm, uclm, P25, P50, P75, qrange)
  result<-cbind(name, value)
  print(result)
}

 

  lclm<-mean-qt(0.975, n-1)*se : t 분포에서 자유도(n-1)에 걸맞게 2.5%에 해당하는 값을 찾고, 표준오차를 곱하여 평균에서 빼면 95% 신뢰구간의 하한이 구해진다. 
  uclm<-mean+qt(0.975, n-1)*se : t 분포에서 자유도(n-1)에 걸맞게 2.5%에 해당하는 값을 찾고, 표준오차를 곱하여 평균에서 더하면 95% 신뢰구간의 상한이 구해진다.
  
  P25<-data.frame(quantile(x)[2])[1,1] : quantile() 함수의 2번째 값은 1사분위수를 의미한다. 데이터프레임으로 바꾸고 값만을 취한다.
  P50<-data.frame(quantile(x)[3])[1,1] : quantile() 함수의 2번째 값은 2사분위수를 의미한다. 데이터프레임으로 바꾸고 값만을 취한다.
  P75<-data.frame(quantile(x)[4])[1,1] : quantile() 함수의 2번째 값은 3사분위수를 의미한다. 데이터프레임으로 바꾸고 값만을 취한다.
  qrange<-data.frame(quantile(x)[4])[1,1]-data.frame(quantile(x)[2])[1,1] : 3사분위수에서 1사분위수를 빼어 값을 구한다.
  name<-c("N", "N of missing","Mean", "Standard Deviation", "Variation", "Standard Error", "Minimum", 
          "Maximum", "Median", "Mode", "95% Lower limit of mean (two-sided)", "95% Upper limit of mean(two-sided)", "P25", "P50", "P75", "Quantile Range") : 각 값의 이름을 지정하여 name이라는 벡터에 저장한다.
  value<-c(n, missing, mean, sd, var, se, min, max, median, mode, lclm, uclm, P25, P50, P75, qrange) : 위에서 구한 값들로 벡터를 만들고 value라는 이름을 붙인다.
  result<-cbind(name, value) : name과 value를 열 별로 합치고 result에 저장한다.
  print(result) : result를 출력한다.
}

 

 

만약 25%, 50%, 75%가 아닌 임의의 n% 백분위수를 구하고 싶다면 Pn을 사용하면 된다.

64%백분위수를 보고싶다면 P64를 사용하면 된다.

 

사분위수는 SAS, SPSS, R의 결과가 서로 다를 수 있다. 왜냐하면 각 프로그램에서 사분위수를 구하는 방법이 다를 수 있기 때문이다. 각 프로그램에는 사분위수를 구하는 여러가지 방법이 내장되어 있으며, 골라서 사용할 수도 있다.

SAS의 사분위수 확인하기:2022.09.23 - [기술 통계/SAS] - [SAS] 기술 통계 (평균, 표준편차, 표준오차, 최댓값, 최솟값, 중위수, 분위수 등) - PROC UNIVARIATE, PROC MEANS

SPSS의 사분위수 확인하기: 2022.09.29 - [기술 통계/SPSS] - [SPSS] 기술 통계 (평균, 표준편차, 표준오차, 최댓값, 최솟값, 중위수, 분위수 등)

 

 

R 기술 통계량 정복 완료!

 

작성일: 2022.09.27.

최종 수정일: 2022.09.29.

이용 프로그램: R 4.1.3

RStudio v1.4.1717

RStudio 2021.09.1+372 "Ghost Orchid" Release 

운영체제: Windows 10, Mac OS 10.15.7

반응형
반응형

 

[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - CrossTable()

 

 이전 글에서 R로 도수분포표 및 분할표를 만드는 것이 얼마나 귀찮은 일인지 설명하였다. 이 글은 아래 글의 후속 글이므로 미리 읽고 오길 권한다.

2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - table(), prop.table(), xtabs(), margin.table()

 

[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - table(), prop.table(), xtabs(), margin.table()

[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - table(), prop.table(), xtabs(), margin.table()  수천 명의 정보를 포함한 데이터를 한눈에 요약하고 싶을 때가 많다...

medistat.tistory.com

 

이 귀찮은 일을 한꺼번에 해주는 함수로 CrossTable()이 있다. 이를 소개하고 한계점 및 일부 해결 방안을 소개한다.

 

 

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.29)

 

분석용 데이터 (update 22.08.29)

2022년 08월 29일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법 1) 엑셀 파일 2) CSV 파일 3) 코드북

medistat.tistory.com

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/SAS] - [SAS] 라이브러리 만들기 - LIBNAME

setwd("C:/Users/user/Documents/Tistory_blog")

 

데이터를 불러와 df에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 저장하기 : CSV 파일 - write.csv(), write_csv()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

 

install.packages("readr")
library("readr")
df<-read_csv("Data.csv")

 

CrossTable() 함수는 gmodels라는 패키지에 있으므로 패키지를 설치한다.

패키지 설치 방법은 다음 글에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 패키지 설치하기 - install.packages(), library()

install.packages("gmodels")
library("gmodels")

 

코드

성별과 음주 여부에 대해 분할표를 작성하도록 하겠다.

CrossTable(df$SEX, df$ALCOHOL, prop.chisq=FALSE)

CrossTable(df$SEX, df$ALCOHOL, prop.chisq=FALSE) : 데이터 df에 있는 SEX와 ALCOHOL로 교차 표를 출력한다. 카이 제곱 검정 기여량은 출력하지 않는다. (백분율, 행백분율, 열백분율은 출력하는 것이 기본 설정이다.)

 

결과

   Cell Contents
|-------------------------|
|                       N |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  1000 

 
             | df$ALCOHOL 
      df$SEX |         0 |         1 | Row Total | 
-------------|-----------|-----------|-----------|
           0 |       236 |       246 |       482 | 
             |     0.490 |     0.510 |     0.482 | 
             |     0.576 |     0.417 |           | 
             |     0.236 |     0.246 |           | 
-------------|-----------|-----------|-----------|
           1 |       174 |       344 |       518 | 
             |     0.336 |     0.664 |     0.518 | 
             |     0.424 |     0.583 |           | 
             |     0.174 |     0.344 |           | 
-------------|-----------|-----------|-----------|
Column Total |       410 |       590 |      1000 | 
             |     0.410 |     0.590 |           | 
-------------|-----------|-----------|-----------|

이전 글 (2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - table(), prop.table(), xtabs(), margin.table())과 거의 같은 결과가 도출된다.

 

코드-퍼센트를 산출 및 소수점 이하 숫자 제한하고 싶을 때

CrossTable(df$SEX, df$ALCOHOL, prop.chisq=FALSE, format=c("SPSS"), digits=2)

결과

  Cell Contents
|-------------------------|
|                   Count |
|             Row Percent |
|          Column Percent |
|           Total Percent |
|-------------------------|

Total Observations in Table:  1000 

             | df$ALCOHOL 
      df$SEX |        0  |        1  | Row Total | 
-------------|-----------|-----------|-----------|
           0 |      236  |      246  |      482  | 
             |    48.96% |    51.04% |    48.20% | 
             |    57.56% |    41.69% |           | 
             |    23.60% |    24.60% |           | 
-------------|-----------|-----------|-----------|
           1 |      174  |      344  |      518  | 
             |    33.59% |    66.41% |    51.80% | 
             |    42.44% |    58.31% |           | 
             |    17.40% |    34.40% |           | 
-------------|-----------|-----------|-----------|
Column Total |      410  |      590  |     1000  | 
             |    41.00% |    59.00% |           | 
-------------|-----------|-----------|-----------|

 

참 강력한 툴이지만 단점이 존재한다.

 

1) 도수분포표의 경우 누적 도수를 산출해주지 않는다.

2) 세 개 이상의 변수를 사용한 분할표를 작성해주지 않는다.

 

첫 번째 단점은 해결할 수 없다.

두 번째 단점인 "세 개 이상의 변수를 사용한 분할표"는 억지로 작성할 수는 있다. 

성별과 음주 여부에 관한 분할표를 고혈압 여부에 따라 작성하고자 한다고 하자. 그렇다면 고혈압이 있는 집단과 없는 집단을 미리 나눠놔야 한다.

 

코드

subsample_wohtn<-df[df$HTN==0,]
subsample_whtn<-df[df$HTN==1,]

CrossTable(subsample_wohtn$SEX, subsample_wohtn$ALCOHOL, prop.chisq=FALSE)
CrossTable(subsample_whtn$SEX, subsample_whtn$ALCOHOL, prop.chisq=FALSE)

subsample_wohtn<-df[df$HTN==0,] : 데이터 df의 HTN변수가 0인 사람만 뽑아 "subsample_wohtn"에 저장한다.
subsample_whtn<-df[df$HTN==1,] : 데이터 df의 HTN변수가 1인 사람만 뽑아 "subsample_whtn"에 저장한다.

CrossTable(subsample_wohtn$SEX, subsample_wohtn$ALCOHOL, prop.chisq=FALSE) : HTN변수가 0인 사람들로만 성별과 음주 여부의 분할표를 작성한다.
CrossTable(subsample_whtn$SEX, subsample_whtn$ALCOHOL, prop.chisq=FALSE) : HTN변수가 1인 사람들로만 성별과 음주 여부의 분할표를 작성한다.

 

결과

   Cell Contents
|-------------------------|
|                       N |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  503 

 
                    | subsample_wohtn$ALCOHOL 
subsample_wohtn$SEX |         0 |         1 | Row Total | 
--------------------|-----------|-----------|-----------|
                  0 |       114 |       122 |       236 | 
                    |     0.483 |     0.517 |     0.469 | 
                    |     0.562 |     0.407 |           | 
                    |     0.227 |     0.243 |           | 
--------------------|-----------|-----------|-----------|
                  1 |        89 |       178 |       267 | 
                    |     0.333 |     0.667 |     0.531 | 
                    |     0.438 |     0.593 |           | 
                    |     0.177 |     0.354 |           | 
--------------------|-----------|-----------|-----------|
       Column Total |       203 |       300 |       503 | 
                    |     0.404 |     0.596 |           | 
--------------------|-----------|-----------|-----------|





   Cell Contents
|-------------------------|
|                       N |
|           N / Row Total |
|           N / Col Total |
|         N / Table Total |
|-------------------------|

 
Total Observations in Table:  497 

 
                   | subsample_whtn$ALCOHOL 
subsample_whtn$SEX |         0 |         1 | Row Total | 
-------------------|-----------|-----------|-----------|
                 0 |       122 |       124 |       246 | 
                   |     0.496 |     0.504 |     0.495 | 
                   |     0.589 |     0.428 |           | 
                   |     0.245 |     0.249 |           | 
-------------------|-----------|-----------|-----------|
                 1 |        85 |       166 |       251 | 
                   |     0.339 |     0.661 |     0.505 | 
                   |     0.411 |     0.572 |           | 
                   |     0.171 |     0.334 |           | 
-------------------|-----------|-----------|-----------|
      Column Total |       207 |       290 |       497 | 
                   |     0.416 |     0.584 |           | 
-------------------|-----------|-----------|-----------|

 

 

 

 

[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 정복 완료!

 

작성일: 2022.08.31.

최종 수정일: 2022.08.31.

이용 프로그램: R 4.1.3

RStudio v1.4.1717

RStudio 2021.09.1+372 "Ghost Orchid" Release 

운영체제: Windows 10, Mac OS 10.15.7

반응형
반응형

[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - table(), prop.table(), xtabs(), margin.table()

 

 수천 명의 정보를 포함한 데이터를 한눈에 요약하고 싶을 때가 많다. 나이, 혈압과 같은 연속형 변수는 평균으로 요약하곤 하는데, 성별이나 음주 여부는 평균을 구할 수 없으니 빈도를 제시하곤 한다. 이를 표로 제시하면 도수분포표 (Frequency table)가 된다. 이를 넘어서 남성 중 음주자가 몇 명인지, 여성중 비음주자가 몇 명인지 알고 싶을 때가 있는데, 이때 사용하는 것이 분할표 (Contingency table)이다. 즉 본 글의 목적은 다음 두 개의 표 내용을 채우는 것이다.

 

<도수분포표>

  빈도 백분율 누적빈도 누적백분율
여성        
남성        

 

<분할표>

  비음주자 음주자 합계
여성      
남성      
합계      

 

R이 웬만한 프로그램보다 거의 모든 분야에서 분석하기엔 훨씬 편리하다. 하지만 오늘 다룰 도수분포표 및 분할표는 R이 압도적으로 불편하다. 그 불편한 분석을 오늘 해보고자 한다. (이런 이유로 CrossTable이라는 훌륭한 함수가 개발된 듯 하다. 다음 글로 소개하겠다. -2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - CrossTable())

 

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.29)

 

분석용 데이터 (update 22.08.29)

2022년 08월 29일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법 1) 엑셀 파일 2) CSV 파일 3) 코드북

medistat.tistory.com

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 작업 디렉토리 (Working Directory) 지정 - getwd(), setwd()

setwd("C:/Users/user/Documents/Tistory_blog")

 

데이터를 불러와 df에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 저장하기 : CSV 파일 - write.csv(), write_csv()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

install.packages("readr")
library("readr")
df<-read_csv("Data.csv")

 

도수분포표

코드 - table() 

* 변수: SEX (성별)

  -0: 여성

  -1: 남성

table(df$SEX)

table(df$SEX) :df데이터에 있는 SEX변수로 도수분포표를 만들어라.

 

결과

  0   1 
482 518

 

해석

SEX(성별)이 0(여성)인 사람이 482명, 1(남성)인 사람이 518명이다.

 

하지만 앞으로 table()함수는 사용하지 않을 것이다. 왜냐하면, 보면 알겠지만 어떤 변수를 분석한 것인지 표시되지 않는다. 한 개의 변수를 분석할 때에는 문제가 되지 않겠지만 당장 분석하게 될 분할표에서는 2개 이상의 변수가 들어가는데, 어떤 변수가 행에 들어갔는지, 열에 들어갔는지 표시되지 않으므로 헷갈릴 때가 있기 때문이다.

 

코드 - xtabs() 

xtabs(~SEX, data=df)

xtabs(~SEX, data=df) : df라는 데이터에 있는 SEX로 도수분포표를 만들어라. 단, 도수는 정해져 있지 않다. 

 

도수란 무엇인가?

만약 데이터가 다음과 같다면 도수가 있는 데이터라고 할 수 있다.

SEX(성별) ALCOHOL(음주) N(도수=몇 명인데?)
0 1 10
0 0 20
1 1 20
1 0 50

이 데이터는

여성 & 음주자: 10명

여성 & 비음주자: 20명

남성 & 음주자: 20명

남성 & 비음주자: 50명

임을 의미한다. 즉 각 특성을 갖는 사람이 몇 명인지 알려주는 것인데 이런 변수가 있다면 코드 xtabs(~SEX, data=df) ~왼쪽에 N을 적어야 한다.

 

#만약 도수를 나타내는 변수가 있는 자료였다면?
xtabs(N~SEX, data=df)

위 코드는 가상의 코드임으로 구동되지 않는다.

 

결과

SEX
  0   1 
482 518

함수 xtabs()는 정말 고맙게도 변수의 이름을 표기해준다.

 

표의 다음 파란 글씨를 이제 채울 수 있게 되었다.

  빈도 백분율 누적빈도 누적백분율
여성 482      
남성 518      

 

코드 - 분율

분율을 구하는 법은 다음과 같다.

prop.table(xtabs(~SEX, data=df))

prop.table(xtabs(~SEX, data=df)) :위에서 구한 도수분포표 [코드: xtabs(~SEX, data=df)]의 분율(proportion)을 구하라.

 

결과

SEX
    0     1 
0.482 0.518

SEX=0의 분율은 0.482, SEX=1의 분율은 0.518이다. 

하지만, %로 나타난 백분율이 아니므로 이대로는 표에 넣을 수 없다. 그리고 이런 식의 코드는 복잡함을 증대시키기 때문에 보통 다음과 같은 코드를 사용한다. 순서대로 설명하면 다음과 같다.

 

코드 - 백분율

freq_sex<-xtabs(~SEX, data=df)
prop_sex<-prop.table(freq_sex)
prop_sex_100<-100*prop_sex
prop_sex_100
round(prop_sex_100,digits=0)

freq_sex<-xtabs(~SEX, data=df) : 데이터 df안에 있는 변수 SEX의 도수분포표를 작성하여 freq_sex에 저장하라.

prop_sex<-prop.table(freq_sex)  : freq_sex의 분율을 구하여 prop_sex에 저장하라.
prop_sex_100<-100*prop_sex : prop_sex에 100을 곱하여 prop_sex_100에 저장하라

prop_sex_100 : prop_sex_100가 뭔지 보여달라.
round(prop_sex_100,digits=0) : prop_sex_100을 소수점 1번째 자리에서 반올림하여 정수로 보여달라

 

결과

SEX
   0    1 
48.2 51.8

SEX
 0  1 
48 52

위의 결과가 일반적인 백분율, 아래 결과는 정수로 반올림한 백분율을 나타낸다. 드디어 표의 두 번째 열을 채울 수 있게 되었다.

 

  빈도 백분율 누적빈도 누적백분율
여성 482 48.2    
남성 518 51.8    

 

코드 - 누적 빈도, 누적 백분율

#누적 빈도 구하기
cumsum(freq_sex)

#누적 백분율 구하기
cumsum(prop_sex_100)

cumsum(freq_sex) : freq_sex (도수분포표)의 누적 도수를 구하라.
cumsum(prop_sex_100) : prop_sex_100 (백분율)로 누적 백분율을 구하라.

 

결과

   0    1 
 482 1000 
 
     0     1 
 48.2 100.0

 

이제 표를 완성할 수 있게 되었다.

  빈도 백분율 누적빈도 누적백분율
여성 482 48.2 482 48.2
남성 518 51.8 1000 100.0

 

도수분포표 코드 전체

#작업 디렉토리 지정
setwd("C:/Users/user/Documents/Tistory_blog")

#데이터 불러오기
install.packages("readr")
library("readr")
df<-read_csv("Data.csv")

#도수분포표
freq_sex<-xtabs(~SEX, data=df) 
freq_sex                       #빈도 
prop_sex<-prop.table(freq_sex) 
prop_sex_100<-100*prop_sex
prop_sex_100                   #백분율
round(prop_sex_100,digits=0)
cumsum(freq_sex)               #누적 빈도
cumsum(prop_sex_100)           #누적 백분율

 

 

 

분할표

분할표를 작성해보자. 코드는 다음과 같다.

코드 - 빈도

#각 셀의 빈도 구하기
freq_sex_alc<-xtabs(~SEX+ALCOHOL, data=df)
freq_sex_alc

#행 별로 합친 빈도 구하기
freq_sex<-margin.table(freq_sex_alc, margin=1)
freq_sex

#열 별로 합친 빈도 구하기
freq_alc<-margin.table(freq_sex_alc, margin=2)
freq_alc

#전체 데이터 수 구하기
total_freq_sex_alc<-sum(freq_sex_alc) #혹은 sum(freq_sex)이나 sum(freq_alc)도 가능
total_freq_sex_alc

freq_sex_alc<-xtabs(~SEX+ALCOHOL, data=df) : ( '+' 표시 앞에 있는) SEX를 세로축에, ('+' 표시 뒤에 있는) ALCOHOL을 가로축에 넣고 분할표를 만들고 freq_sex_alc에 저장하라. 이때 데이터는 df를 사용하라.
freq_sex_alc : 만든 분할표를 보여달라.
freq_sex<-margin.table(freq_sex_alc, margin=1) :행 별로 합친 도수분포표 만들고 freq_sex에 저장하라. 즉, 성별의 도수분포표를 보여달라는 뜻이고 본 데이터에는 결측치가 없으므로 이는 "xtabs(~SEX, data=df)"와 같은 결과를 보여준다. (결측치가 있으면 결과가 다를 수 있다.)
freq_sex : 성별의 도수분포표를 보여달라.
freq_alc<-margin.table(freq_sex_alc, margin=2) :열 별로 합친 도수분포표 만들고 freq_alc에 저장하라. 즉, 음주 여부의 도수분포표를 보여달라는 뜻이고 본 데이터에는 결측치가 없으므로 이는 "xtabs(~ALCOHOL, data=df)"와 같은 결과를 보여준다. (결측치가 있으면 결과가 다를 수 있다.)
freq_alc : 음주 여부의 도수분포표를 보여달라.

total_freq_sex_alc<-sum(freq_sex_alc) : 빈도를 모두 더해 total_freq_sex_alc에 저장하라.
total_freq_sex_alc :총빈도수를 보여달라.

 

 

결과

   ALCOHOL
SEX   0   1
  0 236 246
  1 174 344
  
SEX
  0   1 
482 518 

ALCOHOL
  0   1 
410 590

[1] 1000

 

xtabs()함수의 진가는 분할표를 만들 때에 나온다. table()함수에는 나오지 않는 각 변수명을 보여주니 말이다. 위 데이터로 표의 빈도를 채울 수 있게 되었다.

빈도
백분율
행백분율
열백분율
비음주자 음주자 합계
여성 236 246 482
남성 174 344 518
합계 410 590 1000

 

코드 - 백분율

#각 셀의 백분율
prop_sex_alc<-prop.table(freq_sex_alc)
prop_sex_alc_100<-100*prop_sex_alc
prop_sex_alc_100

#행 별로 합친 데이터의 백분율
prop_sex<-prop.table(freq_sex)
prop_sex_100<-100*prop_sex
prop_sex_100

#열 별로 합친 데이터의 백분율
prop_alc<-prop.table(freq_alc)
prop_alc_100<-100*prop_alc
prop_alc_100

#전체 데이터의 백분율
prop_total<-prop.table(total_freq_sex_alc)
prop_total_100<-100*prop_total
prop_total_100

prop_sex_alc<-prop.table(freq_sex_alc) :2*2 분할표에서 각 셀의 분율을 구하고 prop_sex_alc에 저장하라
prop_sex_alc_100<-100*prop_sex_alc : 분율에 100을 곱하여 백분율을 구하고 prop_sex_alc_100에 저장하라
prop_sex_alc_100 : 백분율을 보여달라

 

prop_sex<-prop.table(freq_sex) :행 별로 합친 데이터의 분율을 구하고 prop_sex에 저장하라
prop_sex_100<-100*prop_sex : 분율에 100을 곱하여 백분율을 구하고 prop_sex_100에 저장하라
prop_sex_100 : 백분율을 보여달라

 

prop_alc<-prop.table(freq_sex) :열 별로 합친 데이터의 분율을 구하고 prop_alc에 저장하라
prop_alc_100<-100*prop_alc : 분율에 100을 곱하여 백분율을 구하고 prop_alc_100에 저장하라
prop_alc_100 : 백분율을 보여달라

 

prop_total<-prop.table(total_freq_sex_alc) : 전체 데이터를 합쳤을 때 분율을 구하고 prop_total에 저장하라
prop_total_100<-100*prop_total :분율에 100을 곱하여 백분율을 구하고 prop_total_100에 저장하라
prop_total_100 : 백분율을 보여달라

결과

   ALCOHOL
SEX    0    1
  0 23.6 24.6
  1 17.4 34.4
  
SEX
   0    1 
48.2 51.8 

ALCOHOL
 0  1 
41 59

[1] 100

표의 백분율을 채울 수 있게 되었다.

빈도
백분율
행백분율
열백분율
비음주자 음주자 합계
여성 236
23.6%
246
24.6%
482
48.2%
남성 174
17.4%
344
34.4%
518
51.8%
합계 410
41.0%
590
59.0%
1000
100.0%

백분율은 가로로 합하면 가로 합계의 백분율과 일치하고, 세로로 더하면 세로 합계의 백분율과 일치한다.

 

코드  - 행백분율

sum_row<-rowSums(freq_sex_alc)
prop_row<-freq_sex_alc/sum_row
prop_row_100<-100*prop_row
prop_row_100
round(prop_row_100, digits=2)

sum_row<-rowSums(freq_sex_alc) : 행 별로 더한 값을 sum_row에 저장한다. 즉 남성과 여성이 각각 몇 명이 있는지 보여준다. 이 값은 겉으로 보기엔 "freq_sex"와 같다. 하지만 속성이 약간 다르며 freq_sex로 대체할 수 없다.
prop_row<-freq_sex_alc/sum_row : 각 셀의 빈도를 행별로 더한 값으로 나눈다. 즉, 음주자건 비음주자건 남성이면 남성의 수로 나누고, 여성이면 여성의 수로 나눈다. 그리하여 분율을 구한다.
prop_row_100<-100*prop_row : 분율에 100을 곱해 백분율을 구한다. 
prop_row_100 : 백분율을 보여달라.

round(prop_row_100, digits=2) : 소수점 셋째 자리에서 반올림하여 둘째 자리까지만 표기하라.

 

결과

   ALCOHOL
SEX        0        1
  0 48.96266 51.03734
  1 33.59073 66.40927
  
   ALCOHOL
SEX     0     1
  0 48.96 51.04
  1 33.59 66.41

반올림한 결과가 훨씬 보기 편한 걸 알 수 있다. 그리고 가로로 합하면 100이 나오는 것을 볼 수 있다.

 

표의 행백분율을 채울 수 있게 되었다.

빈도
백분율
행백분율
열백분율
비음주자 음주자 합계
여성 236
23.6%
48.96%
246
24.6%
51.04%
482
48.2%
남성 174
17.4%
33.59%
344
34.4%
66.41%
518
51.8%
합계 410
41.0%
590
59.0%
1000
100.0%

 

코드 - 열백분율

R 특성상 조금 더 복잡해진다.

sum_col<-colSums(freq_sex_alc)
prop_col<-t(t(freq_sex_alc)/sum_col)
prop_col_100<-100*prop_col
prop_col_100
round(prop_col_100, digits=2)

sum_col<-colSums(freq_sex_alc) : 열 별로 더한 값을 sum_col에 저장한다. 즉 음주자와 비음주자가 각각 몇 명이 있는지 보여준다. 이 값은 겉으로 보기엔 "freq_alc"와 같다. 하지만 속성이 약간 다르며 freq_alc로 대체할 수 없다.
prop_col<-t(t(freq_sex_alc)/sum_col) : R에서 나눌 때에는 행 별로 나눈다. 즉 열 별로 나누려면 행/열을 바꾼 다음에 나누어야 한다. 어려운 말로 전치 행렬을 구해야 한다는 것이고 전치 행렬을 구하는 명령어가 t()다. 나눈 다음에 다시 한번 행/열을 바꾸지 않으면 세로에 음주 여부, 가로에 성별에 들어가 있으므로 보기에 편하려면 다시 한번 전치 행렬을 구해야 한다.
prop_col_100<-100*prop_col : 분율에 100을 곱해 백분율을 구한다. 
prop_col_100 : 백분율을 보여달라.
round(prop_col_100, digits=2) : 소수점 셋째 자리에서 반올림하여 둘째 자리까지만 표기하라.

 

결과

   ALCOHOL
SEX        0        1
  0 57.56098 41.69492
  1 42.43902 58.30508
  
   ALCOHOL
SEX     0     1
  0 57.56 41.69
  1 42.44 58.31

 

표를 완성할 수 있다.

빈도
백분율
행백분율
열백분율
비음주자 음주자 합계
여성 236
23.6%
48.96%
57.56%
246
24.6%
51.04%
41.69%

482
48.2%
남성 174
17.4%
33.59%
42.44%

344
34.4%
66.41%
58.31%

518
51.8%
합계 410
41.0%
590
59.0%
1000
100.0%

 

분할표 코드 전체

#작업 디렉토리 지정
setwd("C:/Users/user/Documents/Tistory_blog")

#데이터 불러오기
install.packages("readr")
library("readr")
df<-read_csv("Data.csv")

########빈도########

#각 셀의 빈도 구하기
freq_sex_alc<-xtabs(~SEX+ALCOHOL, data=df)
freq_sex_alc

#행 별로 합친 빈도 구하기
freq_sex<-margin.table(freq_sex_alc, margin=1)
freq_sex

#열 별로 합친 빈도 구하기
freq_alc<-margin.table(freq_sex_alc, margin=2)
freq_alc

#전체 데이터 수 구하기
total_freq_sex_alc<-sum(freq_sex_alc) #혹은 sum(freq_sex)이나 sum(freq_alc)도 가능
total_freq_sex_alc



########백분율########

#각 셀의 백분율
prop_sex_alc<-prop.table(freq_sex_alc)
prop_sex_alc_100<-100*prop_sex_alc
prop_sex_alc_100

#행 별로 합친 데이터의 백분율
prop_sex<-prop.table(freq_sex)
prop_sex_100<-100*prop_sex
prop_sex_100

#열 별로 합친 데이터의 백분율
prop_alc<-prop.table(freq_alc)
prop_alc_100<-100*prop_alc
prop_alc_100

#전체 데이터의 백분율
prop_total<-prop.table(total_freq_sex_alc)
prop_total_100<-100*prop_total
prop_total_100


########행백분율########

sum_row<-rowSums(freq_sex_alc)
prop_row<-freq_sex_alc/sum_row
prop_row_100<-100*prop_row
prop_row_100
round(prop_row_100, digits=2)


########열백분율########

sum_col<-colSums(freq_sex_alc)
prop_col<-t(t(freq_sex_alc)/sum_col)
prop_col_100<-100*prop_col
prop_col_100
round(prop_col_100, digits=2)

 

세 개 이상의 변수를 사용하는 분할표

코드

freq_sex_alc_htn<-xtabs(~SEX+ALCOHOL+HTN, data=df)
freq_sex_alc_htn

freq_sex_alc_htn<-xtabs(~SEX+ALCOHOL+HTN, data=df) : 데이터는 df를 사용하되 세로축에 SEX, 가로축에 ALCOHOL을 놓는다. HTN 값 별로 분할표를 각각 만들어 freq_sex_alc_htn에 저장한다.
freq_sex_alc_htn : 각각의 분할표를 보여달라.

 

결과

, , HTN = 0

   ALCOHOL
SEX   0   1
  0 114 122
  1  89 178

, , HTN = 1

   ALCOHOL
SEX   0   1
  0 122 124
  1  85 166

고혈압이 없는 (HTN=0) 사람들과 고혈압이 있는 (HTN=1) 사람들의 분할표를 각각 보여준다. 인구를 고혈압뿐만 아니라 RH혈액형으로도 나누고 싶다면 HTN뒤에 "+RH"를 붙여 다음과 같은 코드를 쓰면 된다.

 

#코드
freq_sex_alc_htn_rh<-xtabs(~SEX+ALCOHOL+HTN+RH, data=df)
freq_sex_alc_htn_rh

#결과
, , HTN = 0, RH = 0

   ALCOHOL
SEX   0   1
  0   0   0
  1   2   2

, , HTN = 1, RH = 0

   ALCOHOL
SEX   0   1
  0   1   0
  1   1   0

, , HTN = 0, RH = 1

   ALCOHOL
SEX   0   1
  0 114 122
  1  87 176

, , HTN = 1, RH = 1

   ALCOHOL
SEX   0   1
  0 121 124
  1  84 166

 

SAS에는 인구를 나누는 변수를 맨 앞에 쓰지만, R에서는 맨 뒤에 쓴다는 것을 유의해야 한다.

SAS에서의 분할표 작성법:

2022.08.18 - [기술 통계/SAS] - [SAS] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - PROC FREQ

 

[SAS] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - PROC FREQ

[SAS] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - PROC FREQ  수천 명의 정보를 포함한 데이터를 한눈에 요약하고 싶을 때가 많다. 나이, 혈압과 같은 연속형 변수는 평균으..

medistat.tistory.com

 

결론적으로 R로 분할표를 만드는 것은 매우 귀찮은 일이기 때문에 SPSS나 SAS를 쓰거나 CrossTable()함수를 쓰길 권한다.

2022.08.31 - [기술 통계/R] - [R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 - CrossTable()

 

[R] 도수분포표 (Frequency table), 분할표 (Contingency table) 만들기 정복 완료!

 

작성일: 2022.08.31.

최종 수정일: 2022.08.31.

이용 프로그램: R 4.1.3

RStudio v1.4.1717

RStudio 2021.09.1+372 "Ghost Orchid" Release 

운영체제: Windows 10, Mac OS 10.15.7

반응형
반응형

[R] 고급 Q-Q Plot - Van der Waerden, Rankit, Tukey, Blom

다음 글을 읽고 와야 이해하기 편하므로 먼저 읽고 올 것을 권한다.

2022.08.12 - [통계 이론] - [이론] Q-Q Plot (Quantile-Quantile Plot)

 

[이론] Q-Q Plot (Quantile-Quantile Plot)

[이론] Q-Q Plot (Quantile-Quantile Plot) 정규성을 검정할 때 Q-Q Plot을 쓰곤 한다. 그런데 이런 궁금증이 들 수 있다. 왜 Q-Q Plot이 직선에 가까운 것이 정규성을 따른다는 뜻인가? 이에 대해 조목조목..

medistat.tistory.com

 

Q-Q Plot의 이론에서 상대적 위치를 대칭적으로 정하는 방법이 여럿 있다고 언급했다. 본 글에서는 R에서 권하는 방법이 아니라, 특정 방법을 지정하여 Q-Q Plot을 그리는 법에 대해 소개하겠다.

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 작업 디렉토리 (Working Directory) 지정 - getwd(), setwd()

setwd("C:/Users/user/Documents/Tistory_blog")

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.10)

 

분석용 데이터 (update 22.08.11)

2022년 08월 11일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법

medistat.tistory.com

데이터를 불러와 a에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.08 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : CSV - read_csv(), read.csv(), fread()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

install.packages("readr")
library("readr")
a<-read_csv("Data.csv")

 

1) Van der Waerden 방법

Van der Waerden방법은 $\frac{k}{n+1}$이라는 수식을 사용한다.

 

코드

ALT_Data<-sort(a$ALT)
QQ_Van<-(c(1:length(ALT_Data)))/(length(ALT_Data)+1)
Z_Van<-qnorm(QQ_Van,0,1)
plot(Z_Van,ALT_Data)

ALT_Data<-sort(a$ALT) : a라는 데이터셋의 ALT 변수를 가져와 오름차순으로 정렬하여 ALT_Data에 저장한다.
QQ_Van<-(c(1:length(ALT_Data)))/(length(ALT_Data)+1) : Van der Waerden 수식의 $n$에 해당하는 데이터셋의 수를 의미한다. 우리 데이터에는 1,000명의 정보가 있으므로, 이는 1,000와 같다.

QQ_Van<-(c(1:length(ALT_Data)))/(length(ALT_Data)+1) : 1부터 1,000까지 1,001로 나누어 이를 QQ1에 저장한다.

Z_Van<-qnorm(QQ_Van,0,1) : 정규분포 상 $-\infty$부터 적분했을 때 QQ1의 각 값과 같아지는 $Z$값들을 구해 Z1에 저장한다.
plot(Z_Van,ALT_Data) : Z1과 ALT_Data로 plot을 그린다.

 

결과

2) Rankit 방법

Rankit 방법은 $\frac{k-\frac{1}{2}}{n}$이라는 수식을 사용한다.

 

코드

ALT_Data<-sort(a$ALT)
QQ_Rankit<-(c(1:length(ALT_Data))-1/2)/length(ALT_Data)
Z_Rankit<-qnorm(QQ_Rankit,0,1)
plot(Z_Rankit,ALT_Data)

결과

3) Tukey 방법

Tukey 방법은 $\frac{k-\frac{1}{3}}{n+\frac{1}{3}}$이라는 수식을 사용한다.

 

코드

ALT_Data<-sort(a$ALT)
QQ_Tukey<-(c(1:length(ALT_Data))-1/3)/(length(ALT_Data)+1/3)
Z_Tukey<-qnorm(QQ_Tukey,0,1)
plot(Z_Tukey,ALT_Data)

결과

4) Blom 방법

Blom 방법은 $\frac{k-\frac{3}{8}}{n+\frac{1}{4}}$이라는 수식을 사용한다.

 

코드

ALT_Data<-sort(a$ALT)
QQ_Blom<-(c(1:length(ALT_Data))-3/8)/(length(ALT_Data)+1/4)
Z_Blom<-qnorm(QQ_Blom,0,1)
plot(Z_Blom,ALT_Data)

결과

 지금까지의 결과를 보면 알겠지만, 그림의 차이를 찾아볼 수 없을 정도로 거의 동일하다. 이렇게 $n$수가 충분하면 어떤 방법을 고르든 거의 똑같은 결과를 내주므로 적용할 방법에 대해 크게 연연할 필요가 없다.

 

[R] 고급 Q-Q Plot 정복 완료!

 

작성일: 2022.08.16.

최종 수정일: 2022.08.16.

이용 프로그램: R 4.1.3

RStudio v1.4.1717

RStudio 2021.09.1+372 "Ghost Orchid" Release 

운영체제: Windows 10, Mac OS 10.15.7

반응형
반응형

[R] 정규성 검정 (4) : 정량적 검정 (Lilliefors test) - lillie.test()

정규성 검정을 하는 방법은 지금까지 다룬 세 가지가 많이 쓰인다.

 

정규성 검정 방법

1) QQ plot : 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (1) : QQplot - qqnorm()

2) 히스토그램: 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (2) : 히스토그램 - hist(), dnorm()

3) 통계적 검정: 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (3) : 정량적 검정 (Shapiro-Wilk, Kolmogorov-Smirnov) - shapiro.test(), ks.test()

 

세 번째 방법인 통계적 검정에서 Kolmogorov-Smirnov test는 그대로 사용하지 않고 p-value만 교정한 Lilliefors test를 더 많이 사용한다. SPSS에서도 Lilliefors 교정된 Kolmogorov-Smirnov test 결과를 보여주는 것을 다음 링크에서 확인할 수 있다. 2022.08.11 - [기술 통계/SPSS] - [SPSS] 정규성 검정

 

그래서 이번에는 R에서 Lilliefors test를 하는 방법을 다뤄보고자 한다.

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 작업 디렉토리 (Working Directory) 지정 - getwd(), setwd()

setwd("C:/Users/user/Documents/Tistory_blog")

 

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.10)

 

분석용 데이터 (update 22.08.11)

2022년 08월 11일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법

medistat.tistory.com

 

데이터를 불러와 a에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.08 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : CSV - read_csv(), read.csv(), fread()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

 

install.packages("readr")
library("readr")
a<-read_csv("Data.csv")

 

Lilliefors test를 위해서는 "nortest" 패키지의 "lillie.test()"함수를 사용한다. 따라서 설치한 뒤 데이터의 변수 ALT로 lilliefors test를 시행하는 코드는 다음과 같다.

 

코드

install.packages("nortest")
library("nortest")
lillie.test(a$ALT)

 

결과

	Lilliefors (Kolmogorov-Smirnov) normality test

data:  a$ALT
D = 0.015397, p-value = 0.8184

Kolmogorov-Smirnov test결과와 D statistics 값은 0.015397로 같은데, p-value만 다르다는 것을 알 수 있다. (Kolmogorov-Smirnov test결과는 다음 링크에서 확인할 수 있다.2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (3) : 정량적 검정 (Shapiro-Wilk, Kolmogorov-Smirnov) - shapiro.test(), ks.test())

 

 

해석방법

초급자: p-value>0.05이므로 정규성을 따른다.

 

중급자:

 

귀무 가설과 대립 가설은 다음과 같다.

-귀무 가설: ALT는 정규성을 따른다.

-대립 가설: ALT는 정규성을 따르지 않는다.

 

이때 제 1종 오류는 다음과 같다.

제 1종 오류

=귀무 가설이 참인데도 기각하고 대립 가설을 택함

=ALT는 정규성을 따르는데도 따르지 않는다고 결론 내림

 

p-value는 제 1종 오류를 범할 확률을 의미하므로 다음과 같이 결론 내릴 수 있다.

결론: 정규성을 따르는 것이 진실인데, 따르지 않는다고 결론 내렸을 확률이 0.05보다 크다.

=정규성을 따르는 것이 진실인데, 따르지 않는다고 결론 내린 것은 잘못일 수 있다.

=정규성을 따르지 않는다고는 할 수 없다.

 

고급자:

-본 데이터의 n 수는 1,000명으로 2,000명 미만이므로 Shapiro-Wilk test의 결과를 인용해야 한다. 따라서 본 결과는 신뢰하지 않는다.

-또한, QQplot과 히스토그램의 결과도 고려하여 정규성 여부를 판단해야 한다.

 

R 정규성 검정 (정량적 검정 - Lilliefors test) 정복 완료!

 

작성일: 2022.08.12.

최종 수정일: 2022.08.12.

이용 프로그램: R 4.1.3, RStudio v1.4.1717

운영체제: Windows 10

반응형
반응형

[R] 정규성 검정 (3) : 정량적 검정 (Shapiro-Wilk, Kolmogorov-Smirnov) - shapiro.test(), ks.test()

 

 많은 통계 분석에서 전제조건으로 데이터의 정규성(normality)을 요구하곤 한다. 검정하는 여러 방법이 다음과 같이 존재하지만, 그중 어떤 하나만으로도 결론 내릴 수는 없다.

 

정규성 검정 방법

1) QQ plot : 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (1) : QQplot - qqnorm()

2) 히스토그램: 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (2) : 히스토그램 - hist(), dnorm()

3) 통계적 검정

 

본 글에서는 정량적 검정(Shapiro-Wilk, Kolmogorov-Smirnov test)으로 검정하는 방법에 대해 확인해볼 것이다.

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 작업 디렉토리 (Working Directory) 지정 - getwd(), setwd()

setwd("C:/Users/user/Documents/Tistory_blog")

 

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.10)

 

분석용 데이터 (update 22.08.10)

2022년 08월 10일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법

medistat.tistory.com

 

데이터를 불러와 a에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.08 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : CSV - read_csv(), read.csv(), fread()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

 

install.packages("readr")
library("readr")
a<-read_csv("Data.csv")

 

1) Shapiro-Wilk test

a라는 객체에 있는 데이터 중 "ALT"로 Shapiro-Wilk test를 시행할 것이다. 코드는 다음과 같다.

#R 설치 시 기본으로 설치되는 패키지를 사용하므로 별도 설치가 필요 없다.

shapiro.test(a$ALT)

 

결과

	Shapiro-Wilk normality test

data:  a$ALT
W = 0.9982, p-value = 0.3749

 

2) Kolmogorov-Smirnov test

a라는 객체에 있는 데이터 중 "ALT"로 Kolmogorov-Smirnov test를 시행할 것이다. 코드는 다음과 같다.

#R 설치 시 기본으로 설치되는 패키지를 사용하므로 별도 설치가 필요 없다.

ks.test(a$ALT, "pnorm", mean=mean(a$ALT), sd=sd(a$ALT))

결과

	One-sample Kolmogorov-Smirnov test

data:  a$ALT
D = 0.015397, p-value = 0.9717
alternative hypothesis: two-sided

 

해석방법

초급자: p-value>0.05이므로 정규성을 따른다.

 

중급자:

 

귀무 가설과 대립 가설은 다음과 같다.

-귀무 가설: ALT는 정규성을 따른다.

-대립 가설: ALT는 정규성을 따르지 않는다.

 

이때 제 1종 오류는 다음과 같다.

제 1종 오류

=귀무 가설이 참인데도 기각하고 대립 가설을 택함

=ALT는 정규성을 따르는데도 따르지 않는다고 결론 내림

 

p-value는 제 1종 오류를 범할 확률을 의미하므로 다음과 같이 결론내릴 수 있다.

결론: 정규성을 따르는 것이 진실인데, 따르지 않는다고 결론내렸을 확률이 0.05보다 크다.

=정규성을 따르는 것이 진실인데, 따르지 않는다고 결론내린 것은 잘못일 수 있다.

=정규성을 따르지 않는다고는 할 수 없다.

 

고급자:

-(비록 본 데이터는 n수가 충분하지만) n수가 굉장히 적다면 정규성 검정을 잘 통과하므로 결과를 맹신해서는 안 된다.

-본 데이터의 n수는 1,000명으로 2,000명 미만이므로 Shapiro-Wilk test의 결과를 인용한다. (SAS 기준, 2,000명까지는 Shapiro-Wilk test을 계산해주고, Kolmogorov-Smirnov test는 2,000명 이상이 필요하다.)

-또한, QQplot과 히스토그램의 결과도 고려하여 정규성 여부를 판단해야 한다.



정규성 검정은 p-value가 0.05보다 크기를 바라게 되는 몇 안 되는 통계 검정 중 하나다.

많이 쓰이는 통계 분석 중 이런 검정은 세 가지가 있다

1) 정규성 검정 (Normality test): Shapiro-Wilk test, Kolmogorov-Smirnov test

2) Ordinal logistic regression의 proportional odds assumption 검정인 Score test

3) Cox regression의 proportional hazard assumption 검정인 Schoenfeld residual test

 

p-value가 0.05보다 클 때, 이 분석들의 결론은 "정규성을 위반한다고 볼 수는 없었다.", "비례 오즈(위험) 가정을 위반한다고 볼 수는 없었다." 라고 표현하게 된다.

 

R 정규성 검정 (정량적 검정) 정복 완료!

 

작성일: 2022.08.11.

최종 수정일: 2022.08.11.

이용 프로그램: R 4.1.3, RStudio v1.4.1717

운영체제: Windows 10

 

반응형
반응형

[R] 정규성 검정 (2) : 히스토그램 - hist(), dnorm()

 

 많은 통계 분석에서 전제조건으로 데이터의 정규성(normality)을 요구하곤 한다. 검정하는 여러 방법이 다음과 같이 존재하지만, 그중 어떤 하나만으로도 결론 내릴 수는 없다.

 

정규성 검정 방법

1) QQ plot : 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (1) : QQplot - qqnorm()

2) 히스토그램

3) 정량적 검정: 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (3) : 정량적 검정 (Shapiro-Wilk, Kolmogorov-Smirnov) - shapiro.test(), ks.test()

 

본 글에서는 히스토그램으로 검정하는 방법에 대해 확인해볼 것이다.

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 작업 디렉토리 (Working Directory) 지정 - getwd(), setwd()

setwd("C:/Users/user/Documents/Tistory_blog")

 

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.10)

 

분석용 데이터 (update 22.08.10)

2022년 08월 10일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법

medistat.tistory.com

 

데이터를 불러와 a에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.08 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : CSV - read_csv(), read.csv(), fread()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

 

install.packages("readr")
library("readr")
a<-read_csv("Data.csv")

a라는 객체에 있는 데이터 중 "ALT"의 히스토그램을 그려볼 것이다. 코드는 다음과 같다.

#R 설치 시에 자동으로 설치되는 패키지에 있는 함수들이므로 별도의 패키지를 설치할 필요가 없다.

hist(a$ALT, prob=TRUE)
ALTrange<-seq(min(a$ALT),max(a$ALT),length=max(max(a$ALT)-min(a$ALT),100))
ND<-dnorm(ALTrange,mean=mean(a$ALT),sd=sd(a$ALT))
lines(ALTrange, ND, lwd=2)

코드 설명

이해하지 않아도 된다.

모르겠으면, 그저 "a$ALT"을 원하는 변수명으로 바꾸어 코드를 실행하면 된다.

 

(1)hist(a$ALT, prob=TRUE): "a"라는 객체의 "ALT열"에 있는 데이터로 히스토그램을 그리시오.

(2)ALTrange<-seq(min(a$;ALT),max(a$ALT),length=max(max(a$ALT)-min(a$ALT),100)): ALT의 최댓값에서 최솟값을 뺀 값

(3)ALTrange<-seq(min(a$ALT),max(a$ALT),length=max(max(a$ALT)-min(a$ALT),100)): "ALT의 최댓값에서 최솟값을 뺀 값"과 100중 큰 것

(4)ALTrange<-seq(min(a$ALT),max(a$ALT),length=max(max(a$ALT)-min(a$ALT),100)): 등차수열을 만들 건데, 가장 작은 값은 ALT의 최솟값과 같고, 가장 큰 값은 ALT의 최댓값과 같다. 수열에 있는 숫자의 개수(length)는  (3)에서 구한 값

(5)ALTrange<-seq(min(a$ALT),max(a$ALT),length=max(max(a$ALT)-min(a$ALT),100))(4)에서 구한 수열을 ALTrange에 저장한다.

(6)ND<-dnorm(ALTrange,mean=mean(a$ALT),sd=sd(a$ALT)): 평균은 ALT의 평균, 표준편차는 ALT의 표준편차인 정규분포의 확률밀도함수값을 ALTrange 수열 내 각 항에 대해 구한다.
(7)lines(ALTrange, ND, lwd=2): x축에는 ALTrange, y축에는 ND를 넣고 선으로 잇되 선의 굵기는 2로 한다.


 

결과

 

해석방법

히스토그램 막대가 정규분포 곡선 상에 있음: 정규성 따름

히스토그램 막대가 정규분포 곡선 에서 벗어남: 정규성 따르지 않음

 

따라서, "대부분의 히스토그램 막대가 정규분포 곡선 상에 있으므로 정규성을 따른다고 할 수 있다."

 

 

 

R 정규성 검정 (히스토그램) 정복 완료!

 

작성일: 2022.08.11.

최종 수정일: 2022.08.31.

이용 프로그램: R 4.1.3, RStudio v1.4.1717

운영체제: Windows 10

 

반응형
반응형

[R] 정규성 검정 (1) : Q-Q plot - qqnorm(), qqline()

 

 많은 통계 분석에서 전제조건으로 데이터의 정규성(normality)을 요구하곤 한다. 검정하는 여러 방법이 다음과 같이 존재하지만, 그중 어떤 하나만으로도 결론 내릴 수는 없다.

 

정규성 검정 방법

1) Q-Q plot

2) 히스토그램: 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (2) : 히스토그램 - hist(), dnorm()

3) 정량적 검정: 2022.08.11 - [기술 통계/R] - [R] 정규성 검정 (3) : 정량적 검정 (Shapiro-Wilk, Kolmogorov-Smirnov) - shapiro.test(), ks.test()

 

본 글에서는 Q-Q plot으로 검정하는 방법에 대해 확인해볼 것이다.

 

코드를 보여드리기에 앞서 워킹 디렉토리부터 지정하겠다.

워킹 디렉토리에 관한 설명은 다음 링크된 포스트에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 작업 디렉토리 (Working Directory) 지정 - getwd(), setwd()

setwd("C:/Users/user/Documents/Tistory_blog")

 

*실습용 데이터는 아래 링크를 클릭하면 다운로드할 수 있습니다.

2022.08.04 - [공지사항 및 소개] - 분석용 데이터 (update 22.08.10)

 

분석용 데이터 (update 22.08.10)

2022년 08월 10일 버전입니다. 변수는 계속하여 추가될 예정입니다. 다음 카테고리에 있는 글에서 이용된 데이터입니다. - 기술 통계 - 통계 프로그램 사용 방법

medistat.tistory.com

 

데이터를 불러와 a에 객체로 저장하겠다.

데이터 불러오는 방법은 다음 링크에서 볼 수 있다.

2022.08.05 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : EXCEL - read_excel(), read.xlsx()

2022.08.08 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : CSV - read_csv(), read.csv(), fread()

2022.08.10 - [통계 프로그램 사용 방법/R] - [R] 데이터 불러오기 : SAS file (.sas7bdat) - read.sas7bdat(), read_sas()

 

install.packages("readr")
library("readr")
a<-read_csv("Data.csv")

a라는 객체에 있는 데이터 중 "ALT"의 Q-Q plot을 그려볼 것이다. 코드는 다음과 같다.

 

# install.packages("stats") 
	#stats 패키지는 R 설치 시 함께 딸려오므로 설치 필요 없음
# library("stats)

qqnorm(a$ALT)
qqline(a$ALT)

qqnorm(a$ALT): "a"라는 객체의 "ALT열"에 있는 데이터로 Q-Q plot을 그리시오.
qqline(a$ALT): 추세선을 그리시오.

 

결과

해석방법

데이터가 직선상에 있음: 정규성 따름

데이터가 직선에서 벗어나 있음: 정규성 따르지 않음

 

따라서, "대부분의 데이터들이 일직선 상에 있으므로 정규성을 따른다고 할 수 있다."

 

 

 

Q-Q plot 이론은 다음 링크에서 확인할 수 있다.

2022.08.12 - [통계 이론] - [이론] Q-Q Plot (Quantile-Quantile Plot)

 

[이론] Q-Q Plot (Quantile-Quantile Plot)

[이론] Q-Q Plot (Quantile-Quantile Plot) 정규성을 검정할 때 Q-Q Plot을 쓰곤 한다. 그런데 이런 궁금증이 들 수 있다. 왜 Q-Q Plot이 직선에 가까운 것이 정규성을 따른다는 뜻인가? 이에 대해 조목조목..

medistat.tistory.com

 

 

R 정규성 검정 (Q-Q plot) 정복 완료!

 

작성일: 2022.08.11.

최종 수정일: 2022.08.31.

이용 프로그램: R 4.1.3, RStudio v1.4.1717

운영체제: Windows 10

 

반응형

+ Recent posts