ADsP R기초

본 토픽은 현재 준비중입니다. 공동공부에 참여하시면 완성 되었을 때 알려드립니다.

데이터 프레임 합치기 쪼개기

데이터 분석을 하다보면 데이터 프레임을 쪼개거나 합쳐야 할때가 종종 있습니다.

데이터 불러오기

다음 데이터는 한국관광공사에서 실시한 2018 외래관광객 실태조사에서 가져왔습니다. 코드를 그대로 복사해서 실행하면 됩니다. read.csv()가 어떤 함수인지는 나중에 데이터 입출력에서 배우겠습니다.

한국을 방문하는 외국인 관광객에 대한 데이터가 두 개 있습니다. 하나는 나라별로 몇 명이 방문하는지 적혀 있습니다. 다른 하나는 나라별로 평균 신용카드 사용 금액이 적혀 있습니다. 이 둘을 합치고 더 나아가 두 데이터를 곱해서 나라별로 '총 지출액'을 계산할 수도 있으면 매우 좋을 겁니다.

> expense <- read.csv("https://raw.githubusercontent.com/twinstae/ADsP/master/2018%20%EA%B5%AD%EA%B0%80%EB%B3%84%20%ED%8F%89%EA%B7%A0%20%EC%8B%A0%EC%9A%A9%EC%B9%B4%EB%93%9C%20%EC%A7%80%EC%B6%9C%EC%95%A1%20-%20%EC%8B%9C%ED%8A%B81.csv", header = T, fileEncoding = "UTF-8")
> head(expense)
        국가. 평균.지출액
1       일 본      791.07
2       중 국     1887.43
3       홍 콩     1126.12
4 싱 가 포 르     1280.33
5       대 만     1102.77
6       태 국     1146.79
> visitor <- read.csv("https://raw.githubusercontent.com/twinstae/ADsP/master/2018%20%EA%B5%AD%EA%B0%80%EB%B3%84%20%ED%95%9C%EA%B5%AD%20%EB%B0%A9%EB%AC%B8%EA%B0%9D%20%ED%86%B5%EA%B3%84%20-%20%EC%8B%9C%ED%8A%B81.csv", header = T, fileEncoding = "UTF-8")
> head(visitor)
         국가 사례수 비율.
1       일 본   1902  11.5
2       중 국   2749  16.7
3       홍 콩   1016   6.2
4 싱 가 포 르    581   3.5
5       대 만   1206   7.3
6       태 국    850   5.2

데이터 합치기 rbind(), cbind(), merge()

이제 이 두 데이터 프레임을 합쳐야 합니다. 데이터 프레임을 합칠 때에는 보통 3가지 명령어를 사용합니다. rbind(), cbind(), merge()입니다.

rbind()에서 r은 Row(행)의 약자입니다. 데이터 프레임에 새로운 행을 추가해줍니다. 그러니 cbind에서 c는 반대로coloum(열)의 약자라는 걸 쉽게 알 수 있습니다.

예를 들어 간단한 데이터를 예로 들어서 rbind()와 cbind()를 사용해보겠습니다.

> d <- data.frame(c(1,4),c(2,5))
> d
  c.1..4. c.2..5.
1       1       2
2       4       5

> d2 <- rbind(d, c(7,8))
> d2
  c.1..4. c.2..5.
1       1       2
2       4       5
3       7       8

> d3 <- cbind(d2, c(3,6,9))
> d3
  c.1..4. c.2..5. c(3, 6, 9)
1       1       2          3
2       4       5          6
3       7       8          9

하지만 우리 관광객 데이터에 cbind를 쓰려 하면 다음과 같이 에러가 뜹니다.

> head(cbind(visitor,expense[]))
Error in data.frame(..., check.names = FALSE) : 
  arguments imply differing number of rows: 19, 21

왜냐하면 두 데이터는 rows(행)의 숫자가 다르기 때문입니다. 신용카드 지출액 데이터에는 21개 국가가 포함되어 있는데, 방문객 데이터에는 18개 나라 밖에 없습니다. (19행 중에 1행은 총 사례수 입니다.) 아마 설문지를 다양한 언어로 만드는데 한계가 있었던 모양입니다.

이렇게 행의 숫자가 다를 때 유용하게 쓸 수 있는 게 merge()입니다. merge()는 두 데이터 프레임에 공통되는 행을 기준으로 묶어줍니다.

#by 매개변수를 써서 공통되는 '국가' 행을 기준으로 해서 묶습니다.
> visitor_expense <-merge(visitor,expense, by = "국가")
> visitor_expense
             국가 사례수 비율. 평균지출액
