[R 스튜디오] 배열 / 리스트 / 데이터 프레임
1. 배열
-행렬을 2차원 이상으로 확장시킨 객체
-2차원 구조로 이뤄진 행렬도 일종의 배열이라고 할 수 있고
일반적으로는 3차원 이상의 데이터 객체를 배열이라고 함
length : 자료의 개수
mode : 자료의 형태
dim : 각 차원의 크기
dimnames : 각 차원 리스트의 이름
예를 들어서 행렬은
matrix(1:12,c(4,3))
1~ 12 까지의 숫차를 4개의 행 , 3개의 열로 만드는건데
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
배열은 행, 열 , 행렬의 갯수로 표현
즉 여기는 3*3 을 2개 만드는건데
숫자는 1~24 사이니까 18까지만 나와
array(1:24,c(3,3,2))
array(1:24,c(3,3,2))
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 10 13 16
[2,] 11 14 17
[3,] 12 15 18
*dimnames : 배열이나 행렬의 차원에 대한 이름을 지정해줌.)
( 이름을 지정한다는 의미는 배열의 각 차원(행, 열, 층 등)에 알아보기 쉽게 이름을 붙이는 것을 뜻
예를 들어서
dimnames(arr)<-list(paste("row",c(1:3)),paste("col",c(1:3)),paste("ar",c(1:2)))
이거면
arr 라는 것에 이름을 지어주는데
배열이니까 행 . 열 . 층 세개 에 대해서 이름이 필요해
list(행 열 층)
인데
각 행 열 층은 past("row",c(1:3)) >> row 1 row 2 row 3
이렇게 이름 붙여주면 [ ] 를 통해서 특정 값 꺼내올 수도 있음
기타 함수
length(arr)
mode(arr)
dim(arr)
dimnames(arr)
> length(arr)
[1] 18
> mode(arr)
[1] "numeric"
> dim(arr)
[1] 3 3 2
> dimnames(arr)
[[1]]
[1] "row 1" "row 2" "row 3"
[[2]]
[1] "col 1" "col 2" "col 3"
[[3]]
[1] "ar 1" "ar 2"
<배열의 기본 함수 정리>
array(data,dim=c(행의 개수, 열의 개수, 행렬의 개수),dim.names=NULL)
dim(x) <- c(행렬 개수, 열의 개수, 행렬의 개수) // 이런식으로도 배열 생성 가능
x<-c(1:20)
dim(x)<-c(5,2,2)
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
, , 2
[,1] [,2]
[1,] 11 16
[2,] 12 17
[3,] 13 18
[4,] 14 19
[5,] 15 20
예제)
array() 함수로 1에서 6까지의 자료로 1차원, 2차원 배열을 생성해보고
1:8 값으로 3차원 배열 만들기
array(1:6)
array(1:6,c(3,2))
array(1:8,c(2,4,2))
> array(1:6)
[1] 1 2 3 4 5 6
> array(1:6,c(3,2))
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
> array(1:8,c(2,4,2))
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 4 6 8
, , 2
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 4 6 8
dim() 함수 이용해서 1:24 자료를 3행 4열 행렬 2개로 생성해보기
y<-c(1:24)
> dim(y)<-c(3,4,2)
> y
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
, , 2
[,1] [,2] [,3] [,4]
[1,] 13 16 19 22
[2,] 14 17 20 23
[3,] 15 18 21 24
*1~3 차원의 차이
array(1:8,c(2,2,2))
> array(1:8,c(2,2,2))
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
arrr<-c(1:24)
dim(arrr)<-c(3,4,2)
arrr
> arrr<-c(1:24)
> dim(arrr)<-c(3,4,2)
> arrr
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
, , 2
[,1] [,2] [,3] [,4]
[1,] 13 16 19 22
[2,] 14 17 20 23
[3,] 15 18 21 24
array1<-array(1:8,c(2,2,2))
array2<-array(8:1,c(2,2,2))
array1
array2
> array1
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
array2
, , 1
[,1] [,2]
[1,] 8 6
[2,] 7 5
, , 2
[,1] [,2]
[1,] 4 2
[2,] 3 1
*더하기랑 곱하기는 각 자리에 있는 애들끼리 계산
좀 독특한거는 배열 원소에 대한 곱을 구할때
array1%*%array2
를 하면 이건 각 원소들의 곱한거의 합과 같아
sum(array1*array2)
*원소 추출
array[a,b,c]
array1
array1[,,1] / 첫번쨰 배열을 가져오세용
> array1[,,1]
[,1] [,2]
[1,] 1 3
[2,] 2 4
> array1
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
1 3
5 7
> array1[1,,]
[,1] [,2]
[1,] 1 5
[2,] 3 7
> array1[,1,]
[,1] [,2]
[1,] 1 5
[2,] 2 6
> array1[,2,]
[,1] [,2]
[1,] 3 7
[2,] 4 8
> array1[,,1]
[,1] [,2]
[1,] 1 3
[2,] 2 4
> array1[1,1,]
[1] 1 5
> array1[1,,1]
[1] 1 3
> array[1,,2]
Error in array[1, , 2] : object of type 'closure' is not subsettable
> array1[1,,2]
[1] 5 7
> array1[1,2,]
[1] 3 7
> array1[1,,-1]
[1] 5 7
> array1[1,,-1]
[1] 5 7
> array1[1,,-2]
[1] 1 3
*마이너스는 제외한다는거니까
층 자리에 -1 이면 첫 번쨰 행렬 배열을 삭제하고 다른 행.열 값 가져오면 된다
2. 리스트
리스트는 서로 다른 형태의 데이터로 구성된 객체를 의미
-행렬과 배열 등이 동일한 형태의 원소로 이루어진 객체인 반면
리스트를 구성하는 성분은 서로 다른 형태의 원소를 가질 수 있고, 길이도 다를 수도 있음
length : 자료의 개수
mode : 자료의 형태
names : 각 구성요소의 이름
a<-1:10
b<-11:15
klist<-list(vec1=a,vec2=b,describe='example')
klist
a<-1:10
> b<-11:15
> klist<-list(vec1=a,vec2=b,describe='example')
> klist
$vec1
[1] 1 2 3 4 5 6 7 8 9 10
$vec2
[1] 11 12 13 14 15
$describe
[1] "example"
> length(klist)
[1] 3
> mode(klist)
[1] "list"
> names(klist)
[1] "vec1" "vec2" "describe"
리스트에서의 length 는 배열이나 벡터 처럼 각각의 원소의 갯수를 세는게 아니고
리스트 안에 있는 속성의 갯수를 세는 것
*리스트를 생성하고 추출하는 방법은 행렬과 유사
-[[ ]] >> 이렇게 두 개씩 겹괄호로 성분 추출
-성분의 이름이 부여되었다면 $ 로 구분
-[ ] 를 사용해서 성분 내의 특정 원소 추출
*list () 함수를 이용해서 A 라는 문자와 1 ~ 8 까지의 원소를 갖는 벡터를 성분으로 하는 LIST 1 을 생성하고
list1 의 세번쨰 성분으로 논리값 T, F 를 갖는 벡터를 추가하고 두번쨰 성분의 아홉번째 원소를 9 추가
list1 <- list("A",1:8) list 1 생성
list1[[1]] > A 값이 추출
*리스트에 값을 추가하는 방법
list1[[3]] <- list(c(T,F))
list1
이렇게 하면 list1 의 세번쨰 차리에 T F 넣는거
*성문을 추가할 때는 [[추가할 성분의 위치]]
[1] "A"
[[2]]
[1] 1 2 3 4 5 6 7 8
[[3]]
[[3]][[1]]
[1] TRUE FALSE
list1[[3]] <- list(c(T,F))
두개씩은 추가 못해서 1개씩만 넣어야 함
lista[[4,5]] <-c('d','e')
Error in lista[[4, 5]] <- c("d", "e") :
[[ ]] improper number of subscripts
> lista[[4,5]] <-list(c('d','e'))
Error in lista[[4, 5]] <- list(c("d", "e")) :
[[ ]] improper number of subscripts
특정 성분 안에 원소를 특정 자리에 넣으려면?
list1[[2]][9] <-9
list1
*원래 두번쨰 성분에 1:8 이었는데 9 번쨰 자리에 9라는 값을 넣은 것
list1[[2]][9] <-9
> list1
[[1]]
[1] "A"
[[2]]
[1] 1 2 3 4 5 6 7 8 9
[[3]]
[[3]][[1]]
[1] TRUE FALSE
*특정 성분 삭제하기
list1[[3]]<-NULL * 대문자로 써야해
> list1[[3]]<-null
Error: object 'null' not found
> list1[[3]]<-NULL
> list1[[3]]<-NULL
그러면 이렇게 세번쨰 성분 넣었던게 사라짐
> list1
[[1]]
[1] "A"
[[2]]
[1] 1 2 3 4 5 6 7 8 9
*특정 성분 안에 있는 값을 삭제하려면
list1[[2]] <-list1[[2]][-9] 이런식으로~!
list1[[2]] <-list1[[2]][-9]
> list1
[[1]]
[1] "A"
[[2]]
[1] 1 2 3 4 5 6 7 8
*예제
nlist<-list(vec1=a,vec=2,descrip='example')
이렇게 이름을 넣어준 경우 이름은 $ 가 앞에 붙음
> nlist<-list(vec1=a,vec=b,descrip='example')
> nlist
$vec1
[1] 1 2 3 4 5 6 7 8 9 10
$vec
[1] 11 12 13 14 15
$descrip
[1] "example"
nlist[[2]][5] 면 두 번쨰 성분의 5번쨰 원소니까 15
특정 성분의 순서 말고 이름으로도 지정할 수 있는데, 이때도 $ 를 써줘야함
nlist$vec[c(2,3)] 그러면 12,13
3.데이터 프레임
행렬은 차원으로 표시되며 같은 형태의 객체를 가지는 반면,
데이터 프레임은 각 열들이 서로 다른 형태의 객체를 가질 수 있음
(1) 데이터 프레임은 형태가 일반화된 행렬
(2) 데이터 프레임이라는 하나의 객체에 여러 종류의 자료가 들어갈 수 있음
(3) 데이터 프레임의 각 열은 각각 변수와 대응
(4) 분석이나 모형 설정에 적합한 자료 객체
*기본함수
(1) read.table() 외부 텍스트 파일을 불러들이는 방법
(첫줄에 변수명이 있으면 header = T 옵션)
(2) data.frame () 여러 종류의 자료 객체를 결합
(3) as.data.frame() 다른 형태의 자료객체를 데이터 프레임의 형태로 변환
<데이터 프레임 만들기>
read.table (file, header = FALSE ,sep = "" ,..)
data.frame(객체1 , 객체2 ,,,,)
as.data.frame (대상 객체 , ...)
write.csv (대상 객체, ...)
write.table (대상 객체, ...)
*wirte 는 csv 냐 table 이냐에 따라서 변수 생성 방식에 차이가 생기므로
적절한 옵션 필요
*csv 는 콤마 구분이고
table 은 sep=',' 옵션을 줘야 콤마로 구분
예를 들어서 아래와 같은 행렬이 있을 때
ab<-c(1,2,3,4,5)
> cd<-c(10,20,30,40,50)
> ff<-cbind(ab,cd)
> ff
ab cd
[1,] 1 10
[2,] 2 20
[3,] 3 30
[4,] 4 40
[5,] 5 50
write.csv는 이렇게 기본 열의 이름에 "" , "ab", "cd" 로 생겨있고
wirte.table 은 "ab" ,"cd" 로 생겨있어
또 csv 는 콤마로 구분하고 table 은 탭으로 구분되어 있어
write.csv(ff)
"","ab","cd"
"1",1,10
"2",2,20
"3",3,30
"4",4,40
"5",5,50
> write.table(ff)
"ab" "cd"
"1" 1 10
"2" 2 20
"3" 3 30
"4" 4 40
"5" 5 50
table 은 sep=, 옵션을 주면 이렇게 콤마로 구분할 수 있어
write.table(ff,sep=',')
"ab","cd"
"1",1,10
"2",2,20
"3",3,30
"4",4,40
"5",5,50
일반적으로 write.csv 는 csv, table 은 txt 파일로 저장하는데
csv 는 첫 열이 비워져 있고, txt 는 인덱스 열 뺴고 되어 있음
이 두 저장된 파일을 다시 read 해보면
csv 파일은 첫 열에 X 가 디폴트로 들어가 있고 table 함수는 그런건 없음
이렇게 X 가 생기는 건header 옵션으로 조절이 가능한데
> pp<-read.csv("ff_test.csv")
> pp
X ab cd
1 1 1 10
2 2 2 20
3 3 3 30
4 4 4 40
5 5 5 50
> ii<-read.table("ff_test.txt")
> ii
ab cd
1 1 10
2 2 20
3 3 30
4 4 40
5 5 50
header 가 F 면 내가 넣은 NA ab cd 도 원소로 인식이 되고
header 가 T 면 X ab cd 가 열의 이름으로 인식
단, csv 는 앞에 쓸데없는 열이 하나 붙어서 read 된다
ii<-pp<-read.csv("ff_test.csv",header=F)
> ii
V1 V2 V3
1 NA ab cd
2 1 1 10
3 2 2 20
4 3 3 30
5 4 4 40
6 5 5 50
> oo<-read.csv("ff_test.csv",header=T)
> OO
Error: object 'OO' not found
> oo
X ab cd
1 1 1 10
2 2 2 20
3 3 3 30
4 4 4 40
5 5 5 50
table 은 read 하면 이렇게 새로운 열 추가 없이 인식
기본적으로 header=T 일떄랑 동일하게 READ
> ll<-read.table('ff_test.txt')
> ll
ab cd
1 1 10
2 2 20
3 3 30
4 4 40
5 5 50
ee<-read.table('yy_test.txt',header=T)
ee
ee
ab cd
1 1 10
2 2 20
3 3 30
4 4 40
5 5 50
근데 저장했던 TXT 파일은 그대로 header = FALSE 로 출력 불가함
yy<-read.table('yy_test.txt',header=FALSE)
TABLE header = T 일때
yy<-read.table('yy_test.txt',header=T)
"ab" "cd"
"1" 1 10
"2" 2 20
"3" 3 30
"4" 4 40
"5" 5 50
row.names = F일때
write.table(ff,"JJ_test.txt",row.names=FALSE)
> 이렇게 row.names 가 F 여야 새로운 인덱싱 열이 안생겨 있어서 2줄
즉 열 이름하고 행의 길이가 같아서 이런 모양해서면
"ab" "cd"
1 10
2 20
3 30
4 40
5 50
**read 할 떄는내가 저장했던 파일의 sep 방식과 같은 옵션으로 read 해줘야해
<연습>
다음과 같은 데이트 프레임이 있다고 가정해보자!
num name age sex
1 Lee 55 M
2 Park 47 F
3 So 35 M
4 Kim 26 F
5 Yoon 29 M
*내가 만든거 (오류 발생)
name <-c("Lee","Park","So","Kim","Yoon")
name
age<-c(55,47,35,26,29)
sex<-c("M","F","M","F",'M')
test_0323<-cbind(name,age,sex)
write.table(test_0323,"test_0323.txt")
read.table("test_0323.txt")
각 행렬들은 bind 하고서, write.table 한걸 바로 read.table 하면
num 이름이 없으니까
read.table("C:\\Users\\bohee\\Documents\\test_0323.txt",row.names='num',header=T)
이렇게 옵션을 줬는데 그러면 오류 발생 ㅜ
알고보니
row.names = num 이라고 내가 정의했는데
R 은 num 이 뭔지 알 수 없는 상태
name <- c("Lee", "Park", "So", "Kim", "Yoon")
age <- c(55, 47, 35, 26, 29)
sex <- c("M", "F", "M", "F", "M")
num <- 1:5 # ✅ num 컬럼 만들기
test_0323 <- data.frame(num, name, age, sex)
write.table(test_0323, "test_0323.txt", row.names = FALSE, quote = FALSE)
이렇게 num < -1:5 라고 해야 함
name <-c("Lee","Park","So","Kim","Yoon")
name
age<-c(55,47,35,26,29)
sex<-c("M","F","M","F",'M')
num<-1:5
test_0323<-data.frame(num,name,age,sex)
test_0323
write.table(test_0323,"0323_test.txt",row.names=FALSE,quote=FALSE)
>> 아무튼 이렇게 row.names=FALSE 해야 쓸데없는 열번호 1 2 3 4 5 안 생김
num name age sex
1 Lee 55 M
2 Park 47 F
3 So 35 M
4 Kim 26 F
5 Yoon 29 M
근데 얘를 다시 read.table 하면 header=T 꼭 해줘야 하고 ,
또 열 번호가 생겨있어!
(예제2)
문자형 벡터 char1 과 수치형 벡터 num1 을 생성하고 결합하여 test1 이라는 데이터 프레임을 만들어 보는 예제
char1
A B C 라는 것을 각 요소당 2 2 1 반복해서 생성
> char1<-rep(LETTERS[1:3])
> char1
[1] "A" "B" "C"
> char1<-rep(LETTERS[1:3],c(2,2,1))
> char1
[1] "A" "A" "B" "B" "C"
num1<-rep(1:3)
> num1
[1] 1 2 3
> num1<-rep(1:3,c(2,2,1))
> num1
[1] 1 1 2 2 3
test1<-data.frame(char1,num1)
> test1
char1 num1
1 A 1
2 A 1
3 B 2
4 B 2
5 C 3
(예제)
문자 a 부터 o 까지로 이루어진 벡터를 생성하고 이를 5행 3열의 행렬로 변환한 뒤 a1으로 저장하고 데이터 프레임으로 변환
우선 행렬로 만드는 함수는 dim
a<-1:9
> dim(a)<-c(3,3)
> print(a)
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
*소문자로 만드는 함수 tolower 로 Letters 묶어주고
행렬 만들고
as.data.frame 으로 데이터 프레임 생성
a1<-tolower(LETTERS[1:15])
> a1
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
> print(a1)
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
> print(a1)
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
> dim(a1)<-c(3,3)
Error in dim(a1) <- c(3, 3) :
dims [product 9] do not match the length of object [15]
> print(a1)
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
> dim(a1)<-c(3,5)
> print(a1)
[,1] [,2] [,3] [,4] [,5]
[1,] "a" "d" "g" "j" "m"
[2,] "b" "e" "h" "k" "n"
[3,] "c" "f" "i" "l" "o"
> dim(a1)<-c(5,3)
> print(a1)
[,1] [,2] [,3]
[1,] "a" "f" "k"
[2,] "b" "g" "l"
[3,] "c" "h" "m"
[4,] "d" "i" "n"
[5,] "e" "j" "o"
> t1<-as.data.frame(a1)
> t1
V1 V2 V3
1 a f k
2 b g l
3 c h m
4 d i n
5 e j o
*참고
rbind 쓸 떄는 열 이름이 같아야 두개를 합칠 수 있는데
colnames(t1)<-c("a","b","c") 이렇게 써주니까 이름 바뀜
*merge()