R

R - reshape2,cut,히스토그램,상자그림

Positive_Monster 2022. 1. 26. 21:41
더보기

▣ 주요 키워드  

  1. reshape2(melt, dcast)
  2. cut
  3. 히스토그램
  4. 상자그림

★ reshape2

  • melt : 칼럼이 많은 형태(wide) 가로를 세로 방향 긴(long) 형태로 변경하는 함수
install.packages('reshape2')
library(reshape2)
sales <- read.csv('c:/data/fruits_sales.csv',header=T)
sales  #1

reshape2::melt(sales,id='year') #2
- sales데이터프레임에서 year컬럼을 기준으로 삼고 variable컬럼과 value컬럼을 만들어
  variable컬럼에는 year를 제외한 나머지 컬럼들이 들어가고 
  value컬럼에는 그 컬럼에 일치하는 값들이 들어감
reshape2::melt(sales,id='name') #3
reshape2::melt(sales,id=c('year','name')) #4
- sales데이터프레임에서 year,name컬럼을 기준으로 나머지 컬럼들을 variable컬럼에 stack, value에는 일치하는 값들을 stack



  • dcast : long(세로)을 wide(가로)형태로 변경하는 함수
# dcast(원본데이터, 행고정~unstack처리컬럼(컬럼분리),...)
# m -> sales로 바꾸고 싶을 때 dcast함수 사용

m <- reshape2::melt(sales,id=c('year','name')) #1 year,name을 기준으로 나머지 컬럼 variable컬럼을 생성하여 stack,값들은 value컬럼에 stack
str(m) #data.frame형식, 새로운열이 2개 생김
dcast(m,year+name~variable) #2 원래 상태로 복귀
reshape2::dcast(m,year~variable,sum) #3 년도별 수량의합,price의 합 , sum자리에는 그룹함수들
reshape2::dcast(m,name~variable,sum) #4 name별 수량의합,price의 합
#-------------------------
library(dplyr)
sales%>% # = reshape2::dcast(m,year~variable,sum)
  dplyr::group_by(year)%>%
  dplyr::summarise(qty=sum(qty),price=sum(price))
sales%>% # = reshape2::dcast(m,name~variable,sum)
  dplyr::group_by(name)%>%
  dplyr::summarise(qty=sum(qty),price=sum(price))

1
2
3
4

● 예제 경기,부산,인천,대구,세종 지역별로 전입지 이동수를 그래프로 그리기

# 그래프를 그리기 전 data 작업
data <- read.csv('c:/data/전출지_전입지_시도_별_이동자수.csv',header=T) # 데이터 읽어오기
data <- data[-1,-1] # 필요없는 열과 행 제거
names(data)[2:8] <- c(2015:2021) # 이상한 컬럼이름 변경
data

data <- dcast(melt(data,id='전입지별'),variable~전입지별)
# melt사용하여 전입지별 컬럼을 기준으로 나머지 날짜열들을 variable컬럼에 stack ->
#그 후 dcast함수에서 variable~전입지별의 옵션으로 variable을 기준으로 전입지별에 있는 각각의 행들은 각각의 컬럼으로 들어가게 된다.
#기존의 방법과 다르게 dcast를 이용했을 때 데이터프레임으로 만드는 작업을 할 필요가 없음(t함수를 사용하면 data.frame을 수행해야함)
str(data) #수치값들이 chr형으로 되어있기 때문에 변경이 필요함을 확인

data[,-1] <- lapply(data[,-1],as.integer) # rownames를 1열로 바꾸고 1열을 삭제해서  data[,1:길이]하는 방법도 있다.
str(data)
data
# 산점도 그래프 그리기

plot(data$경기도,xlab="",ylab="",ylim=c(0,400000),axes=F,col='violet',type='b')
lines(data$부산광역시, col='blue',type='b')
lines(data$인천광역시, col='red', type='b')
lines(data$대구광역시, col='black', type='b')
lines(data$세종특별자치시, col='green', type='b')
axis(1,at=1:7,label=data$variable,las=2) # x축에 2015 ~ 2021 7개의 데이터로 at옵션에는 1부터 7까지 들어감
axis(2,at=seq(0,400000,by=50000),las=2) # y축은 0부터 40만까지 50000 단위로 구분
abline(v=seq(1,10,1),lty=3,lwd=0.2)
legend('topleft',legend=c('경기도','부산광역시','인천광역시',
                          '대구광역시','세종특별자치시'),
       col=c('violet','blue','red','black','green'),cex=0.5,lty=1,lwd=0.5)