1           대 만   1206   7.3    1102.77
2           독 일    397   2.4    1247.91
3        러 시 아    587   3.6    1348.67
4  말 레 이 시 아    675   4.1    1035.93
5           미 국   1135   6.9    1190.03
6     싱 가 포 르    581   3.5    1280.33
7           영 국    434   2.6    1158.68
8           인 도    347   2.1    1548.15
9  인 도 네 시 아    524   3.2    1126.54
10          일 본   1902  11.5     791.07
11          중 국   2749  16.7    1887.43
12          중 동    560   3.4    1776.64
13       캐 나 다    513   3.1    1006.56
14          태 국    850   5.2    1146.79
15       프 랑 스    384   2.3    1172.54
16       필 리 핀    631   3.8     965.40
17          호 주    476   2.9    1048.72
18          홍 콩   1016   6.2    1126.12

이런 식으로 공통되는 18개 국가를 기준으로 묶었습니다.

국가별 평균 지출액 비율을 구하려면 이제 비율.과 평균 지출액을 곱해서 열로 넣어주면 됩니다. 이 역시 새로운 열을 추가하는 한 방법입니다.

> visitor_expense["국가별지출액비율"] <- visitor_expense["비율."]*visitor_expense["평균지출액"]
> head(visitor_expense)
            국가 사례수 비율. 평균지출액 국가별지출액비율
1          대 만   1206   7.3    1102.77           8050.221
2          독 일    397   2.4    1247.91           2994.984
3       러 시 아    587   3.6    1348.67           4855.212
4 말 레 이 시 아    675   4.1    1035.93           4247.313
5          미 국   1135   6.9    1190.03           8211.207
6    싱 가 포 르    581   3.5    1280.33           4481.155

기출 연습 문제

다음은 ADsP시험 접수자 명단과, 합격 여부를 담은 2개의 데이터 프레임이다.

다음 두 데이터를 합칠 때 어떻게 프로그래밍해야 하는가?

(단 중복되는 데이터는 정확하게 구분해야 한다.)

> id <- c(1,2,3,4,5,6)
> name <- c("김태희", "이지우", "남궁민수", "강유원", "박수철", "김태희")
> pass <- c(TRUE, FALSE, TRUE, FALSE, FALSE, FALSE)
> a <- data.frame(id, name)
> b <- data.frame(id, pass)
> a
  id     name
1  1   김태희
2  2   이지우
3  3 남궁민수
4  4   강유원
5  5   박수철
6  6   김태희
> b
  id  pass
1  1  TRUE
2  2 FALSE
3  3  TRUE
4  4 FALSE
5  5 FALSE
6  6 FALSE

1. merge(a,b,by="name")

2. cbind(a,b,by="id") 

3. rbind(a,b)

4. merge(a,b,by="id")

5. cbind(a,b)

데이터 쪼개기 grep()색인, subset(), split()

반대로 데이터가 쪼개서 보고 싶을 때도 있습니다. 예를 들어 국가별 지출액 비율 데이터를 국가별로 쪼개고 싶을 수 있을 겁니다. 일단 간단하게 색인을 쓰면 편합니다. grep(String, df$column_name)함수를 쓰면 지정한 열에서 원하는 값을 가진 행의 위치를 알 수 있습니다.

>grep('미 국', visitor_expense$국가)
[1] 5
> USA_visitor_expense <- visitor_expense[grep('미 국', visitor_expense$국가),]
> USA_visitor_expense
   국가 사례수 비율. 평균지출액 국가별지출액비율
5 미 국   1135   6.9    1190.03           8211.207

이게 복잡해보인다면 subset() 함수를 쓸 수도 있습니다. subset()함수는 조건에 맞는 행(row)만 뽑아내줍니다.

> subset(visitor_expense, 국가 == "미 국")
   국가 사례수 비율. 평균지출액 국가별지출액비율
1 미 국   1135   6.9    1190.03           8211.207

조건에 맞는 행이 여러 개 이면, 여러 행을 한 번에 뽑아낼 수도 있습니다.

> subset(visitor_expense, 국가별지출액비율 > 7000)
    국가 사례수 비율. 평균지출액 국가별지출액비율
1  대 만   1206   7.3    1102.77         8050.221
5  미 국   1135   6.9    1190.03         8211.207
10 일 본   1902  11.5     791.07         9097.305
11 중 국   2749  16.7    1887.43        31520.081

하지만 정말 18개의 국가를 한 번에 다 쪼개버리고 싶을 때에는 split()함수를 씁니다. 그러면 각 국가별로 쪼개진 데이터가 벡터와 비슷한 리스트로 저장됩니다.

