모던지 / 데이터분석 준전문가 / 데이터분석 2강. R로 데이터 다루기

데이터분석 2강. R로 데이터 다루기

R에서 NA가 하나라도 섞이면 평균도 NA가 됩니다. 빈 값을 어떻게 다룰지 정하지 않으면 계산이 시작조차 되지 않습니다.

풀고 시작

문제 1. R에서 mean(c(1, NA, 3))의 결과는 무엇입니까?
결측값 NA가 하나라도 섞이면 R은 평균을 알 수 없다고 보고 NA를 돌려줍니다. NA를 빼고 계산하려면 na.rm = TRUE를 줘야 하며, 그러면 1과 3의 평균인 2가 나옵니다.

원소 고르기

1강에서 담는 법을 봤다면 이번에는 꺼내는 법입니다. 대괄호 안에 무엇을 넣느냐에 따라 고르는 방식이 네 가지로 갈립니다.

x <- c(10, 20, 30, 40)
x[c(1, 3)]      # 10 30   순번으로 고릅니다
x[-2]           # 10 30 40   음수는 그 자리를 뺍니다
x[x > 20]       # 30 40   조건이 참인 것만 남깁니다
which(x > 20)   # 3 4   조건이 참인 자리의 순번을 돌려줍니다

음수 인덱스가 "뒤에서 두 번째"가 아니라 "두 번째를 빼라"는 뜻이라는 점이 파이썬과 가장 다릅니다. 조건으로 고르는 논리 인덱싱은 분석에서 가장 많이 쓰는 방식입니다. 논리값을 더하면 TRUE가 1로 세어지므로 sum(x > 20)은 조건을 만족하는 원소의 개수가 됩니다.

데이터프레임은 대괄호 안에 쉼표를 두고 행, 열 순서로 적습니다. 한쪽을 비워 두면 그 방향은 전부 가져옵니다.

df[1, ]                  # 첫째 행 전체
df[, "score"]            # score 열 전체
df[df$score >= 90, ]     # 점수가 90 이상인 행만
subset(df, score >= 90)  # 같은 결과를 함수로

수열 만들기

규칙 있는 벡터는 직접 치지 않고 만들어 씁니다.

표현 결과
seq(1, 10, by = 2) 1 3 5 7 9
seq(0, 1, length.out = 5) 0.00 0.25 0.50 0.75 1.00
rep(1:2, times = 3) 1 2 1 2 1 2
rep(1:2, each = 2) 1 1 2 2

times는 묶음째 되풀이하고 each는 원소마다 되풀이합니다. 정렬도 두 가지를 구분해야 합니다. sort(c(3, 1, 2))는 값을 정렬한 1 2 3을 돌려주지만, order(c(3, 1, 2))는 정렬했을 때 몇 번째 원소가 오는지를 알려 주는 2 3 1을 돌려줍니다. 데이터프레임을 정렬할 때는 df[order(df$score), ]처럼 order를 씁니다.

빈 값의 네 얼굴

R에는 "값이 없다"를 나타내는 것이 넷 있습니다. 시험은 이 넷을 섞어 놓고 가려내게 합니다.

표기 뜻 생기는 곳
NA 값이 있어야 하는데 모릅니다(결측) 설문 무응답, 누락된 기록
NULL 아예 아무것도 없습니다 비어 있는 객체, 길이가 0
NaN 숫자가 아닙니다(Not a Number) 0/0
Inf 무한대입니다 1/0

NA는 자리를 차지합니다. length(c(1, NA))는 2입니다. NULL은 자리를 차지하지 않아 c(1, NULL, 3)은 그냥 1 3이 됩니다. NA와 계산하면 결과도 NA이고, 심지어 NA == NA도 TRUE가 아니라 NA입니다. 모르는 값 둘이 같은지는 알 수 없기 때문이죠. 그래서 결측값을 찾을 때는 is.na()를 씁니다. mean, sum, sd 같은 함수에는 na.rm = TRUE를 주면 NA를 빼고 계산합니다.

함수로 한꺼번에 계산하기

