@@@ 데이터분석/데이터 분석의 모든 것

Chapter 2. R 프로그래밍 - 2.3 데이터 구조

HTG 2021. 9. 12. 15:38
728x90

키워드 : 벡터, 매트릭스, 데이터프레임, 배열, 리스트

더보기

벡터 : 하나 이상의 데이터를 저장할 수 있는 1차원 저장 구조. 벡터 안의 데이터는 모두 같은 타입.

매트릭스 : 표 형태와 같은 2차원 데이터 저장 구조. 매트릭스 안의 데이터는 벡터와 마찬가지로 모두 같은 데이터 타입.

데이터프레임 : 매트릭스처럼 행과 열을 가진 2차원 구조. 벡터, 매트릭스와 다른 점은 각 열별로 서로 다른 데이터 타입을 가질 수 있다는 점.

배열 : 다차원 데이터 저장 구조. 벡터나 매트릭스처럼 동일한 데이터 타입으로 저장.

리스트 : 다차원 데이터 저장 구조. 배열과 다른 점은 키와 값 쌍으로 저장되며 값에 해당하는 데이터가 벡터, 매트릭스, 배열, 리스트 등 어떠한 데이터 종류도 가능.

 

2.3.1 벡터(vector)

하나 이상의 데이터를 저장할 수 있는 1차원 저장 구조.

6명의 학생 나이를 students_age 변수에 저장하는 예.

명령어 c의 괄호 안에 콤마를 구분자로 하나 이상의 데이터를 나열한 후, 변수에 저장.

students_age <- c(11, 12, 13, 20, 15, 21) # c는 concentration을 의마하는 명령어
students_age
[1] 11 12 13 20 15 21

#length()로 벡터의 길이를 확인.
length(students_age)
[1] 6

students_age에 다음과 같은 1차원의 저장 구조인 벡터가 생성, 데이터가 저장.

벡터 안에 하나 이상의 데이터가 있고, 각각의 데이터 위치를 나타내는 인덱스가 존재.

인덱스는 1부터 시작.(다른 대부분의 언어는 0부터 시작함.)

 

2.3.1.1 일부 데이터만 접근

인덱싱과 슬라이싱을 이용하여 일부 데이터만 접근.
인덱스를 이용하는 방법은 변수 이름 뒤 대괄호 [ ] 안에 접근할 데이터의 인덱스를 쓰면 됨.

이것을 인덱싱이라고 부름.

students_age[1]
[1] 11
students_age[3]
[1] 13

특정 인덱스의 데이터만 제되하고 접근도 가능. 제외하고 싶은 인덱스에 -를 붙이면 됨.

students_age[-1]
[1] 12 13 20 15 21

 

다은은 슬라이싱.

대괄호 [ ] 안에 [시작인덱스:끝인덱스]라고 쓰면, 시작 인덱스의 데이터부터 끝 인덱스 데이터 까지 접근.

이것을 슬라이싱이라고 부름.

students_age[1:3]
[1] 11 12 13
students_age[4:6]
[1] 20 15 21

 

2.3.1.2 벡터의 구조

class()로 데이터 타입을 확인.

length()로 벡터의 길이 확인.

str()는 데이터 타입, 길이 등 전체 구조를 확인.

students_age <- c(11, 12, 13, 20, 15, 21)
class(students_age)
[1] "numeric"

length(students_age)
[1] 6

str(students_age)
num [1:6] 11 12 13 20 15 21

 

2.3.1.3 벡터 데이터 추가, 갱신, 삭제

인덱스를 이용해서 벡터에 데이터를 갱신하거나 추가.

score <- c(1, 2, 3)
score[1] <- 10 # 저장하고 있는 인덱스가 있다면 갱신
score[4] <- 4  # 저장하고 있는 인덱스가 없다면 추가

score
[1] 10 2 3 4

 

2.3.1.4 벡터의 데이터 타입

벡터는 하나의 원시 데이터 타입으로 저장.

만약, 다양한 데이터 타입을 섞어 저장하면 하나의 타입으로 자동으로 형변환.

 

다음과 같이 숫자, 문자를 섞어 벡터를 만드는 경우 문자타입으로 모두 바뀜.

code <- c(1, 12, "30")
class(code)
[1] "character"

str(code)
chr [1:3] "1" "12" "30"

 