> visitor_expense_bycountry <- split(visitor_expense, visitor_expense$국가)
> head(visitor_expense_bycountry)
$`대 만`
   국가 사례수 비율. 평균지출액 국가별지출액비율
1 대 만   1206   7.3    1102.77           8050.221

$`독 일`
   국가 사례수 비율. 평균지출액 국가별지출액비율
2 독 일    397   2.4    1247.91           2994.984

$`러 시 아`
      국가 사례수 비율. 평균지출액 국가별지출액비율
3 러 시 아    587   3.6    1348.67           4855.212

$`말 레 이 시 아`
            국가 사례수 비율. 평균지출액 국가별지출액비율
4 말 레 이 시 아    675   4.1    1035.93           4247.313

$`미 국`
   국가 사례수 비율. 평균지출액 국가별지출액비율
5 미 국   1135   6.9    1190.03           8211.207

$`싱 가 포 르`
         국가 사례수 비율. 평균지출액 국가별지출액비율
6 싱 가 포 르    581   3.5    1280.33           4481.155

이제는 grep을 쓰지 않고 간단하게 $색인을 써서 국가별 데이터를 불러올 수 있습니다.

> visitor_expense_bycountry$'영 국'
   국가 사례수 비율. 평균지출액 국가별지출액비율
7 영 국    434   2.6    1158.68           3012.568

기출 연습 문제

Cars93 데이터 프레임에서 MPG.city(국도에서 연비) 변수를 제조사(Manufacturer) 별로 쪼개려 한다. R프로그램으로 적절한 것은?

1. subset(Cars93, Manufacturer )

2. split(Cars93, "Mamufacturer")

3. split(Cars93$MPG.city, Cars93$Manufacturer)

4. split(Cars93$MPG.city, by = "Manufacturer")

어마어마하게 긴 데이터

또 데이터가 어마어마하게 커서 중요한 부분만 쪼개서 보고 싶을 때도 있습니다.

*주의* : 절대 다음 데이터를 그냥 열면 안 됩니다. head를 써도 엄청난 양이 나옵니다.

#국가별로 선호하는 관광지에 대한 데이터입니다.
> attraction <- read.csv("https://raw.githubusercontent.com/twinstae/ADsP/master/2018%20%EA%B5%AD%EA%B0%80%EB%B3%84%20%EC%84%A0%ED%98%B8%20%EA%B4%80%EA%B4%91%EC%A7%80%20-%20%EC%8B%9C%ED%8A%B81.csv", header = T, fileEncoding = "UTF-8")

#색인을 써서 5개 행 5개 열만 불러왔습니다.
> attraction[1:5,1:5]
         국가 사례수 명동..남대문..북창 X.제주. 신촌..홍대주변
1       일 본   3358               34.4     2.3            8.3
2       중 국   5447               48.8    12.2            4.1
3       홍 콩    789               35.3     5.4           11.0
4 싱 가 포 르    251               27.3     8.8            7.4
5       대 만   1286               31.4     2.9            7.7
6       태 국    588               28.9     5.8           12.1
dim() 함수를 쓰면 데이터 프레임의 모양, 다시 말해 행과 열의 개수를 알 수 있습니다.
> dim(attraction)
[1]  21 263

무려 263개의 관광지 별로 데이터가 있습니다! 주관식 설문에서 이런 결과가 자주 나옵니다. 사람들이 뭘 적을지는 천차만별이기 때문이죠. 그러면 이 복잡한 데이터를 어떻게 할까요?

가장 간단한 방법은 앞에서 본 것처럼 색인을 써서 가장 중요한 5~15개 행만 남기는 겁니다. 물론 다른 방법도 있지만, 일단은 이런 게 있다는 정도만 알아보고 넘어가겠습니다.

댓글

댓글 본문
작성자
비밀번호
  1. Taehee Kim
    맞습니다. visitor와 expense를 합쳐야 본문에 나온 결과가 나오겠죠. 수정했습니다. 제보 감사합니다.
    대화보기
    • student
      subset(visitor, 국가 == "미 국") 이 부분은 subset(visitor_expense, 국가 == "미 국")로 변경해야

      국가 사례수 비율. 평균지출액 국가별 지출액 비율
      1 미 국 1135 6.9 1190.03 8211.207

      이렇게 결과가 나옵니다.

      원래 본문대로 하면
      국가 사례수 비율.
      9 미 국 1135 6.9
      이렇게만 나오네요.
    버전 관리
    Taehee Kim
    현재 버전
    선택 버전
    graphittie 자세히 보기