행렬이나 데이터프레임의 행 또는 열마다 같은 계산을 할 때는 반복문 대신 apply 계열 함수를 씁니다.

m <- matrix(1:6, nrow = 2)
apply(m, 1, sum)   # 9 12      둘째 인자 1은 행마다
apply(m, 2, sum)   # 3 7 11    둘째 인자 2는 열마다
tapply(c(10, 20, 30, 40), c("a", "b", "a", "b"), mean)   # a 20, b 30

lapply는 결과를 리스트로 돌려주고, sapply는 가능하면 벡터로 단순화해 돌려줍니다. tapply는 두 번째 인자로 준 그룹마다 함수를 적용합니다. 벡터에 조건을 한꺼번에 거는 ifelse(x > 0, "양수", "그외")도 자주 씁니다. 직접 함수를 만들 때는 f <- function(x) x^2처럼 쓰고, 함수는 마지막에 계산한 값을 돌려줍니다. 파일은 read.csv로 읽고, head로 앞의 여섯 행을, summary로 최솟값, 사분위수, 중앙값, 평균, 최댓값을 한눈에 봅니다.

인출 문제

문제 1. x <- c(10, 20, 30, 40)일 때 x[-2]의 결과는 무엇입니까?
R에서 음수 인덱스는 그 자리의 원소를 빼라는 뜻이라 두 번째 원소 20을 뺀 10 30 40이 나옵니다. 파이썬처럼 뒤에서 세는 뜻이 아니라는 점이 핵심입니다.
문제 2. rep(1:2, each = 2)의 결과는 무엇입니까?
each는 원소마다 되풀이하므로 1을 두 번, 2를 두 번 적어 1 1 2 2가 됩니다. 묶음째 되풀이하는 times = 2였다면 1 2 1 2가 되었을 것입니다.
문제 3. NA와 NULL의 차이로 가장 적절한 것은?
length(c(1, NA))는 2이지만 c(1, NULL, 3)은 1 3이 되어, NA는 자리를 지키고 NULL은 사라집니다. 0/0으로 생기는 것은 NaN입니다.
문제 4. apply(m, 2, sum)이 하는 일로 옳은 것은?
apply의 둘째 인자가 1이면 행마다, 2이면 열마다 함수를 적용합니다. 그래서 apply(m, 2, sum)은 열의 합을 돌려줍니다.

더 풀기

출제기준의 세부항목을 따라 이 강의 범위에서 새로 낸 문제입니다. 모의고사도 여기에서 뽑습니다.

묶음 1