숫자와 논리(TRUE, FALSE)를 섞어 벡터를 만드는 경우 숫자타입으로 모두 바뀜.

code <- c(1, 12, TRUE, FALSE)
class(code)
[1] "numeric"

str(code)
num [1:4] 1 12 1 0

 

2.3.1.5 벡터 데이터 생성

연속된 숫자를 생성하는 예.

data <- c(1:10) # 1부터 10까지 1씩 증가시켜 생성.
data
[1] 1 2 3 4 5 6 7 8 9 10

data1 <- seq(1, 10) # 1부터 10까지 1씩 증가시켜 생성
data1
[1] 1 2 3 4 5 6 7 8 9 10

data2 <- seq(1, 10, by = 2) # 1부터 10까지 2씩 증가시켜 생성
data2
[1] 1 3 5 7 9

 

rep()를 이용하여 반복된 숫자 벡터를 생성.

data3 <- rep(1, times = 5)
data3
[1] 1 1 1 1 1

data4 <- rep(1:3, times = 3)
data4
[1] 1 2 3 1 2 3 1 2 3

data5 <- rep(1:3, each = 5)
data5
[1] 1 1 1 2 2 2 3 3 3

# 1부터 3을 각각 두 번씩 반복 생성하고, 전체 데이터를 세 번 반복 생성.
data6 <- rep(1:3, each = 2, times = 3)
data6
[1] 1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3

 

2.3.2 매트릭스(행렬, matrix)

표 형태와 같은 2차원 데이터 저장 구조.

매트릭스는 벡터와 마찬가지로 모두 같은 데이터 타입.

행렬은 matrix()로 생성.

var1 <- c(1, 2, 3, 4, 5, 6)

# var1을 이용 2행 3열 행렬 생성. 기본적으로 열 우선으로 값이 채워짐.
x1 <- matrix(var1, nrow = 2, ncol = 3)
x1
     [, 1] [, 2] [, 3]
[1, ]   1     3     5
[2, ]   2     4     6

# var2을 이용 2열 행렬 생성. 행의 개수는 자동 생성.
x2 <- matrix(var1, ncol = 2)
x2
     [, 1] [, 2]
[1, ]   1     4 
[2, ]   2     5 
[3, ]   3     6

 

2.3.2.1 일부 데이터만 접근

다음과 같이 대괄호 안에 행 인덱스, 열 인덱스를 사용하여 매트릭스의 일부 데이터만 접근.

x1[1, ]  # x1의 1행, 모든 열
[1] 1 3 5
x1[, 1]  # x1의 모든 행, 1열
[1] 1 2
x1[2, 2]  # x1의 2행, 2열
[1] 4

 

dimnames()로 행렬의 행 이름, 열 이름을 부여할 수 있음. 행 이름과 열 이름으로도 데이터 접근이 가능.

# x2행렬에 행 이름과 열 이름 부여
dimnames(x2) <- list(c("r1","r2","r3"), c("c1","c2"))
x2
   c1 c2
r1  1  4
r2  2  5
r3  3  6

x2[, "c1"]
r1 r2 r3
 1  2  3
 
x2["r1", ]
c1 c2
 1  4
 
x2["r1", "c1"]
[1] 1

 

2.3.2.2 행렬에 데이터 추가

rbind()로 행을 추가, cbind()로 열을 추가.

x1
     [, 1] [, 2] [, 3]
[1, ]   1     3     5
[2, ]   2     4     6

# 행 추가
x1 <- rbind(x1, c(10, 10, 10))
x1
     [, 1] [, 2] [, 3]
[1, ]   1     3     5
[2, ]   2     4     6
[3, ]  10    10    10

# 열 추가
x1 <- cbind(x1, c(20, 20, 20))
x1
     [, 1] [, 2] [, 3] [, 4]
[1, ]   1     3     5    20
[2, ]   2     4     6    20
[3, ]  10    10    10    20

 

2.3.3 데이터프레임(dataframe)

매트릭스처럼 행과 열을 가진 2차원 구조.

벡터, 매트릭스와 다른 점은 각 열이 서로 다른 데이터 형싱을 가질 수 있다. 는 것. (단, 길이는 같아야함.)

이러한 장점으로 인해 데이터 분석에서 가장 많이 사용되는 데이터 저장 구조.

data.frame()로 생성.

