벡터
벡터는 다음과 같은 특성을 지닌다.
•
한 벡터의 모든 원소는 같은 mode를 가지고 있어야 한다.
•
벡터는 여러 개의 위치로 인덱스 될 수 있으며, 이때 하위 벡터로 반환된다.
v[c(2,3)] # 은 v의 2,3번째 원소로 이루어진 하위 벡터다.
R
복사
•
벡터 원소들은 이름을 가질 수 있다. (names 속성)
v<-c(10,20,30)
names(v)<-c("Moe","Larry","Curly")
print(v)
# 원소가 이름을 가지고 있으면 이름으로 인덱싱할 수 있다.
v["Larry"]
R
복사
리스트
•
리스트는 여러 자료형의 원소들이 포함되어 있을 수 있다.
•
리스트는 위치로 인덱스된다. [[]] 를 사용한다.
•
리스트에서도 하위 리스트를 추출할 수 있다. lst[c(2,3)]
•
리스트에서도 원소들은 이름을 가질 수 있다. lst[[”Moe”]] , lst$Moe
모드(mode)
숫자와 숫자 벡터는 다른것이고, 문자열과 문자열 벡터는 다른 것이다.
클래스(Class)
R에서 모든 객체는 추상 자료형인 클래스도 가지고 있다. 같은 숫자형이더라도 해석 방법이 다르기 때문에 클래스는 상이하다는 것이다.
d <- as.Date("2022-03-22")
mode(d)
length(d)
class(d)
R
복사
요인(factor)
벡터에 가능한 모든 수준들 중에서 일부만이 들어있으면, R은 가능한 수준들 전체를 알 수 없다.
예를들어 수준들이 월요일 화요일 목요일 수요일만이 나왔다고 한다면 R은 나머지 요일들이 수준으로 존재한다고 생각하지 않는다. 이럴때는 우리가 가능한 수준들을 모두 명확하게 열거해줘야 한다.
f<-factor(wday,c("Mon","Tue","Wed","Thu","Fri"))
R
복사
즉, factor 의 두번째 인자가 요인을 순서에 맞게 정의해준다.
물론, 대개의 경우 factor함수를 특별히 호출할 필요는 없다. 어떤 함수가 요인을 필요로 하면, 보통 자동적으로 데이터를 요인으로 변환하기 때문이다.
하지만, 수준들 전체를 명시하고 싶다거나, 수준들의 순서를 조정하고 싶다면 요인 변수를 명확하게 생성해주어야 한다.
여러 벡터를 합쳐서 하나의 벡터와 요인으로 만들기
각 집단에 대한 벡터가 하나씩 있고, 그러한 집단데이터가 여러개다. 벡터들을 하나의 큰 벡터로 합침과 동시에 각 값이 속했던 원래 집단을 알려주는 상용요인을 만들고 싶다면?
•
stack함수를 사용(두열짜리 데이터프레임, 1열은 데이터를 담고, 2열은 상응요인을 담는다)
comb<-stack(list(v1=v1, v2=v2, v3=v3))
R
복사
1열은 values, 2열은 ind라고 불린다.
필요성 : 이런 함수가 필요한 이유는 중요한 통계 함수 대다수가 이러한 데이터 형식이어야 쓸 수 있기 때문이다.
ex) 집단 간 차이에 대한 분산분석을 수행하는 aov함수는 데이터 결과가 담긴 하나의 벡터와 집단에 대한 요인을 필요로 할 것이고 이때 stack 함수를 사용하면 된다.
comb<-stack(list(fresh=freshmen, soph=sophomores, jrs=juniors)
R
복사
# 분산분석
aov(values~ind, data=comb)
R
복사
리스트 생성하기
개별적인 데이터 항목들을 가지고 리스트를 만들려면 list함수를 사용한다.
# lst<-list(x,y,z)
lst<-list(0.5,0.841,0.977)
lst
[[1]]
[1] 0.5
[[2]]
[1] 0.841
[[3]]
[1] 0.977
R
복사
리스트가 벡터보다 유용한 점은 다른 모드로 된 원소들을 가질 수 있다는 것이다.
lst<-list(3.14, "Moe", c(1,2,3,4), mean) # 단일값, 문자열, 벡터, 함수
[[1]]
[1] 3.14
[[2]]
[1] "Moe"
[[3]]
[1] 1 2 3 4
[[4]]
function (x, ...)
UseMethod("mean")
<bytecode: 0x00000180a187ea70>
<environment: namespace:base>
R
복사
빈 리스트를 생성하고 채워 넣는 방법도 있다.
lst<-list()
lst[[1]]<-3.14
lst[[2]]<-"Moe"
lst[[3]]<-c(1,2,3,4)
lst[[4]]<-mean
# 원소들에 이름을 붙일 수도 있다.
lst<-list(mid=0.5, right=0.841, far.right=0.977)
$mid
[1] 0.5
$right
[1] 0.841
$far.right
[1] 0.977
R
복사
위치로 리스트 원소를 선택할 때는 [[ ]] 와 [ ] 을 주의해야 한다.
또한, 이름으로 선택할 때는 [[”원소이름”]] 은 $원소이름 과 결과가 같고, 리스트[c(원소이름1, 원소이름2,...)] 은 결과가 리스트다.
years<-list(Kennedy=1960, Johnson=1964, Carter=1976, Clinton=1994)
years[["Kennedy"]]
years$Kennedy # 위와 결과 동일
[1] 1960
years[c("Kennedy","Johnson")]
$Kennedy
[1] 1960
$Johnson
[1] 1964
years["Carter"]
$Carter
[1] 1976
R
복사
이름/값 연계 리스트 만들기
lst <- list(mid=0.5, right=0.841, far.right=0.977) # 이렇게 만들거나
# 이미 이름으로 된 벡터와 값으로 된 벡터가 있다면
lst <- list() # 빈리스트 생성
lst[names] <- values # 벡터 형식의 대입으로도 생성 가능하다.
lst <- list(
far.left = 0.023,
left = 0.159,
mid = 0.500,
right = 0.841,
far.right = 0.977)
#위와 동일한 방식은 다음과 같다
lst <- list()
lst$far.left <- 0.023
lst$left <- 0.159
lst$mid <- 0.500
lst$right <- 0.841
lst$far.right <- 0.977
# 때로는 이름이 들어있는 벡터와 값들이 들어있는 벡터가 따로 있다.
values <-pnorm(-2:2)
names <-c("far.left","left","mid","right","far.right")
lst <- list()
lst[names] <- values
R
복사
리스트에서 원소 제거하기
제거하고 싶은 원소에 NULL을 대입한다.
years[["Johnson"]]<-NULL <- # 한 개 원소 제거
years[c("Carter","Clinton")] <- NULL # 두 개 원소 제거
R
복사
리스트의 구조를 없애 벡터로 만들기
unlist함수 사용.
일반적으로 기본적인 통계함수들은 벡터에는 잘 작동하지만 리스트에는 작동하지 않는다.
예를들어 iq.scores가 숫자 리스트라고 치면
mean(unlist(iq.scores))
R
복사
NULL 원소를 리스트에서 제거하기
sapply 와 is.null 함수를 이용해서 제거할 수 있다.
sapply를 호출해서 is.null함수를 리스트의 모든 원소에 적용한다. sapply는 논리값 벡터를 반환할 것이고, 리스트의 원소가 NULL인 곳의 논리값이 TRUE가 될 것이다. 해당원소들은 선택이 될 것이고 그 선택된 원소들에 NULL을 대입함으로써 제거된다.
lst[sapply(lst,is.null)] <- NULL
R
복사
물론, NULL을 포함하는 리스트를 만들 수 있다.
lst <- list("Moe", NULL, "Curly")
[[1]]
[1] "Moe"
[[2]]
NULL
[[3]]
[1] "Curly"
lst[sapply(lst,is.null)] <- NULL
[[1]]
[1] "Moe"
[[2]]
[1] "Curly"
R
복사
조건을 사용해 리스트의 원소 제거하기
예를 들어 리스트의 원소들 중 음수값이나 기준치보다 작은 값들을 제거하고 싶을 수도 있다.
조건에 따른 논리형 벡터를 만들고 논리값이 TRUE인 애들에 NULL값을 대입해 제거한다.
다음은 모든 음의 값을 제거하는 예시다
lst[lst<0] <- NULL
R
복사
리스트에서 NA값을 제거한다.
lst[is.na(lst)] <- NULL
R
복사
문제는 논리형 벡터를 쉽사리 만들지 못할 경우 문제가 생긴다. 리스트를 다루지 못하는 함수를 쓰고 싶을 때 종종 발생한다.
예를 들어 절대값이 1보다 작은 원소들을 제거하고 싶다고 하자. 이때 절댓값 함수 abs는 리스트를 다루지 못한다.
lst[abs(lst)<1] <- NULL # 을 하면 오류가 발생한다.
R
복사
이런 경우에는 리스트의 구조를 해체해 벡터로 만든 뒤, 벡터를 검사하는 방법이 있다.
lst[abs(unlist(lst))<1] <- NULL
R
복사
좀 더 고급진 방법은 lapply를 사용하는 것이다.
lst[lapply(lst,abs) < 1] <- NULL
R
복사
리스트는 복잡한 개체들도 담고 있을 수 있다. 예를 들어 선형모형들이 원소로 있는 리스트를 mods라고 하고 결정계수 값이 0.3보다 작은 모든 모형을 제거하고 싶다고 해보자.
mods[sapply(mods,function(m) summary(m)$r.squared < 0.3)] <- NULL
R
복사
행렬의 초기 내용 설정하기
행렬을 생성한 뒤 주어진 값으로 초기화하고 싶다고 하자.
벡터나 리스트에 데이터를 담은 후, matrix함수를 사용해서 데이터를 행렬로 바꿀 수 있다.
matrix(vec,2,3) # 벡터를 2x3 행렬로 바꿨다.
theData<-c(1.1,1.2,2.1,2.2,3.1,3.2)
mat <- matrix(theData,2,3)
mat
[,1] [,2] [,3]
[1,] 1.1 2.1 3.1
[2,] 1.2 2.2 3.2
R
복사
행렬의 초기 내용을 0이나 NA등 하나의 값으로 설정하는 경우가 자주 있다. 이럴때는 데이터자리에 단일값을 넣어주면 된다.
matrix(0,2,3) # 모두 0인 행렬 생성
[,1] [,2] [,3]
[1,] 0 0 0
[2,] 0 0 0
matrix(NA,2,3) # NA로 채워진 행렬을 생성한다.
[,1] [,2] [,3]
[1,] NA NA NA
[2,] NA NA NA
R
복사
byrow인자를 사용해서 열 순서가 아닌 행 순서로 데이터를 배치할 수 있다.
theData<-c(1.1,1.2,1.3,2.1,2.2,2.3)
mat<-matrix(theData,2,3,byrow=TRUE)
mat
[,1] [,2] [,3]
[1,] 1.1 1.2 1.3
[2,] 2.1 2.2 2.3
R
복사
벡터를 간단히 행렬로 변환할 수 있는 방법이 있는데 벡터에 차원을 부여하는 것이다. 하지만, byrow라는 옵션이 없기 때문에 왠만하면 matrix함수를 사용하자
v <- c(1.1,1.2,1.3,2.1,2.2,2.3)
dim(v) <- c(2,3)
v
[,1] [,2] [,3]
[1,] 1.1 1.3 2.2
[2,] 1.2 2.1 2.3
R
복사
행렬의 연산 수행하기
행렬의 전치, 역행렬 계산, 행렬곱셈, 단위행렬 만들기 등 행렬 연산을 수행하려고 한다.
•
t(A) : A의 전치 행렬
•
solve(A) : A의 역행렬
•
A %*% B : A와 B의 행렬 곱셈(내적)
•
diag(n) : n차 대각선 단위행렬
위 함수의 인자들은 행렬이나 데이터프레임(물론 모두 수치형일때)이다.
행렬의 행과 열에 친절한 이름 붙이기
모든 행렬에는 rownames 속성과 colnames 속성이 있다.
rownames(mat) ← c(”행이름1”,”행이름2”,”행이름3”,...)
colnames(mat) ← c(”열이름1”,”열이름2”,”열이름3”,,,)
행과 열에 이름을 붙이면 이름으로 행렬의 원소를 지칭할 수 있다.
행렬에서 하나의 행 또는 열을 선택하기
결과를 어떻게 내고 싶냐에 따라 방법이 여러가지다.
1.
결과가 벡터
vec <- mat[1,] # 첫째 행 출력
vec <- mat[,3] # 셋째 열 출력
R
복사
2.
결과가 행 하나짜리 또는 열 하나짜리 행렬 : drop=FALSE 인자를 넣는다(차원을 유지하게함)
row <- mat[1,,drop=FALSE] # 행 하나짜리 행렬의 첫 행
col <- mat[,3,drop=FALSE] # 열 하나짜리 행렬의 셋째 열
R
복사
일반적으로 인덱스형태로 선택하면 결과는 차원이 없는 벡터가 된다.
열 데이터로 데이터 프레임 만들기
여러 개의 열들로 정리되어 있는 데이터를 데이터프레임으로 조립하고 싶다고 하자.
데이터가 여러 개의 벡터와 요인에 담겨 있으면 data.frame 함수를 사용해서 데이터프레임으로 조립한다.
dfrm <- data.frame(v1,v2,v3,f1,f2)
R
복사
만약, 데이터가 벡터와 요인을 포함하고 있는 리스트에 담겨 있다면 as.data.frame을 쓴다.
dfrm <- as.data.frame(list.of.vectors)
R
복사
예를 들어, 두개의 수치형 예측변수, 한 개의 범주형 예측변수, 한 개의 반응변수가 있다고 할 때 데이터프레임을 만들어보면
dfrm <- data.frame(pred1,pred2,pred3,resp)
# 물론 변수 이름을 따로 지정할 수도 있다
dfrm <- data.frame(p1=pred1,p2=pred2,p3=pred3,r=resp)
R
복사
데이터가 벡터로 정리되어있기는 하지만 리스트에 들어 있는 경우가 있다.
lst <- list(p1=pred1, p2=pred2, p3=pred3, r=resp)
as.data.frame(lst)
R
복사
행 데이터로 데이터 프레임 만들기
여러 개의 행들로 정리되어 있는 데이터를 데이터프레임으로 조립하고 싶다.
1.
각 행을 한 행짜리 데이터 프레임에 담는다.
2.
한 행짜리 데이터프레임을 리스트에 저장한다.
3.
rbind와 do.call을 사용해서 행들을 하나의 큰 데이터 프레임으로 묶는다.
dfrm <- do.call(rbind, obs) # obs는 한 행짜리 데이터프레임들로 된 리스트다.
R
복사
데이터는 종종 관측값들의 형태로 들어온다. 즉 관측을 기준으로 정리되어 있기 때문에 행별로 읽게되는데 여러 가지 방법으로 저장될 수 있다.
가장 흔한 방법은 모든 데이터가 수치형일때 벡터로 저장하는 것이다.
하지만 대부분의 데이터들은 여러 종류의 데이터가 혼합되어 있어서 벡터를 쓸 수가 없다. 이럴때는 행 하나짜리 데이터 프레임으로 저장해야 한다.
예를 들어, 관찰값 하나당 네 개의 변수가 있는 행이 열개 있다고 하자. pred1, pred2, pred3, resp로 총 네 개의 변수다. 각 행이 하나의 데이터프레임에 저장이 되기 때문에 총 10 개의 데이터프레임이 있는 것이다. 또, 이 데이터프레임들이 obs라는 리스트에 저장되어 있다.
obs의 첫 번 째 원소는 다음과 같을 것이다.
obs[[1]]
pred1 pred2 pred3 resp
[1] -1.197 0.36 AM 18.701
# 이제 각 행들을 데이터프레임으로 합쳐야 한다. rbind함수를 사용한다.
rbind(obs[[1]],obs[[2]]) # 1행 2행을 합친 데이터프레임
# 모든 행을 합치기 위해서 do.call함수를 사용한다.
do.call(rbind, obs)
R
복사
불가피하게 데이터들의 행들이 한 행짜리 데이터프레임이 아니라 리스트로 저장되어있는 경우도 있다.
이럴때 obs는 리스트로된 목록이 된다. —> Map함수를 사용해서 행들을 데이터프레임으로 변형한 후, 위의 방법을 적용한다.
do.call(rbind,Map(as.data.frame,obs))
R
복사
데이터프레임에 행 추가하기
데이터프레임에 하나 또는 그 이상의 새로운 행을 추가하고 싶다고 하자.
rbind()함수를 사용한다.
먼저, 새 데이터가 들어있는 한 행짜리 데이터 프레임을 생성한다.
newRow <- data.frame(city="West Dundee", county="Kane", state="IL", pop=5428)
R
복사
rbind함수를 사용해서 원 데이터프레임에 추가해준다.
suburbs <- rbind(suburbs, newRow)
R
복사
주의할 점은 새로운 행은 원 데이터프레임과 동일한 열이름을 사용해야만 한다. 그렇지 않으면 rbind는 작용하지 않는다.
위의 과정을 합치면,
suburbs <- rbind(suburbs,data.frame(city="West Dundee", county="Kane", state="IL",pop=5428))
R
복사
하지만, 위의 방식은 크 데이터 프레임에 행을 한꺼번에 많이 추가할 경우 효율적이지 못하다.
대신 아래의 방식을 사용하면 좋다.
데이터 프레임 사전 할당하기
하나씩 행을 추가하는 대신 공간을 사전 할당해 둘 수가 있다. 물론 전제조건은 필요한 행의 수를 알고 있다는 것이다.
numeric(n), character(n), factor(n) 함수를 사용해서 제네릭 벡터와 요인으로부터 데이터 프레임을 만든다. 여기서 n은 데이터프레임에 필요한 행의 개수다.
dfrm <- data.frame(열이름1=numeric(n), 열이름2=character(n), ...etc...)
R
복사
예를들어 1000000개의 행과 세 개의 열(두개는 수치형, 하나는 문자형)로 된 데이터프레임을 만들고 싶다고 해보자. numeric과 character함수를 사용해서 열들을 사전 할당한다.
N <- 1000000
dfrm <- data.frame(dosage=numeric(N), lab=character(N), response=numeric(N))
R
복사
예를 들어, 위의 lab이 요인이라고 치고 가능한 수준이 NJ, IL, CA라고 하자. 다음과 같이 요인을 사전할당 한다.
N <- 1000000
dfrm <- data.frame(dosage=numeric(N), lab=factor(N,levels=c("NJ","IL","CA")),response=numeric(N))
R
복사
위치로 데이터 프레임의 열 선택하기
리스트 인덱스와 비슷하다. 하나의 열을 선택하여 벡터로 결과를 반환받고 싶다면 다음과 같이 한다.
1.
dfrm[[n]] : dfrm의 열 n번째 열을 벡터로 반환한다.
하나 이상의 열을 데이터프레임형태로 반환받고 싶다면 다음과 같이 한다.
2.
dfrm[n] : dfrm의 열 n번째 하위 데이터프레임을 반환한다.
또는 dfrm[c(n1,n2,...nk)] : dfrm의 열 n1, n2,...nk로 구성된 데이터프레임 반환
물론, 행렬의 형식으로도 선택할 수 있다. —> 결과는 열벡터 또는 데이터프레임
dfrm[,n] : n번째 열인 열벡터로 반환한다.
dfrm[,c(n1,n2,...nk)] : n1,n2,...nk번째 열로 구성된 데이터 프레임 반환한다.
이름으로 데이터 프레임 열 선택하기
열을 한개만 선택할 경우, 2가지의 방식이 있다. dfrm [[”name”]] 또는 dfrm$name 결과는 둘 모두 벡터인 열로 반환한다.
열을 한개이상 선택할 경우 데이터프레임으로 출력하려면 다음과 같이 한다. 한개라면 dfrm[’name’], 여러개라면 dfrm[c(”name1”,”name2”,...)] 이다.
행렬 방식으로 출력하려면 dfrm[,”name”] : 결과는 열벡터 , 또는 dfrm[,c(”name1”,”name2”,...)] : 결과는 데이터프레임 이다.
더 쉽게 행과 열 선택하기
데이터프레임이나 행렬에서 더 쉬운 방법으로 행과 열을 선택하려고 한다. subset 함수를 사용한다.
subset(dfrm, select=열이름)
subset(dfrm, select=c(열이름1,열이름2,...))
R
복사
subset 인자는 행을 선택하는 논리식이다. 논리식 안에 직접 열 이름을 사용할 수 있다.
subset(dfrm, subset=(response > 0)) # response열이 양수인 행을 선택한다.
R
복사
select와 subset 인자를 같이 쓰면 아주 효율적으로 선택할 수 있다.
subset(dfrm, select=c(predictor,response), subset=(response > 0))
# predictor, response열을 선택하는데, response값이 양수인 행만 선택
R
복사
MASS패키지의 Cars93 데이터 세트를 활용해보자.
시내에서 갤런 당 30마일 이상을 주행하는 연비를 갖는 차의 모델명을 선택해보자.
subset(Cars93, select=Model, subset=(MPG.city > 30))
Model
31 Festiva
39 Metro
42 Civic
73 LeMans
80 Justy
83 Swift
84 Tercel
R
복사
미국에서 만들어진 4기통 차의 모델명과 가격대를 선택해보자.
subset(Cars93,select=c(Model,Min.Price,Max.Price), subset=(Cylinders=="4" & Origin=="USA"))
Model Min.Price Max.Price
6 Century 14.2 17.3
12 Cavalier 8.5 18.3
13 Corsica 11.4 11.4
15 Lumina 13.4 18.4
21 LeBaron 14.5 17.1
23 Colt 7.9 10.6
24 Shadow 8.4 14.2
25 Spirit 11.9 14.7
27 Dynasty 14.8 16.4
29 Summit 7.9 16.5
31 Festiva 6.9 7.9
32 Escort 8.4 11.9
33 Tempo 10.4 12.2
34 Mustang 10.8 21.0
35 Probe 12.8 15.2
60 Capri 13.3 15.0
68 Achieva 13.0 14.0
69 Cutlass_Ciera 14.2 18.4
72 Laser 11.4 17.4
73 LeMans 8.2 9.9
74 Sunbird 9.4 12.8
79 SL 9.2 12.9
R
복사
고속도로에서의 MPG(연비) 값이 중앙값 이상인 모든 차의 제조사와 모델명을 선택해보자.
subset(Cars93,select=c(Model,Make), subset=(MPG.highway >= median(MPG.highway)))
Model Make
1 Integra Acura Integra
5 535i BMW 535i
6 Century Buick Century
7 LeSabre Buick LeSabre
12 Cavalier Chevrolet Cavalier
13 Corsica Chevrolet Corsica
14 Camaro Chevrolet Camaro
15 Lumina Chevrolet Lumina
20 Concorde Chrylser Concorde
21 LeBaron Chrysler LeBaron
23 Colt Dodge Colt
24 Shadow Dodge Shadow
29 Summit Eagle Summit
30 Vision Eagle Vision
31 Festiva Ford Festiva
32 Escort Ford Escort
34 Mustang Ford Mustang
35 Probe Ford Probe
37 Taurus Ford Taurus
39 Metro Geo Metro
40 Storm Geo Storm
41 Prelude Honda Prelude
42 Civic Honda Civic
43 Accord Honda Accord
44 Excel Hyundai Excel
45 Elantra Hyundai Elantra
46 Scoupe Hyundai Scoupe
53 323 Mazda 323
54 Protege Mazda Protege
55 626 Mazda 626
58 190E Mercedes-Benz 190E
62 Mirage Mitsubishi Mirage
64 Sentra Nissan Sentra
65 Altima Nissan Altima
68 Achieva Oldsmobile Achieva
69 Cutlass_Ciera Oldsmobile Cutlass_Ciera
71 Eighty-Eight Oldsmobile Eighty-Eight
72 Laser Plymouth Laser
73 LeMans Pontiac LeMans
74 Sunbird Pontiac Sunbird
75 Firebird Pontiac Firebird
77 Bonneville Pontiac Bonneville
79 SL Saturn SL
80 Justy Subaru Justy
81 Loyale Subaru Loyale
82 Legacy Subaru Legacy
83 Swift Suzuki Swift
84 Tercel Toyota Tercel
85 Celica Toyota Celica
86 Camry Toyota Camry
88 Fox Volkswagen Fox
90 Passat Volkswagen Passat
92 240 Volvo 240
93 850 Volvo 850
R
복사
데이터프레임의 열 이름 바꾸기
데이터프레임에는 열 이름으로 된 벡터인 colnames라는 속성이 있다. 전체 열 이름을 부여하거나 변경하려면 다음과 같이 한다.
colnames(dfrm) <- newnames # newnames는 문자열 벡터다.
R
복사
행렬을 데이터프레임으로 변환할 때 기존에 이름이 있다면 자동으로 그 이름을 열의 이름으로 갖다쓰거나 이름이 없다면 v1, v2,... 이런식으로 이름을 붙인다.
하지만, 리스트를 데이터프레임으로 변환하는 경우에 이름이 없다면 이상한 이름을 갖다 쓴다. 이럴때 colnames라는 함수를 활용하면 된다.
데이터 프레임에서 NA 제거하기
1.
NA값이 들어있는 행을 삭제할 수 있다. —> na.omit() 함수를 사용한다.
clean <- na.omit(dfrm)
R
복사
단, 벡터와 행렬에 대해서는 작동하지만 리스트에서는 안된다.
이름으로 열 제외하기
subset 과 select를 사용하는데 select에서 변수앞에 ‘-’ 를 붙인다.
subset(dfrm, select=-badboy) # badboy를 제외한 모든 열 출력
# 복수의 열 제거
subset(dfrm, select=c(-열이름1, -열이름2))
R
복사
상관계수 행렬에 ID같은 열은 필요가 없다.
데이터프레임 두 개 합치기
두 데이터프레임을 합쳐서 하나의 데이터 프레임으로 만들고 싶다고 하자.
먼저, 옆으로 붙이고 싶다면 cbind()함수를 사용한다.
all.cols <- cbind(dfrm1,dfrm2)
R
복사
아래로 붙이고 싶다면 rbind()함수를 사용한다.
all.rows <- rbind(dfrm1,dfrm2)
R
복사
cbind는 일반적으로 동일한 행의 수를 가지고 있는 열들을 결합한다. 하지만, 꼭 그렇지 않아도 된다. 한쪽이 짧다면 재활용의 법칙을 적용해서 필요한만큼 길이를 늘린다.
rbind는 동일한 변수의 이름, 동일한 변수를 가지고 있어야 한다. 하지만, 굳이 열이 동일한 순서로 있지 않아도 된다. ( rbind가 알아서 정리한다 )
merge() 함수는 열이 모자라거나 달라서 호환이 안되는 데이터 프레임들을 합칠 수 있다. 또한 reshape2 와 plyr 패키지는 더 강력한 함수들을 담고 있다.
하나의 공통된 열로 데이터 프레임 병합하기
merge() 함수를 사용해서 공통된 열을 바탕으로 새로운 데이터 프레임으로 병합한다.
m <- merge(df1,df2, by="공통된 열")
R
복사
이때, 공통된 값만 갖고 있는 행들만 구성해서 새로운 데이터 프레임을 만드는 것이다. 즉, 한쪽의 데이터 프레임에만 나타나는 데이터는 버린다.
데이터프레임의 내용에 더 쉽게 접근하기
데이터프레임 이름을 계속 입력하려니 귀찮다고 하자. 더 쉽게 열에 접근할 수 있는 방법을 알아보자.
with() 함수로 열의 이름을 꺼내는 방법이다. expr 안에서 dataframe의 열들을 단순한 변수처럼 이름으로 지칭할 수 있다.
with(dataframe, expr)
# z 값을 구하는 것을 with를 통해서 하면
z <- with(suburbs, (pop - mean(pop)) / sd(pop) ) # pop은 suburbs의 변수다.
R
복사
attach()함수를 사용하면 데이터프레임을 언급하지 않고도 바로 열들에 접근할 수 있다.
attach(dataframe)
#데이터 프레임의 사용이 종료되면 꼭 detach()를 해주자
detach(dataframe)
R
복사
위와 같은 성질로 attach를 한 변수의 변화도 실제 원본 데이터의 변화를 가져오지는 않는다.
자료형 변환하기
자료형 변환 함수에는 다음과 같은 것들이 있다.
•
as.character(x)
•
as.complex(x)
•
as.numeric(x) 또는 as.double(x)
•
as.integer(x)
•
as.logical(x)
변환이 잘 먹히면 값이 나올 것이고 잘 변환이 되지 않는다면 NA값이 나올 것이다.
as.numeric("3.14") # 문자형을 실수형으로
[1] 3.14
as.integer(3.14) # 실수형을 정수형으로
[1] 3
as.numeric("foo") # 문자형을 실수형으로 --> 변환 x
[1] NA
Warning message:
NAs introduced by coercion
as.character(101) # 정수형을 문자형으로
[1] "101"
R
복사
물론, 복수도 변환 가능하다
as.numeric(c("1","2.718","7.389","20.086"))
[1] 1.000 2.718 7.389 20.086
as.numeric(c("1","2.718","7.389","20.086","etc."))
[1] 1.000 2.718 7.389 20.086 NA
Warning message:
NAs introduced by coercion
as.character(101:105)
[1] "101" "102" "103" "104" "105"
R
복사
논리값을 숫자로 바꿀때는 FALSE를 0, TRUE를 1로 변환한다.
as.numeric(FALSE)
[1] 0
> as.numeric(TRUE)
[1] 1
# 논리값으로 된 벡터에서 TRUE의 개수를 셀 때 유용. logvec이 논리값벡터라고 하면
sum(logvec) #은 TRUE의 개수를 반환한다.
R
복사
데이터 구조 변환하기
다음 함수들은 해당하는 데이터 구조로 인자를 변환한다.
•
as.data.frame(x) :벡터나 행렬, 리스트를 데이터프레임으로 변환
•
as.list(x) : 벡터나 행렬, 데이터프레임을 리스트로 변환
•
as.matrix(x) : 벡터나 리스트, 데이터프레임을 행렬로 변환
•
as.vector(x) : 행렬의 모든 원소들을 벡터로 반환
주의할 사항은 R cookbook의 p185에 나와있다. 필요하면 참고하자
7장. 문자열과 날짜
R에는 날짜와 시간을 다루는 데 쓰는 클래스들의 종류가 많다. 일부는 날짜만 다루는 클래스이고, 일부는 날짜 및 시간 클래스들이다.
다음은 기본 배포판에 포함된 클래스들이다.
•
Date : 날짜는 나타낼 수 있지만 시간은 나타내지 못한다. 변환, 형식 설정, 기본 날짜 연산, 표준 시간대 처리 등의 작업을 할 때 쓴다.
•
POSIXct : 날짜 및 시간 클래스다. 1970년 1월 1일 이후로 흐른 초로 저장된다. 날짜시간 정보를 저장할 때 쓰기를 추천된다.
•
POSIXlt : 날짜 및 시간 클래스다. 하지만 연도, 월, 일, 시, 분, 초를 포함하는 아홉 개의 원소로 된 리스트에 저장된다. 따라서 추출하기 쉽다. 그렇기에 POSIXct보다는 덜 간결하다. 따라서 중간 처리 과정에서 쓰이지 저장하는데 쓰이지는 않는다.
기본 배포판은 이 표현들 간의 변환을 쉽게 해주는 함수들을 제공한다. as.Date, as.POSIXct, as.POSIXlt 와 같다.
다음은 다운로드 받을 수 있는 패키지들이다.
•
chron : 날짜와 시간 모두 나타낼 수 있다. Date보다는 사용하기 쉽지만 POSIXct나 POSIXlt보다는 성능이 좋지 않다. 시계열 분석 할때 사용하면 좋다.
•
lubridate : 새로 나온 다목적 패키지다. 날짜 시간 연산 능력이 좋다.
•
mondate : 날짜를 연도와 일 외에도 추가적으로 월 단위로 다룰 수 있게 특화된 패키지.
•
timeDate : 날짜와 시간을 면밀하게 다룰 수 있도록 된 고성능 패키지. 따라서 날짜 기능이 많이 요구되는 일을 한다면 이 패키지가 유용
7.1 문자열의 길이 알아내기
문자열의 길이를 알고 싶다고 하자. length 가 아니라 nchar 함수를 사용한다.
nchar은 문자열을 받아서 문자열에 있는 문자의 개수를 반환한다.
nchar("Moe")
nchar("Curly")
R
복사
문자열로 된 벡터를 받게되면 각 길이를 벡터로 반환한다.
s <- c("Moe","Curly","Larry")
nchar(s)
[1] 3 5 5
R
복사
length("Moe") # 결과는 1이 나올것이다.
[1] 1
length(c("Moe","Curly","Larry")) # 결과는 3
R
복사
7.2 문자열 연결하기
두 개 이상의 문자열을 합치고 싶다고 하자. paste 함수를 사용한다.
paste 함수는 여러 개의 문자열들을 연결해 준다. 즉 새로운 문자열을 생성한다.
paste("Everybody","loves","stats.")
[1] "Everybody loves stats."
R
복사
paste 기본설정으로 문자열을 연결할 때 그 사이에 빈칸(” “)을 삽입한다.
자동으로 빈칸이 삽입되는 것을 바꾸려면 sep 인자를 이용해서 다른 구분자를 사용할 수 있다.
paste("Everybody","loves","stats.", sep="-")
[1] "Everybody-loves-stats."
paste("Everybody","loves","stats.", sep="")
[1] "Everybodylovesstats."
R
복사
이 함수는 심지어 문자열이 아닌 값이 들어와도 알아서 as.character 함수를 써서 문자열로 변환하려고 한다.
paste("The square root of twice pi is approximately", sqrt(2*pi))
[1] "The square root of twice pi is approximately 2.506628274631"
R
복사
또한 인자값이 문자열로 된 벡터라면 해당 원소들의 모든 조합을 만들어서 문자열을 연결한다.
stooges <- c("Moe","Larry","Curly")
paste(stooges,"loves","stats.")
[1] "Moe loves stats." "Larry loves stats." "Curly loves stats."
# 만약 위의 모든 조합도 다 합쳐서 하나의 큰 문자열을 만들고 싶다면
# collapse 인자를 사용하면 최고 수준의 구분자를 정의하여 연결할 수 있다.
> paste(stooges, "loves","stats",collapse=', and ')
[1] "Moe loves stats, and Larry loves stats, and Curly loves stats"
R
복사
7.3 하위 문자열 추출하기
위치에 따라 문자열의 일부를 추출하려고 한다. substr(string, start, end)를 사용해서 추출한다.
> substr("Statistics",1,4)
[1] "Stat"
> substr("Statistics",7,10)
[1] "tics"
R
복사
물론 substr은 첫 번째 인자가 문자열로 된 벡터여도 된다. 각 원소에 적용한 결과를 벡터로 반환해준다.
> ss <- c("Moe","Larry","Curly")
> substr(ss,1,3)
[1] "Moe" "Lar" "Cur"
R
복사
더 나아가서 모든 인자가 벡터여도 가능하다. 서로 상응하는 벡터로 취급한다. 다음은 각 문자열에서 마지막 두 문자를 추출한다.
> cities <-c("New York, NY", "Los Angeles, CA", "Peoria, IL")
> substr(cities,nchar(cities)-1,nchar(cities)) # 모든 인자가 벡터
[1] "NY" "CA" "IL"
R
복사
7.4 구분자로 문자열 분할하기
문자열을 하위 문자열로 분할하려고 한다. 하위 문자열들은 구분자로 나뉘어 있다.
strsplit 함수를 사용한다. 인자는 문자열과 하위 문자열의 구분자다.
—> strsplit(문자열, 구분자)
동일한 구분자에 의해 여러 개의 하위 문자열이 나뉘는 것은 문자열에서 흔한 일이다. 일반적으로 파일 경로가 그런 예이다. (”/”)
path <- "/home/mike/data/trials.csv"
strsplit(path, "/")
[[1]]
[1] "" "home" "mike" "data" "trials.csv"
R
복사
strsplit은 결과를 리스트로 반환한다. 리스트의 각 원소는 하위 문자열로 된 벡터다.
다음은 세 개의 파일 경로를 분할해서 세 개의 원소로 된 리스트를 반환하는 예시다.
> paths <- c("/home/mike/data/trials.csv",
+ "/home/mike/data/errors.csv",
+ "/home/mike/corr/reject.doc")
> strsplit(paths, "/")
[[1]]
[1] "" "home" "mike" "data" "trials.csv"
[[2]]
[1] "" "home" "mike" "data" "errors.csv"
[[3]]
[1] "" "home" "mike" "corr" "reject.doc"
R
복사
strsplit의 두번째 인자인 구분자인자는 정규표현식 기능을 사용하는 것도 가능하다. 즉, 훨씬 더 복잡한 패턴을 찾을 수 있게 해준다. 하지만, 기본 설정인 정규표현식 기능을 꺼두려면 fixed=TRUE 인자를 꼭 넣어줘야 한다.
7.5 하위 문자열 대체하기
문자열 내에서 어떤 하위 문자열을 다른것으로 대체하고 싶다고 하자.
sub함수를 사용해서 첫 번째 하위 문자열을 대체한다. string내의 old라는 하위 문자열의 첫번째 인스턴스를 찾아서 new라는 하위문자열로 대체한다.
sub(old, new, string)
> s <- "Curly is the smart one. Curly is funny, too."
> sub("Curly", "Moe", s)
[1] "Moe is the smart one. Curly is funny, too."
R
복사
gsub함수를 사용해서 모든 하위 문자열을 대체한다.
gsub(old, new, string)
> gsub("Curly", "Moe", s)
[1] "Moe is the smart one. Moe is funny, too."
R
복사
이를 응용해서 하위 문자열을 제거할 수도 있다.
> sub(" and SAS", "", "For really tough problems, you need R and SAS.")
[1] "For really tough problems, you need R."
R
복사
마찬가지로 old 인자는 정규표현식이어도 상관없다. 즉 더 복잡한 패턴을 찾을 수 있다. 정규표현식이 기본 설정이니 원하지 않다면 fixed = TRUE 로 설정한다.
7.6 문자열에서 특수문자 보기
출력되지 않는 특수문자들이 문자열에 포함되어 있다. 그게 뭔지 알고 싶다고 하자.
print를 사용하면 문자열에 있는 특수문자를 볼 수 있다.
7.7 문자열의 모든 쌍별 조합 만들기
문자열이 두 세트 있고, 이 세트들 간의 모든 조합을 만들고 싶다고 하자.
outer함수와 paste 함수를 함께 쓰면 가능한 모든 조합의 행렬을 만들 수 있다.
m <- outer(문자열1, 문자열2, paste, sep="")
R
복사
기존에 outer함수는 외적하는 함수다. 하지만 세번 째 인자에 행렬의 곱셈대신 다른 함수가 들어갈 수 있게 해준다.
예시로 네 개의 실험 장소와 세 가지 실험 처리 방법이 있다고 해보자. outer 와 paste를 사용해서 실험 장소와 처리 방법의 모든 조합을 만들 수 있다.
> locations <- c("NY","LA","CHI","HOU")
> treatments <-c("T1","T2","T3")
> outer(locations, treatments, paste, "-")
[,1] [,2] [,3]
[1,] "NY T1 -" "NY T2 -" "NY T3 -"
[2,] "LA T1 -" "LA T2 -" "LA T3 -"
[3,] "CHI T1 -" "CHI T2 -" "CHI T3 -"
[4,] "HOU T1 -" "HOU T2 -" "HOU T3 -"
R
복사
보이다시피 outer의 결과는 행렬이다. 결과를 벡터로 나타내고 싶다면 as.vector 함수를 사용한다.
자기 자신과의 모든 조합을 만들 수도 있다. 물론 따라서 쌍이 중복되는 값이 생길 것이다.
outer(treatments, treatments, paste, sep="-")
[,1] [,2] [,3]
[1,] "T1-T1" "T1-T2" "T1-T3"
[2,] "T2-T1" "T2-T2" "T2-T3"
[3,] "T3-T1" "T3-T2" "T3-T3"
R
복사
물론 위의 결과에서 중복되는 값을 없애고 싶을 경우에는 행렬의 아래 삼각형(또는 위쪽)을 제거함으로써 해결할 수 있다.
lower.tri함수는 lower triangle 에 해당하는 행렬의 원소의 값을 TRUE로 바꾼다.
반대는, upper.tri 함수다.
!lower.tri 를 하게 되면 하상삼각원소를 제외한 나머지 원소들을 가지고 오게 된다.
> m <- outer(treatments, treatments, paste, sep="-")
> m[!lower.tri(m)]
[1] "T1-T1" "T1-T2" "T2-T2" "T1-T3" "T2-T3" "T3-T3"
R
복사
7.8 현재 날짜 알아내기
오늘 날짜를 알고 싶다고 하자.
Sys.Date 함수는 현재 날짜를 반환한다.
Sys.Date()
[1] "2022-03-31"
class(Sys.Date())
[1] "Date"
R
복사
Date 객체를 반환한다. 즉, 날짜만 반환한다.
7.9 문자열을 날짜로 변환하기
“2022-03-31” 처럼 문자열 표현으로 된 날짜를 Date 객체로 변환하고 싶다고 하자.
물론, as.Date를 사용할 수도 있지만 그 전에 문자열의 형식을 알아야 한다. 왜냐하면 as.Date는 문자열이 기본으로 ‘yyyy-mm-dd’라고 가정하기 때문이다.
따라서, 문자열이 위의 yyyy-mm-dd 형식이 아니라면 as.Date의 format 인자를 따로 지정해줘야 한다.
예를들어 날짜가 미국 스타일로 되어있다면 format=”%m/%d/%Y” 를 사용한다.
> as.Date("2022-03-31")
[1] "2022-03-31"
R
복사
다음과 같은 실수는 하지 말자.
as.Date("03/31/2022")
Error in charToDate(x) : 문자열이 표준서식을 따르지 않습니다
R
복사
아래처럼 바꾼다.
as.Date("03/31/2022", format="%m/%d/%Y")
[1] "2022-03-31"
R
복사
7.10 날짜를 문자열로 변환하기
Date 객체를 문자열로 변환하고 싶다고 하자.
format이나 as.character를 사용한다.
format(Sys.Date())
[1] "2022-03-31"
> as.character(Sys.Date())
[1] "2022-03-31"
R
복사
두 함수 모두 형식을 제어하는 format인자를 사용할 수 있다.
> format(Sys.Date(), format="%m/%d/%Y")
[1] "03/31/2022"
R
복사
%뒤에 오는 문자 하나로 된 구성된 조합은 특별한 의미를 지닌다.
•
%b : 축약된 월 이름(”Jan”)
•
%B : 전체 월 이름(”January”)
•
%d : 두 자리 숫자로 된 일
•
%m : 두 자리 숫자로 된 월
•
%y : 두 자리 숫자로 된 연도
•
%Y : 네 자리 숫자로 된 연도
7.11 연, 월, 일을 날짜로 변환하기
연, 월, 일로 표현된 날짜가 있다. 이 원소들을 합쳐서 하나의 Date 객체 형식으로 바꾸고싶다고 하자.
ISOdate 함수를 사용한다.
ISOdate(연, 월, 일) : 결과는 Date 객체로 변환이 가능한 POSIXct 객체다.
입력데이터에 연, 월, 일 세 개의 숫자로 인코딩되어 있는 날짜가 포함되는 경우는 흔하다. ISOdate 함수는 이들을 통합해 POSIXct 객체로 만들 수 있다.
ISOdate(2022,4,4)
[1] "2022-04-04 12:00:00 GMT"
R
복사
순수하게 날짜만 원한다면 Date객체로 변환하는 것이 좋다.
as.Date(ISOdate(2022,4,4))
[1] "2022-04-04"
R
복사
ISOdate 함수는 연도, 월, 일들로 된 벡터들 전체를 처리할 수 있어서 입력 데이터를 대량으로 변환할 때 매우 편리하다.
다음예는 여러 해의 1월 셋째 수요일에 해당하는 연/월/일 벡터들을 모두 합쳐 Date 객체로 만든다.
> years <- c(2010,2011,2012,2013,2014)
> months <-c(1,1,1,1,1)
> days <-c(15,21,20,18,17)
> ISOdate(years,months,days)
[1] "2010-01-15 12:00:00 GMT" "2011-01-21 12:00:00 GMT" "2012-01-20 12:00:00 GMT"
[4] "2013-01-18 12:00:00 GMT" "2014-01-17 12:00:00 GMT"
> as.Date(ISOdate(years,months,days))
[1] "2010-01-15" "2011-01-21" "2012-01-20" "2013-01-18" "2014-01-17"
# 더 응용하면 월 벡터가 계속 반복되기 때문에 재활용 규칙을 활용해서 단순하게 만든다.
> as.Date(ISOdate(years,1,days))
[1] "2010-01-15" "2011-01-21" "2012-01-20" "2013-01-18" "2014-01-17"
R
복사
7.13 날짜의 일부 추출하기
주어진 Date 객체에서 날짜의 일부를 추출하려고 한다.
Date 객체를 날짜 부분들의 리스트인 POSIXlt 객체로 변환한다. 그 다음 리스트에서 원하는 부분을 추출한다.
> d <- as.Date("2010-03-15")
> p <- as.POSIXlt(d)
> p
[1] "2010-03-15 UTC"
> class(p)
[1] "POSIXlt" "POSIXt"
> p$mday # 그 달의 몇째 날인지
[1] 15
> p$mon # 월 (0=1월)
[1] 2
> p$year + 1900 # 연도
[1] 2010
R
복사
POSIXlt 객체는 어떤 날짜를 날짜 부분들의 리스트로 표현한다.
POSIXlt 객체는 다음과 같은 구성으로 된 리스트를 가진다.
•
sec : 초
•
min : 분
•
hour : 시
•
mday : 해당 달의 몇째 날(1-31)
•
mon : 월(0-11) , 1월이 0이고 12월이 11이라고 생각하면 된다.
•
year : 1900년 이후로 지난 햇수 ( + 1900 을 해줘야 현재 연도가 출력 )
•
wday : 해당 주의 몇째 날(0-6, 0=일요일)
•
yday : 해당 해의 몇째 날(0-365, 0=1월 1일)
> d <- as.Date("2010-04-01")
> as.POSIXlt(d)$wday
[1] 4
> as.POSIXlt(d)$yday
[1] 90
R
복사
7.14 날짜로 된 수열 생성하기
일별, 월별, 혹은 연도별 날짜 수열같은 것을 만들고 싶다.
seq 함수는 Date객체를 위한 수열을 만들 수 있다.
사용방법은 시작날짜(from), 끝나는 날짜(to), 증가분(by)을 지정하는 것이다.
증가분 1은 하루를 의미한다.
> s <- as.Date("2012-01-01")
> e <- as.Date("2012-02-01")
> seq(from=s,to=e,by=1)
[1] "2012-01-01" "2012-01-02" "2012-01-03" "2012-01-04" "2012-01-05" "2012-01-06" "2012-01-07"
[8] "2012-01-08" "2012-01-09" "2012-01-10" "2012-01-11" "2012-01-12" "2012-01-13" "2012-01-14"
[15] "2012-01-15" "2012-01-16" "2012-01-17" "2012-01-18" "2012-01-19" "2012-01-20" "2012-01-21"
[22] "2012-01-22" "2012-01-23" "2012-01-24" "2012-01-25" "2012-01-26" "2012-01-27" "2012-01-28"
[29] "2012-01-29" "2012-01-30" "2012-01-31" "2012-02-01"
R
복사
to 대신에 날짜 수(length.out)을 지정할 수도 있다.
> seq(from=s,by=1,length.out=7)# 일주일 간의 날짜
[1] "2012-01-01" "2012-01-02" "2012-01-03" "2012-01-04" "2012-01-05" "2012-01-06" "2012-01-07"
R
복사
by은 유동적이라서 일, 주, 월, 혹은 연으로도 지정될 수 있다.
> seq(from=s,by="month",length.out=12)
[1] "2012-01-01" "2012-02-01" "2012-03-01" "2012-04-01" "2012-05-01" "2012-06-01" "2012-07-01"
[8] "2012-08-01" "2012-09-01" "2012-10-01" "2012-11-01" "2012-12-01"
> seq(from=s,by="3 months", length.out=4)
[1] "2012-01-01" "2012-04-01" "2012-07-01" "2012-10-01"
> seq(from=s, by="year",length.out=10)
[1] "2012-01-01" "2013-01-01" "2014-01-01" "2015-01-01" "2016-01-01" "2017-01-01" "2018-01-01"
[8] "2019-01-01" "2020-01-01" "2021-01-01"
R
복사
물론, by=”month”로 지정할 때는 2월의 마지막날은 28임을 주의해야 한다.