문제 1. x <- c(10, 20, 30, 40)일 때 x[x > 20]의 결과는 무엇입니까?
조건이 참인 원소만 남기는 논리 인덱싱이라 값 30과 40이 나옵니다. 3 4는 which(x > 20)이 돌려주는 순번이고, 논리값 넷은 x > 20만 계산했을 때의 결과입니다.
문제 2. x <- c(10, 20, 30, 40)일 때 which(x > 20)의 결과는 무엇입니까?
which는 조건이 참인 자리의 순번을 돌려줍니다. 30과 40은 세 번째와 네 번째 자리에 있으므로 3 4입니다.
문제 3. x <- c(10, 20, 30, 40)일 때 sum(x > 20)의 결과는 무엇입니까?
x > 20은 FALSE FALSE TRUE TRUE이고, 논리값을 더하면 TRUE가 1로 세어지므로 합은 2입니다. 조건을 만족하는 원소의 개수를 셀 때 쓰는 방식입니다.
문제 4. x <- c(10, 20, 30, 40)일 때 x[c(1, 3)]의 결과는 무엇입니까?
순번 1과 3의 원소를 고르므로 10과 30이 나옵니다. 1 3은 고른 자리의 번호일 뿐 결과가 아닙니다.
문제 5. x <- c(10, 20, 30, 40)일 때 x[c(TRUE, FALSE)]의 결과는 무엇입니까?
짧은 논리 벡터가 되풀이되어 TRUE FALSE TRUE FALSE로 맞춰지므로 첫째와 셋째 원소인 10과 30이 남습니다. 1강의 재사용 규칙이 인덱싱에도 똑같이 적용됩니다.
문제 6. seq(1, 10, by = 2)의 결과는 무엇입니까?
1에서 시작해 2씩 늘리되 10을 넘지 않는 데까지 가므로 1 3 5 7 9입니다. 11은 끝값 10을 넘으므로 들어가지 않습니다.
문제 7. seq(0, 1, length.out = 5)의 결과는 무엇입니까?
length.out은 원소의 개수를 정하므로 0부터 1까지를 같은 간격으로 나눠 다섯 개를 만듭니다. 간격이 0.25라 0 0.25 0.5 0.75 1이 됩니다.
문제 8. rep(1:2, times = 3)의 결과는 무엇입니까?
times는 벡터를 묶음째 되풀이하므로 1 2를 세 번 이어 붙여 1 2 1 2 1 2가 됩니다. 원소마다 되풀이하는 each = 3이었다면 1 1 1 2 2 2가 되었을 것입니다.
문제 9. sort(c(3, 1, 2))와 order(c(3, 1, 2))의 결과를 차례로 옳게 짝지은 것은?
sort는 값을 정렬해 1 2 3을 돌려주고, order는 정렬했을 때 몇 번째 원소가 오는지를 알려 줍니다. 가장 작은 1이 둘째, 다음 2가 셋째, 3이 첫째에 있으니 order는 2 3 1입니다.
문제 10. 데이터프레임 df를 score 열 기준으로 오름차순 정렬하는 표현으로 가장 알맞은 것은?
order가 정렬된 순서의 행 번호를 돌려주므로 그것을 행 자리에 넣으면 표 전체가 점수순으로 정렬됩니다. sort는 값 자체를 돌려줘 행 번호로 쓸 수 없습니다.

묶음 2

문제 1. 데이터프레임 df에서 첫째 행 전체를 꺼내는 표현은 무엇입니까?
데이터프레임은 대괄호 안에 행, 열 순서로 적고 비운 쪽은 전부 가져옵니다. 그래서 df[1, ]은 첫째 행 전체이고, df[, 1]은 첫째 열 전체입니다.
문제 2. 데이터프레임 df에서 score가 90 이상인 행만 고르는 표현으로 가장 알맞은 것은?
조건을 행 자리에 넣고 쉼표 뒤를 비워야 조건을 만족하는 행의 모든 열이 나옵니다. 마지막 보기는 행을 고르지 않고 논리값 벡터만 돌려줍니다.
문제 3. subset(df, score >= 90)과 같은 결과를 내는 표현은 무엇입니까?
subset은 조건을 만족하는 행을 골라 주는 함수라 논리 인덱싱으로 행을 고른 것과 같습니다. which는 행의 순번만 돌려줄 뿐 표를 돌려주지 않습니다.
문제 4. R에서 0/0의 결과는 무엇입니까?
0을 0으로 나누면 숫자로 정할 수 없어 NaN(Not a Number)이 됩니다. 0이 아닌 수를 0으로 나누면 무한대인 Inf가 됩니다.
문제 5. R에서 1/0의 결과는 무엇입니까?
R은 0이 아닌 수를 0으로 나누면 오류 대신 무한대 Inf를 돌려줍니다. 0/0일 때만 NaN이 됩니다.
문제 6. R에서 NA == NA의 결과는 무엇입니까?
NA는 모르는 값이라 모르는 값 둘이 같은지도 알 수 없어 결과가 NA입니다. 그래서 결측값을 찾을 때는 비교 연산 대신 is.na()를 씁니다.
문제 7. 벡터 x에 결측값이 있는지 원소마다 확인하는 함수는 무엇입니까?
is.na는 원소마다 결측값이면 TRUE를 돌려줍니다. x == NA는 모든 결과가 NA가 되어 쓸모가 없고, is.null은 객체 전체가 NULL인지를 봅니다.
문제 8. c(1, NULL, 3)의 결과는 무엇입니까?
NULL은 아예 없는 것이라 벡터 안에서 자리를 차지하지 않고 사라집니다. 자리를 지키는 결측값은 NA입니다.
문제 9. length(c(1, NA, 3))의 결과는 무엇입니까?
NA는 모르는 값이지만 자리를 차지하므로 원소는 세 개입니다. NULL이었다면 자리를 차지하지 않아 길이가 2였을 것입니다.
문제 10. sum(c(1, NA, 3), na.rm = TRUE)의 결과는 무엇입니까?
na.rm = TRUE를 주면 NA를 빼고 계산하므로 1과 3을 더한 4가 나옵니다. 이 옵션이 없으면 NA가 하나라도 있어 결과가 NA입니다.