[문제167] 조사된 데이터 값들이 있습니다. 도수분포표를 만드세요.
#도수: 개수라고 보면됨, 
#상대도수 : 전체에서 도수값 나누기
#누적도수 : 도수에 대한 누적값
90 88 78 65 80 94 69 72 83 64 95 68 87 69 82 91 63 70 81 67 

계급                도수    상대도수  누적도수
----------------- -------   --------  --------
  90점이상             4       4/20        4
80점이상~90점미만    6                   10
70점이상~80점미만    3                   13
60점이상~70점미만    7                   20

score <- scan()
# scan()함수 직접값을 입력해서 벡터형으로 변수를 만듬

df <- data.frame(계급=c('90점이상','80점이상~90점미만','70점이상~80점미만','60점이상~70점미만'),
             도수=c(0,0,0,0))
# 데이터프레임 만들기

1) 도수 구하기
for(i in 1:length(score)){
  if(score[i] >=90){
    df[1,2] <- df[1,2] +1 
  }else if(score[i] >=80){
    df[2,2] <- df[2,2] +1 
  }else if(score[i] >=70){
    df[3,2] <- df[3,2] +1 
  }else if(score[i] >=60){
    df[4,2] <- df[4,2] +1 
  }
}
df

2)상대도수
df$상대도수 <- prop.table(df$도수) # = df$도수/sum(df$도수)

3) 누적도수
df$누적도수 <- cumsum(df$도수)
# =
df$누적도수 <- NULL
for(i in 1:NROW(df)){
  if(i==1){
    df$누적도수[i] <- df$도수[i] 
  }else{
    df$누적도수[i] <- df$도수[i] + df$누적도수[i-1] 
  }
  
}
df

[문제168] 조사된 데이터 값들이 있습니다. 도수분포표를 만드세요.
단 기존값(수치형)을 문자(범주형)로 수정한 후 도수를 구하세요.

(예) 90 ->"90점이상",95 -> "90점이상", 88 -> "80점이상~90점미만"

score <- scan()
90 88 78 65 80 94 69 72 83 64 95 68 87 69 82 91 63 70 81 67 

for(i in 1:length(score)){
  if(score[i] >= 90){
    score[i] <- "90점이상" 
  }else if(score[i] >= 80){
    score[i] <- "80점이상~90점미만"
  }else if(score[i] >= 70){
    score[i] <- "70점이상~80점미만"
  }else if(score[i] >= 60){
    score[i] <- "60점이상~70점미만"
  }
}
score
table(score)
s <- data.frame(table(score)) # 결과는 잘 나오나 90점이상부터가 아닌 60점이상 70점 미만부터 출력이 되므로 순서를 바꿔주고 싶다
factor(s,levels = c("90점이상","80점이상~90점미만","70점이상~80점미만","60점이상~70점미만")) #factor함수에 levels옵션으로 원하는 순서대로 출력될 수 있게 순서대로 작성
df <- data.frame(table(factor(s,levels = c("90점이상","80점이상~90점미만","70점이상~80점미만","60점이상~70점미만"))))
names(df) <- c('계급','도수')
df$상대도수 <- prop.table(df$도수) #상대도수 : prop.table(도수값)
df$누적도수 <- cumsum(df$도수) #누적도수 : cumsum(도수값)
df

★cut

- 연속형 변수를 범주형 변수로 변환하는 함수

score <- scan()
90 88 78 65 80 94 69 72 83 64 95 68 87 69 82 91 63 70 81 67 
min(score) # 63
max(score) # 95

table(cut(score,breaks=seq(60,100,by=10), right=FALSE)) 
# breaks옵션 : 60~100까지 10단위로 나눔, 
#right=FALSE : [60,70) 60점이상 ~ 70점 미만 (60 <=점수 < 70)

