카테고리 없음

[R 스튜디오] 배열 / 리스트 / 데이터 프레임

datahaseo 2025. 3. 19. 22:59

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()