지난 포스트에선 데이터프레임의 생성과 데이터프레임의 정보를 파악하는 법에 대하여 공부해보았다.
이번 포스트에선 데이터프레임에서 새로운 컬럼을 생성하는 방법과 데이터 프레임에 접근하는 법에 대해 공부해보도록 하자.
데이터 프레임 접근
데이터 프레임은 색인과 행과 열의 이름을 통해서 접근할 수 있다.
df$colname : "데이터프레임$컬럼이름"을 이용하면 데이터프레임에서 원하는 데이터에 접근할 수 있다.
df[r, c, drop = TRUE] : 데이터프레임 df의 r행, c열의 컬럼에 저장된 데이터를 가지고 올 수 있다. r과 c를 벡터로 지정하여 다수의 행과 컬럼을 동시에 가져올 수 있으며, 색인과 행 이름, 열 이름을 지정할 수도 있다. r과 c중 하나만 입력하는 경우, 예를 들어 c 하나만 넣은 경우엔 해당 열에 대한 모든 행 데이터를 가지고 온다.
r과 c중 하나만 불러오는 경우, 해당하는 행과 열 데이터만 해당 컬럼의 데이터 타입으로 가지고 오는데, 이러한 형 변환을 원하지 않는 경우엔 drop = FALSE로 지정하면 된다.
인덱싱 방법은 다음과 같다.
df$col1 : 데이터 프레임 df에서 col1 컬럼을 가지고 온다.
df[1,] : 데이터 프레임 df에서 1번째 행을 가지고 온다.
df[c(1,3), 2] : 데이터 프레임 df에서 1, 3번째 행을 가지고 오고, 2번째 컬럼을 가지고 온다.
df[ , c(2:5)] : 데이터 프레임 df에서 2~5번까지 컬럼을 가지고 온다.
df[ , -c(2:5)] == df[ , c(-2:-5)] : 데이터 프레임 df에서 2~5번 컬럼을 제외하고 가지고 온다.
df[ , c("math", "science")] : 데이터 프레임 df에서 math와 science 컬럼만 가지고 온다.
위 인덱싱 방법말고도 다른 함수들을 조합해서 가지고 올 수는 있으나, 위 방법만으로도 충분하다.
배열은 행렬을 다차원으로 담을 수 있는 데이터 타입으로, 전통적인 통계 분석에서는 그다지 필요가 없어보일 수 있다. 그리고, 동일한 2차원의 행렬에 대해서만 array에 적재할 수 있으므로, 모든 형태의 데이터 타입을 담을 수 있는 List에 비해 그 기능이 부족해보일 수 있다.
그러나, 반대로 말하자면 다차원 행렬을 적극적으로 사용해야하는 공학이나 요즘 핫한 빅데이터 분석에서는 array가 매우 유용한 데이터 타입이라고 할 수 있다. 꼭 숙지해놓고, 잘 활용해보도록 하자.
저번 포스트에선 행렬 생성과 행과 열의 이름 변경, 행렬의 정보 얻기 등을 공부해보았다. 이번 포스트에선 행렬 데이터 접근, 행렬의 연산에 대해 학습해보자.
행렬 데이터 접근하기
행렬은 색인 또는 행과 열의 이름을 통해서 접근할 수 있다.
행렬은 벡터와 같게 [] 대괄호를 이용해서 데이터에 접근한다.
단 행렬은 벡터와 다르게 2개의 차원인 행(Row), 열(Column)으로 구성되어 있으므로, 2개의 index를 부여해야한다.
Matrix[행index,열index]로 행렬 데이터에 접근할 수 있다.
Indexing 예시는 다음과 같다.
Matrix[row_id, col_id] : 행렬의 row_id 행과 col_id 열에 지정된 값을 가지고 온다. 이 때, row_id나 col_id에 벡터를 사용하여 여러 값을 지정할 수 있다. row_id나 col_id 둘 중 하나를 생략하면 전체 행이나 열을 뜻한다.
Matrix[1:3,] : 1~3 행의 데이터를 가지고 온다.
Matrix[-3,] : 3행의 데이터를 제외하고 모두 가지고 온다.
Matrix[c(1,3),] : 1, 3 행만 가지고 온다.
Matrix[,c("col5", "col3")] : 행렬 또한 행과 열에 부여된 이름으로 불러올 수 있다.
※ 접근한 행렬의 색인이나 이름의 순서에 따라서 행렬의 배열은 바뀌게 된다!
# 행렬에서 내가 원하는 데이터만 가지고 와보자.
vt = c(80, 60, 70, 75,
90, 70, 60, 60,
85, 90, 40, 70,
80, 75, 90, 80,
85, 80, 70, 65)
mat <- matrix(vt, nrow = 5, byrow = TRUE, dimnames = list(c("민철", "재성", "기훈", "재빈", "현희"), c("수학", "영어", "국어", "탐구")))
mat
이전 Scalar를 설명하면서 R에 있는 기본적인 Class들에 대해 설명을 하다보니, 분량 조절에 실패를 하고 말았다.... 이번엔 R 데이터 타입의 대표 주자인 벡터(Vector)에 대해 설명할 것인데, 벡터는 스칼라보다 다뤄야할 것도 많고, 매우 중요하기도 하므로, 2개 파트로 끊어서 진행할 예정이다.
벡터(Vector)
: R에서 벡터는 가장 대표적으로 사용되는 타입으로, 다른 프로그래밍 언어의 배열(Array)와 대응되는 개념이라고 볼 수 있다. 벡터의 가장 큰 특징은 단 한가지의 클래스만 담을 수 있다는 것이다.
벡터는 한 가지 Class만 담을 수 있으며, 만약 서로 다른 Class가 섞여있다면, 자동으로 그에 맞는 형변환이 이루어진다.
R의 벡터는 슬라이스(Slice)를 제공한다. 슬라이스란 벡터의 일부를 잘라낸 뒤, 이를 또 다시 벡터처럼 사용할 수 있는 개념이다.
벡터는 c()안에 원하는 인자를 넣어서 생성할 수 있다. (c = Combine, 하나의 단체로 결합하다.)
벡터는 중첩될 수 없다. 따라서 벡터 안에 벡터를 정의하면 단일 차원의 벡터로 변경된다.
벡터의 각 원소에는 이름을 부여할 수 있다.
# 벡터를 생성해보자.
x <- c("1", "2", "3")
x
## [1] "1" "2" "3"
# 벡터 안에 벡터를 넣어서 생성해보자.
c(1,2,3,c(1,2,3))
## [1] 1 2 3 1 2 3
Python의 list와 달리 R의 벡터는 벡터 안에 벡터를 넣을 수 없다.
# 벡터의 각 원소에 이름을 지어보자.
math <- c(60, 80, 70)
names(math) <- c("kim", "seo", "park")
math
R의 코드는 굉장히 직관적이라고 할 수 있는데, names(data)는 data의 이름을 가지고 오는 함수이다.
data의 이름을 가지고 오는 함수에 data의 길이와 같은 벡터를 넣으면, 그것을 이름으로 사용할 수 있다.
## kim seo park
## 60 80 70
names(math)
## [1] "kim" "seo" "park"
벡터의 길이 관련 함수
length(): 객체의 길이를 반환한다.
python의 len()과 같은 역할을 하는 함수로 몇 개의 인자를 가지고 있는지 확인할 수 있다.
# 벡터의 길이를 확인해보자.
x <- c(1,2,5,3)
length(x)
## [1] 4
NROW(): 벡터나 행렬의 행의 수를 반환한다.
NROW()는 그렇게 자주 쓰이는 함수는 아니며, 행렬이나 데이터프레임의 행 개수를 확인하는 nrow()와 유사한 함수이다. 차이는 벡터에서 사용될 수 있는지의 여부이다.
벡터는 각각의 인자를 행으로 잡고 있기 때문에, 행의 개수로 인자의 수를 반환한다. length()와 동일한 기능을 가지고 있으므로, 편하게 length()를 쓰도록 하자.
# 벡터의 행의 수를 확인해보자.
NROW(x)
## [1] 4
unique(): 중복된 값을 제외한 벡터.
데이터 프레임에서도 즐겨 사용되는 함수로, 벡터에서는 단순하게 중복 값을 없애는 함수로 인지하면 된다. (데이터 프레임에선 중복 행을 제거한다.)
벡터, 데이터 프레임 모든 곳에서 자주 사용하는 함수이므로 꼭, 기억하도록 하자.
# 중복값을 제외한 벡터를 생성해보자.
x <- c(1,1,3,2,3,4,2)
unique(x)
## [1] 1 3 2 4
벡터 내 데이터 접근(Indexing)
: Index를 통해 내가 원하는 데이터를 가지고 오는 것은 데이터 분석의 사전 작업인 전처리(Data Handling)에서 필수 중에 필수이다.
벡터는 [] 안에 Index를 적어서 내가 원하는 원소를 가지고 올 수 있다.
R의 인덱스는 Python을 비롯한 다른 언어들과 달리 1로 시작한다.
문법
의미
x[n]
벡터 x의 n번째 원소를 가지고 온다. n은 숫자 또는 원소의 이름인 문자열이다.(names로 확인 가능)
x[-n]
벡터 x의 n번째 원소를 제외한 나머지를 가지고 온다. n은 위의 n과 동일하다.
x[idx_vector]
벡터 x로부터 index vextor에 지정된 원소를 가지고 온다. 이때 idx_vector는 index를 표현하는 숫자 벡터 또는 원소의 이름을 표현하는 문자열 벡터이다.
x[start:end]
벡터 x의 start부터 end까지의 원소를 가지고 온다. 반환 되는 값은 start의 위치 값과 end 위치 값을 모두 포함한다.
# 다양한 indexing을 통해 내가 원하는 원소를 가지고 와 보자.
x <- c("apple", "banana", "melon", "chocolate", "ice cream", "corn")
x[5]
: 스칼라는 단일 차원의 값을 뜻하며, 길이가 1인 벡터와 동일하다. 즉, 구성인자가 하나인 벡터를 말한다.
스칼라는 정수, 부동소수, 문자열(""나 ''로 묶인), 논리값(TRUE, T, FALSE, F), NA, NULL의 데이터 타입을 갖는다.
스칼라를 쉽게 이야기 하자면, 값이 딱! 한 개만 있는 상태라고 생각하면 된다.
스칼라(Scalar)에선 R에 있는 다양한 Class에 대해 이야기해보도록 하겠다.
R에 있는 다양한 Class를 설명하면서, 벡터(Vector)를 예시로 들 수 있다. 벡터는 R에서 가장 기본적인 데이터 타입 단위이며, 스칼라는 벡터를 구성하는 하나하나의 원소라고 단순히 생각해도 무방하다. (벡터를 비롯한 다양한 연산자들은 다음 포스트에서 자세히 다루도록 할테니, 진행하다가 설명이 부족하거나 이해가 안되더라도 넘기면서 따라오기를 바란다.)
NA (Not Available)
데이터에 값이 존재하지 않는다는 뜻으로 결측치(Missing Value)이다. (결측치: 어떠한 이유로 인해, 값이 빠져 있는 경우다.)
데이터 분석을 할 때, 결측값이 존재한다면, 데이터 분석 결과를 왜곡 시킬 위험이 있기 때문에 결측값이 발생한 원인과 결측값의 존재를 반영하여 분석을 진행해야한다. (결측값에 대해선 추후 심도 깊게 다룰 예정이다.)
결측값의 존재를 파악하는 대표적인 함수는 in.na() 함수이다.
NULL
"아무 가치도 없는, 효력이 없는"이라는 뜻을 가진 NULL은, 값이 있어야 하는데 빠져버린 NA와 달리 값이 아직 정해지지 않은 상태를 의미한다.
NULL은 프로그래밍의 편의를 위해 미정(Undefined) 값을 표현하는데 사용하는 개념으로, 아직 정해지지 않은 값을 표현할 때 사용되는 값이다.
NULL의 존재를 파악하는 대표적인 함수는 is.null() 함수이다.
문자열(String, Character)
문자열은 ""나 ''로 묶어서 지정한다.
What's your name과 같이 문자 안에 ' (Quote) 기호가 들어가 있는경우 "What's your name"과 같이 쌍 따옴표(Double Quote)를 사용해서 묶어주면 된다.
is.character() 함수를 이용하여 문자열 여부를 확인할 수 있다.
noquote() 함수나 print(data, quote = FALSE)로 Qutation을 출력하지 않을 수 있다.
R은 다른 프로그래밍 언어랑 다르게 문자형과 문자열을 구분하지 않는다.
문자열 사용 방법
1) Quote 사용하기 : ""(Double Quotation)이나 ''(Single Quotation)을 사용하여 묶는다.
x1 <- ""
class(x1)
## [1] "character"
length(x1)
## [1] 1
x2 <- "car"
length(x2)
## [1] 1
R에서 length() 함수는 뒤에서 배울 데이터(벡터, 데이터프레임 등)의 길이를 재는 함수로, ""나 "car"모두 1자리 값인 스칼라이므로 length가 1로 나온 것을 알 수 있다.
즉, Quotation을 사용하여 문자열을 생성하면 1개의 스칼라가 생성되는 것을 알 수 있다.
2) character() 사용하기
y1 <- character()
class(y1)
## [1] "character"
length(y1)
## [1] 0
y2 <- character(5)
y2
## [1] "" "" "" "" ""
length(y2)
## [1] 5
y2[3] <- "third"
y2[7] <- "seventh"
y2
## [1] "" "" "third" "" "" NA "seventh"
## 값이 없는 index에도 새로운 인자를 추가할 수 있음
character() 함수는 주어진 Parameter만큼 문자열 벡터를 생성하는 함수이다.
character(5)로 길이가 5인 문자열 벡터를 생성하는 경우, 벡터의 길이를 벗어난 index에 값을 부여할 수 있으며, 그 사이에 있는 값은 NA처리가 된다.
문자열(character) 벡터에서 원소인 문자들의 길이를 확인해보자.
R에서 기본으로 제공하는 data인 mtcars를 이용해보자.
# R의 내장 Data인 mtcars의 행이름을 cars라는 변수에 담아보자
cars <- rownames(mtcars)
# nchar함수를 이용해서 문자의 길이들을 알아보자
nchar(cars)
nchar()은 number of character이라는 의미로 문자의 길이를 확인할 때 사용하는 함수이다.
위와 같은 문제 발생을 막기 위해 가능한 T, F로 쓰지말고 TRUE, FALSE로 쓰도록 하자.
진리값에는 논리연산자를 사용할 수 있다.
의미
논리연산자
설명
NOT
!
참은 거짓, 거짓은 참으로 반전시킴.
AND
&
양쪽 모두 참이어야 한다.
OR
|
양쪽 중 하나만 참이어도 참으로 한다.
AND
&&
양쪽 모두 참이어야 하며, 벡터의 요소 간 계산이 아닌 한 개의 Boolean 값끼리의 연산을 위한 연산자이다.
OR
||
양쪽 중 하나만 참이어도 참이며, 벡터의 모든 요소 간 계산이 아닌, 한 개의 Boolean 값끼리의 연산을 위한 연산자.
XOR
xor(A, B)
함수로 제공, A와 B가 서로 다를 때만 참이다.
&와 &&의 차이
c(TRUE, TRUE) & c(TRUE, FALSE)
## [1] TRUE FALSE
c(TRUE, FALSE) & c(TRUE, FALSE)
## [1] TRUE FALSE
c(TRUE, TRUE) && c(TRUE, FALSE)
## [1] TRUE
c(TRUE, FALSE) && c(TRUE, FALSE)
## [1] TRUE
c(FALSE, TRUE) && c(FALSE, TRUE)
## [1] FALSE
c(FALSE, FALSE) && c(FALSE, FALSE)
## [1] FALSE
&는 Boolean이 저장된 인자(스칼라)끼리 연산하여, 참, 거짓을 각각 구분한다.
&&는 벡터 안에 들어잇는 인자 간 계산이 아니라 한 개의 Boolean값만 연산한다. 또한 &&나 ||는 short-circuit를 지원한다. 따라서 위 와 같이 Boolean으로 구성된 2개의 인자를 가진 벡터 A와 벡터 B가 존재하고 이 둘을 A && B로 계산하는 경우, A가 만약 TRUE라면 B도 평가하지만 A가 FALSE라면 B가 TRUE던 FALSE던 의미가 없으므로 평가하지 않는다.
Boolean 활용 방법
: Boolean은 활용도가 매우 높은 Class이다. 다음 R에서의 예제를 보며, 한 번 따라해보도록 하자.
# x는 숫자타입(numeric), y는 문자타입(character)으로 생성해보았다.
x <- c(1,2,3,4,5)
y <- c("1", "2", "3", "4", "5")
x == y
## [1] TRUE TRUE TRUE TRUE TRUE
# x에서 3보다 큰 인자만 TRUE로 나타내어라.
x>3
## [1] FALSE FALSE FALSE TRUE TRUE
# x에서 3보다 큰 인자들을 TRUE(=1)로 나타내고, 그 합을 구하여라
sum(x>3)
## [1] 2
주의할 사항이며, Boolean의 성질이다.
x>3을 하는 경우 FALSE FALSE FALSE TRUE TRUE로 결과가 나오는데, 앞에서 이야기했듯이 FALSE == 0, TRUE == 1이다.
그러므로, sum(x>3)을 하게 되면, 0 0 0 1 1 의 합을 구하게 되는 것이다.
# x에서 3보다 큰 인자들을 가지고오고, 그 인자들의 합을 구하여라.
sum(x[x>3])
## [1] 9
x>3인 원소들의 합을 구하고자 한다면 다음과 같이 코드를 짜야한다.
여기서 x[x>3]은 x>3을 했을 때, TRUE인 값만 가지고 오는 것이다.
[]는 R에서 벡터, 행렬, 데이터프레임 등에서 내가 원하는 값만 가지고 올 때, 쓰이는 것으로 이에 대한 것은 다음 포스트에서 자세히 다루도록 하겠다.
# x에서 3보다 큰 인자들의 위치를 가지고 와라.
which(x>3)
## [1] 4 5
which 함수는 내가 벡터, 행렬, 데이터프레임에서 내가 원하는 값의 위치를 알 수 있게 하는 함수로 매우 유용하다.
요인(Factor)
요인(Factor)은 범주형 변수(Categorical Variables)를 위한 데이터 타입이다.
Factor가 필요한 이유는 다음과 같다. 성별(Sex)라는 벡터가 있다고 생각해보자, 이 변수에 들어갈 대상이 5명이라고 할 때, 성별을 문자(Female, Male)로 적는 것과 숫자(1,2)로 적는 것 이 둘 중 무엇이 컴퓨터에게 편할지 생각해보며, 해당 글을 읽도록 해보자.
# "male" 하나만 factor로 sex라는 변수에 부여하였다.
sex <- factor("male", c("male", "female"))
sex
## [1] male
## Levels: male female
# 5개의 원소를 factor로써 sex라는 변수에 부여하였다.
sex <- factor(c("male", "male", "female", "male", "female"), c("male", "female"))
sex
## [1] male male female male female
## Levels: male female
# 범주의 수를 확인해보자.
nlevels(sex)
## [1] 2
# 범주 목록을 확인해보자.
levels(sex)
## [1] "male" "female"
# 범주 목록에서 특정 인자(2번째)만 가지고 와보자.
levels(sex)[2]
## [1] "female"
# 범주 목록을 수정해보자.
levels(sex) <- c("m", "f")
sex
## [1] m m f m f
## Levels: m f
levels(sex) <- c(1, 2)
sex
## [1] 1 1 2 1 2
## Levels: 1 2
요인(Factor)을 사용하면, Data를 연산을 보다 효율적을 할 수 있고(문자보다 숫자가 컴퓨터에겐 당연히 더 알아보기 쉽고, 컴퓨터의 자원(Resource)도 더 적게 먹을 수 있다.)
Factor로 하여 숫자로 바꾸면, 우리가 눈으로 보기에는 숫자로 보이나, 실제론 문자이므로 더하기, 곱하기와 같은 연산은 불가능하다.
Factor형은 애초에 데이터를 불러오는 과정에서 잡아주어 숫자로 바꿔줄 수 있으므로, 굉장히 편리하다.
그러나, 텍스트 마이닝 같이 문자 그 자체가 분석의 대상인 경우엔 함부로 Factor형으로 바꿔주어서는 안된다. 만약 텍스트 마이닝을 할 것이면서 문자형 데이터를 Factor로 만든 경우, 많은 텍스트 마이닝에 사용되는 함수들이 적용 안될 수 있다.
서열척도(Ordinal scale)은?
요인(Factor)는 기본적으로 순서가 없는 명목형 척도(Nominal scale)로 생성된다. 만약 변수가 순서가 있는 경우 서열 척도로 만들어주기 위해 ordered() 함수를 사용하거나, 호출 시 factor()에 Parameter로 ordered = TRUE로 지정해주자.
지금까지 스칼라에 대한 기초적인 개념과 NA, NULL, 문자열, 진리값(Boolean), 요인(Factor)에 대해 알아보았다. 결측값을 의미하는 NA와 값이 아직 정해지지 않은 NULL의 개념은 이번 포스트에서 설명을 끝내기엔 사용처가 많고, 특히 결측값 같은 경우엔, 심도 깊게 들어가야할 필요가 있으므로, 추후 다른 포스트에서 다루도록 하겠다.
다음 포스트는 데이터 타입에서 가장 기본적으로 사용되는 벡터(Vector)에 대해 공부해보도록 하자.