table(cut(score,breaks=seq(60,100,by=10), right=TRUE))
# right=TRUE : (60,70] 60점초과 ~ 70점이하 (60 < 점수 <= 70)

x <- cut(score,breaks=seq(60,100,by=10), right=FALSE,
    labels = c("60점이상~70점미만","70점이상~80점미만","80점이상~90점미만","90점이상"))
    #보기 불편하게 나온 값들을 원하는 문자열로 바꾸는 labels 옵션
result <- cbind(table(x), prop.table(table(x)),cumsum(table(x)))
class(result)
data.frame(result)

[문제169] cost.txt 데이터를  분석하세요.
91 78 93 57 75 52 99 80 97 62
71 69 72 89 66 75 79 75 72 76
104 74 62 68 97 105 77 65 80 109
85 97 88 68 83 68 71 69 67 74
62 82 98 101 79 105 79 69 62 73

#데이터 읽기 3가지
cost <- read.csv('c:/data/cost.txt',header=F)
cost <- scan() 
cost <- read.table("c:/data/cost.txt") # data.frame으로 읽어들임

#read.table사용할 때
str(cost) #각 컬럼에 값들이 데이터프레임형식으로 들어가 있음
dim(cost) # 5행10열을 하나의 행으로 바꿔야함 
cost <- as.matrix(cost) # 먼저 matrix형으로 바꾸어줌
dim(cost) <- c(50,1) # dim(cost)의 행에 50, 열을1로 변형

cost_cut <- cut(cost,breaks=seq(50,110,by=10),right=FALSE,
    labels=c('50이상~60미만','60이상~70미만','70이상~80미만','80이상~90미만','90이상~100미만','100이상'))
cost_result <- data.frame(cbind(table(cost_cut),prop.table(table(cost_cut))))
names(cost_result) <- c('도수','상대도수')
cost_result$누적도수 <- cumsum(cost_result$도수)
cost_result


★ 히스토그램(histogram)

  • 연속형 자료가 모여 있는 위치나 자료의 분포에 관한 대략적인 정보를 파악할 수 있는 그래프
  • 단점은 구체적인 수치정보를 알 수 없다.
cost
hist(cost) #히스토그램
hist(cost,breaks = seq(50,110,by=10),right=FALSE,col=brewer.pal(7,'RdBu'),
     ylim=c(0,20),labels=TRUE)
     #hist(데이터,breaks= 값의 범위, right=F(이상~미만,T:초과~이하),col=색,ylim=y축눈금,labels=T(막대 위에 데이터 값표시))

★ 상자그림(box plot)

  • 최솟값, 제1사분위수, 중앙값(굵은 검은 줄), 제3사분위수, 최댓값 다섯 가지의 요약 수치 등을 파악할 수 있는 그래프 
  • 이 상치 데이터를 확인할 수 있다.
boxplot(1:10, main='1')
boxplot(c(1:10,20),main='2') #이상치 데이터 20 확인
boxplot(cost, main='3')
boxplot(cost,horizontal=T, main='4')

▶중앙값(median) # 평균이랑 다름

(1) 관측값을 크기순으로 정렬(오름차순)
(2) 관측값의 개수(n) 홀수면 (n+1)/2 번째 관측값
    -(예) 1 2 3 4 5 6 7 8 9 
    n=9  (9+1)/2 = 5 , 5번째 위치값을 리턴
(3) 관측값의 개수(n) 짝수면 n/2 번째 관측값과, (n/2)+1 번째 관측값의 평균
    -(예) 1 2 3 4 5 6 7 8 9 10
    n=10 10/2 = 5, 5번째 위치값
         (10/2)+1 = 6, 6번째 위치값
         (5+6)/2 = 5.5 중앙값
         
 costs <- sort(cost)
(costs[25] + costs[26])/2
median(cost)

▶ 사분위수(quartile)

Q1 : 1사분위 Q2(중앙값)보다 작은 데이터의 중앙값,25%
    -(예) 1 2 (3 Q1) 4 5 (5.5 중앙값) 6 7 8 9 10

Q2(중앙값)
  50% Q2 50%
    