열은 속성(attribute) 또는 변수(variable), 행은 관측 데이터.

no <- c(10, 20, 30, 40, 50, 60, 70)
age <- c(18, 15, 13, 12, 10, 9, 7)
gender <- c("M", "M", "M", "M", "M", "F", "M")

# no, age, gender 벡터들을 각열로 포함하는 데이터프레임 생성.
# 이때 주의할 점은 각 벡터의 길이가 같아야 함.
students <- data.frame(no, age, gender)
student
   no age gender
 1 10  18      M
 2 20  15      M
 3 30  13      M
 4 40  12      M
 5 50  10      M
 6 60   9      F
 7 70   7      M

 

각 열의 이름은 colnames(), 각 행의 이름은 rownames() 로 확인 및 수정 가능.

colnames(student)
[1] "no"  "age"  "gender"

# 수정
colnames(student) <- c("no", "나이", "성별")
rownames(student) <- c("A", "B", "C", "D", "E", "F", "G")

student
   no 나이 성별
 A 10  18     M
 B 20  15     M
 C 30  13     M
 D 40  12     M
 F 50  10     M
 G 60   9     F
 H 70   7     M

 

2.3.3.1 일부 데이터만 접근

행 이름, 열 이름 또는 행 인덱스, 열 인덱스를 이용하여 일부 데이터만 접근 가능.

열의 이름으로 특정 열에 접근하는 예.

데이터프레임의 변수이름$열이름 또는 대괄호 안에 콤마 뒤의 열의 이름을 써도 됨.

 

열 이름을 특정 열에 접근

# 데이터프레임의 변수이름$열이름으로 특정 열에 접근.
students$no
[1] 10 20 30 40 50 60 70
students$age
[1] 18 15 13 12 10 9 7

# 대괄호 안에 열 이름으로 특정 열에 접근
# 대괄호 안에 콤마를 쓴 후 열 이름을 씀. 이때 열 이름은 " " 또는 ' '로 감쌈.
students[, "no"]
[1] 10 20 30 40 50 60 70
students[, "age"]
[1] 18 15 13 12 10 9 7

 

열 인덱스로 특정 열에 접근

students[, 1]
[1] 10 20 30 40 50 60 70
students[, 2]
[1] 18 15 13 12 10 9 7

 

행 이름으로 특정 행만 접근

students["A", ] # A행 데이터가 출력. 행 이름은 " " 또는 ' '로 감쌈.
                # 행 이름 뒤에 콤마를 반드시 써야함.
  no age gender
A 10  18      M

 

행 인덱스로 특정 행만 접근

students[1, ] # 첫 번째 행 데이터가 출력
              # 행 인덱스 뒤에 콤마를 반드시 써야함.
  no age gender
A 10  18      M

students[2, ] # 두 번째 행 데이터가 출력
              # 행 인덱스 뒤에 콤마를 반드시 써야함.
  no age gender
A 20  15      M

 

행 인덱스, 열 인덱스 또는 행 이름, 열 이름으로 데이터에 접근

students[3, 1]
[1] 30
student["A", "no"]
[1] 10

 

2.3.3.2 데이터프레임의 데이터 타입

벡터의 경우 class()로 데이터 타입을 확인하면 벡터 내에 저장된 데이터의 타입이 출력되지만, 그 외의 데이터 구조는 데이터 구조 자체의 타입이 출력

class(student)
[1] "data.frame"

 

데이터프레임 내의 각 열은 서로 다른 벡터이므로 각 벡터별로 다른 기본 데이터 타입을 가지고 있을 수 있음.

class()로 특정 열의 데이터 타입을 확인.

class(students$no)
[1] "numeric"
class(students$gender)
[1] "character"

데이터프레임 생성 시 문자타입을 펙터타입으로 생성하고 싶으면 stringsAsFactaer = TRUE 옵션 사용.

no <- c(10, 20, 30, 40, 50, 60, 70)
age <- c(18, 15, 13, 12, 10, 9, 7)
gender <- c("M", "M", "M", "M", "M", "F", "M")

new_students <- data.frame(no, age, gender, stringAsFactors = TRUE)
class(new_students)
[1] factor

stringAsFators = TRUE가 디폴트.

 

2.3.3.3 데이터프레임의 구조

벡터와 마찬가지로 str()로 데이터프레임의 대략적인 구조를 확인.