묶음 3

문제 1. m <- matrix(1:6, nrow = 2)일 때 apply(m, 1, sum)의 결과는 무엇입니까?
행렬은 열 방향으로 채워져 첫째 행이 1 3 5, 둘째 행이 2 4 6입니다. 둘째 인자 1은 행마다 계산하라는 뜻이라 9와 12가 나옵니다.
문제 2. m <- matrix(1:6, nrow = 2)일 때 apply(m, 2, sum)의 결과는 무엇입니까?
둘째 인자 2는 열마다 계산하라는 뜻이고 열은 1 2, 3 4, 5 6이므로 합은 3, 7, 11입니다.
문제 3. lapply와 sapply의 차이로 가장 적절한 것은?
두 함수 모두 원소마다 함수를 적용하지만 lapply는 리스트를, sapply는 되도록 단순한 벡터나 행렬을 돌려줍니다. 이름의 s가 단순화(simplify)를 가리킵니다.
문제 4. tapply(c(10, 20, 30, 40), c("a", "b", "a", "b"), mean)의 결과는 무엇입니까?
tapply는 둘째 인자의 그룹마다 함수를 적용합니다. a 그룹은 10과 30이라 평균 20, b 그룹은 20과 40이라 평균 30입니다. 40과 60은 평균이 아니라 합입니다.
문제 5. ifelse(c(1, -2, 3) > 0, "양", "음")의 결과는 무엇입니까?
ifelse는 벡터의 원소마다 조건을 검사해 참이면 둘째 인자를, 거짓이면 셋째 인자를 고릅니다. 1과 3은 양수, 가운데 값은 음수입니다.
문제 6. f <- function(x) x^2를 정의한 뒤 f(3)을 실행한 결과는 무엇입니까?
R의 함수는 따로 return을 적지 않아도 마지막에 계산한 값을 돌려줍니다. 3의 제곱이라 9입니다.
문제 7. 데이터프레임의 앞부분을 기본 설정으로 보여 주는 head(df)는 몇 개의 행을 보여 줍니까?
head와 tail은 따로 개수를 정하지 않으면 여섯 행을 보여 줍니다. 다른 개수는 head(df, 10)처럼 둘째 인자로 정합니다.
문제 8. 숫자 열에 summary를 적용했을 때 보여 주지 않는 값은 무엇입니까?
숫자 열의 summary는 최솟값, 1사분위수, 중앙값, 평균, 3사분위수, 최댓값 여섯 개를 보여 주며, 결측값이 있으면 그 개수도 붙입니다. 표준편차는 sd로 따로 구해야 합니다.
문제 9. CSV 파일을 데이터프레임으로 읽어 들이는 함수로 가장 알맞은 것은?
read.csv는 쉼표로 구분된 파일을 읽어 데이터프레임으로 돌려줍니다. write.csv는 거꾸로 파일로 저장하고, summary와 str은 이미 읽은 데이터를 요약합니다.
문제 10. R로 데이터 다루기에 관한 진술로 옳지 않은 것은?
NULL은 아예 없는 것이라 벡터 안에서 자리를 차지하지 않고 사라집니다. 자리를 차지하는 결측값은 NA입니다. 나머지 셋은 옳은 진술입니다.

이전: 1강 R의 자료 구조 · 다음: 3강 데이터 마트

모던지 · 궁금하면 모던지 GitHub · 2026-09-30