Q3 : 3사분위 Q2(중앙값)보다 큰 데이터의 중앙값,75%
  -(예) 1 2 3 4 5 (5.5 중앙값) 6 7 (8 Q3) 9 10
  
quantile(1:10) # 4분위수 출력
quantile(1:10,type=7) # type=7 기본값
quantile(1:10,type=2) # 보통 중앙값구할 때는 type=2
summary(1:10) # 최소값, 1사분위수, 중앙값, 평균, 3사분위수, 최대값

boxplot(c(1:10,20),horizontal=T)  # horizontal=T는 가로로 boxplot을 출력
min(c(1:10,20))
max(c(1:10,20)) 

● 사분위수범위( Inter Quartile Range)
IQR = Q3-Q1
iqr = 8 - 3  #위의 boxplot의 Q1은 3, Q3는 8, 계산한 값은 사분위수범위(IQR)

#가상의 경계선
upper fence : Q3 + 1.5*IQR
8(Q3) + 1.5 * 5(iqr) = 15.5

lower fence : Q1 - 1.5*IQR
3 - 1.5*5 = -4.5

lower fence(-4.5) ~ upper fence(15.5) 의 기준으로 데이터의 최소값, 최대값을 찾아 baxplot을 만들고
범위에 속하지 않는 데이터는 이상치가 된다.

boxplot.stats(c(1:10,20,-10)) # 4분위수, 개수,중앙값의95%신뢰구간 ,최대값 최소값
boxplot.stats(c(1:10)) #boxplot의 값들을 보는 함수

#exam변수에 파일을 읽어오고 각 과목의 grade값들을 각각 sql,r,python변수에 저장, boxplot그래프로 시각화

exam <- read.csv('c:/data/exam.csv', header=T)
exam              
sql <-exam[exam$subject == 'SQL','grade']
r <-exam[exam$subject == 'R','grade']
python <-exam[exam$subject == 'PYTHON','grade']

boxplot(sql,r,python,names = c('SQL','R','PYTHON'))

[문제170] store.csv 파일에 있는 데이터를 분석하세요 (배달시간)
store <- read.csv('c:/data/store.csv',header=T)
> store
    A  B  C
1  20  5  5
2  21  6  5
3  23 11  5
4  22 15 12
5  26 13 10
6  28 20 11
7  35 16 20
8  35 20 20
9  41 21 20
10 42 23 20
11 43 22 20
12 45 27 21
13 44 27 20
14 45 30 30
15 46 30 32
16 47 32 31
17 47 36 31
18 46 37 31
19 58 37 36
20 58 40 40
21 59 40 40
22 60 43 51
23 56 44 61
24 57 45 61
25 57 51 51
26 80 54 61
27 47 70 70

par(mfrow=c(2,2))
hist(store$A,main='A배달', xlab = '분',ylab='건수')
hist(store$B,main='B배달', xlab = '분',ylab='건수')
hist(store$C,main='C배달', xlab = '분',ylab='건수')

boxplot(store$A, store$B, store$C, names=c('A','B','C'))
#히스토그램 시각화보다 boxplot이 더 보기 좋은 데이터이다.
#y축을 배달 시간이라고 하면 A의 배달시간이 평균적으로 오래걸리는 것을 알 수 있고 B와 C는 
똑같다는 것을 알 수 있다. 

quantile(store$A)
quantile(store$B)
quantile(store$C)
# 사분위수도 B,C는 같다

mean(store$B)
mean(store$C)
# 평균도 같다

var(store$B)
var(store$C)
#하지만 값이 퍼져있는 분포의 차이를 확인하기 위해 분산값을 보면 c보다 b가 퍼져있는 정도가 작다는 것을 알 수 있다.

sd(store$B)
sd(store$C)
# 편차가 크면 퍼져있는 정도가 크다는 것이기 때문에 표준편차가 작은 B를 이용하는게 효과적이라는 것을 알 수 있다.

'R' 카테고리의 다른 글

R - wordcloud, grep, 정규표현식,stringr  (0) 2022.02.06
R barplot, 산점도  (0) 2022.01.25
R dplyr, sqldf함수  (0) 2022.01.21
R dplyr, rank 함수  (0) 2022.01.20
R subset,ddply 함수  (0) 2022.01.19