str(students)
'data.frame':     7 obs. of 3 variables:
$ no    : num  10 20 30 40 50 60 70
$ age   : num  18 15 13 12 10 9 7
$ gender: Factor w/ 2 levels "F","M": 2 2 2 2 2 1 2

dim()으로 차원 정보를 확인.

dim(students)
[1] 7 3     # 7행 3열

빅데이터의 경우 앞이나 뒤의 몇 행의 데이터만 출력하여 데이터를 파악하는 것이 유용할 때가 있음.

head()와 tail()로 앞 뒤 일부 데이터만 추출.

head(students) # 앞의 6행만 추출
tail(students) # 뒤의 6행만 추출

 

2.3.3.4 데이터프레임 데이터 추가

데이터프레임에 열을 추가할 수 있음.

기존에 존재하지 않은 열 이름으로 벡터를 저장하면 열이 추가.

만약, 기존에 존재하는 열 이름이면 데이터가 갱신.

# 열 추가
students$name <- c("이용", "준희", "이훈", "서희", "승희", "하정", "하준")
students
  no age gender name
A 10 18       M 이용
B 20 15       M 준희
C 30 13       M 이훈
D 40 12       M 서희
E 50 10       M 승희
F 60  9       F 하정
G 70  7       M 하준

데이터프레임에 행을 추가할 수 있음.

기존에 존재하지 않는 행 이름 또는 행 인덱스를 사용하여 행을 추가 할 수 있음.

만약, 존재하는 행 이름 또는 행 인덱스에 데이터를 저장하면 기존 데이터가 갱신.

# 행 추가
students["H",] <- c(80, 10, "M", '홍태균')
tail(students)
  no age gender name
C 30 13       M 이훈
D 40 12       M 서희
E 50 10       M 승희
F 60  9       F 하정
G 70  7       M 하준
H 80  10      M 홍길동

 

2.3.4 배열(array)

다차원 데이터 저장 구조.

벡터나 행렬처럼 하나의 원시 데이터 타입으로 저장.

array()로 배열을 만듬.

var1 <- c(1:12)
var1
[1] 1 2 3 4 5 6 7 8 9 10 11 12

# 3차원 배열 생성
arr1 <- array(var1, dim = c(2, 2, 3))
arr1
, , 1

    [, 1] [, 2]
[, 1]  1     3
[, 2]  2     4

, , 2

    [, 1] [, 2]
[, 1]  5     7
[, 2]  6     8

, , 3

    [, 1] [, 2]
[, 1]  9    11
[, 2] 10    12

arr2 <- array(var1, dim = c(6,2)) # 2차원 배열
arr3 <- array(var1, dim = c(2,2,2,2)) # 4차원 배열

 

2.3.5 리스트(list)

다차원 데이터 저장 구조.

배열과 다른 점은 키와 값 쌍으로 저장되며 값에 해당하는 데이터가 벡터, 행렬, 리스트 등 어떠한 데이터 구조의 데이터도 가능.

list()로 리스트 생성.

v_data <- c("08-111-2222", "01022223333")           # 벡터
m_data <- matrix(c(21:36), nrow = 2)                # 행렬
a_data <- array(c(31:36), dim = c(2, 2, 2))         # 배열
d_data <- data.frame(address = c("seoul", "busan"), # 데이터프레임
                     name = c("Lee", "Kim"),
                     stringsAsFactors = F)

생성한 다양한 데이터 구조에 담긴 데이터를 리스트에 저장하는 예.

# list(키1 = 값, 키2 = 값, ..., )와 같이 키와 값 쌍으로 리스트 생성.
list_data <- list(name = "홍길동",   # name 키에 "홍길동" 값 저장
                  tel = v_data,      # tel 키에 v_data 값 저장
                  score1 = m_data,   # score1 키에 m_data 값 저장
                  score2 = a_data,   # score2 키에 a_data 값 저장
                  friends = d_data)  # friends 키에 d_data 값 저장

리스트의 일부 데이터에 접근

# 리스트이름$키
list_data$name     # list_data에서 name키와 쌍을 이루는 값
[1] "홍길동"
list_data$tel      # list_data에서 tel키와 쌍을 이루는 값
[1] "02-111-2222" "01022223333"

# 리스트이름[숫자]
list_data[1]       # list_data에서 첫 번째 서브 리스트
$name
[1] "홍길동"