티스토리 뷰
데이터 프레임(date frame) 중요!!!
데이터 프레임은 엑셀 시트와 유사한 표 형태를 가진 데이터 구조입니다.
데이터 프레임은 행, 열 구조로, 각 열은 서로 다른 데이터 타입을 가질 수 있습니다.
data.frame(data, stringsAsFactors = T)
데이터 프레임 형성 시 stringsAsFactors 옵션이 default값 TRUE로 설정됩니다.
stringsAsFactor 생략 시 문자열은 무조건 팩터로 저장되는데, 그렇게되면 row(행)를 추가할 수 없게됩니다.
만일 데이터 프레임을 생성한 후 행을 더 추가할 필요가 있다면 stringsAsFactor 옵션을 FALSE로 해주어야겠죠?
데이터 프레임는 행렬(Matrix)과 출력 결과가 다를 뿐, Key-Value를 갖고 리스트와 문법이 비슷합니다.
다만 행렬(Matrix)과 다른 점은 서로 다른 타입의 데이터를 저장할 수 있다는 것, 그리고 행 번호가 자동으로 부여되는 것.
# data frame 생성
> no <- c(1,2,3,4)
> name <- c('apple', 'banana','peach','berry')
> price <- c(500,200,200,50)
> qty <- c(5,2,7,9)
> df1 <- data.frame(no = no, name = name, price = price, qty = qty) # stringsAsFactors 생략 시 TRUE
> df1
no name price qty
1 1 apple 500 5
2 2 banana 200 2
3 3 peach 200 7
4 4 berry 50 9
# 오라클에서 desc 함수로 테이블 구조를 확인했죠?! R에서는 str 함수로 데이터 프레임의 구조 확인합니다.
> str(df1)
'data.frame': 4 obs. of 4 variables: # 4개의 관측치(행), 4개의 변수(컬럼)
$ no : num 1 2 3 4
$ name : Factor w/ 4 levels "apple","banana",..: 1 2 4 3
# stringsAsFactors 가 TRUE 이므로 문자열인 name컬럼이 factor형으로 저장
# factor형으로 생성 시 컬럼의 그룹별 분석이 가능하다면 좋지만, 추가할 데이터가 있을 시 삽입이 불가하다는 점!
$ price: num 500 200 200 50
$ qty : num 5 2 7 9
데이터 프레임(date frame) 행 추가
> rbind(df1,c(5,'mango',100,10)) # rbind로 행 추가
no name price qty
1 1 apple 500 5
2 2 banana 200 2
3 3 peach 200 7
4 4 berry 50 9
5 5 <NA> 100 10 # factor형 level로 선언되지 않은 값은 NA처리
Warning message: # mango는 데이터 프레임 생성 시 지정된 name의 factor가 아니므로 삽입이 불가합니다.
In `[<-.factor`(`*tmp*`, ri, value = "mango") :
요인의 수준(factor level)이 올바르지 않아 NA가 생성되었습니다.
# 해결방법
# 1. data frame 생성 시 문자열 컬럼을 factor형으로 생성하지 않기
# 가공 없이 바로 분석에 사용할 데이터가 아닌 이상, 데이터 가공을 위해 왠만하면 stringsAsFactors를 FALSE로 해주는게 좋습니다.
# 추후 분석에 factor형이 필요하다면 분석 직전에 factor형으로 변환해주면 됩니다.
> df2 <- data.frame(no = no, name = name, price = price, qty = qty,
+ stringsAsFactors = F)
> str(df2)
'data.frame': 4 obs. of 4 variables:
$ no : num 1 2 3 4
$ name : chr "apple" "banana" "peach" "berry"
$ price: num 500 200 200 50
$ qty : num 5 2 7 9
> df2 <- rbind(df2,c(5,'mango',100,10)) # rbind로 행 추가
> df2 # name 컬럼이 factor 형식이 아니므로 행 추가 가능
no name price qty
1 1 apple 500 5
2 2 banana 200 2
3 3 peach 200 7
4 4 berry 50 9
5 5 mango 100 10
# 2. 이미 생성된 data frame의 factor형 컬럼을 일반 문자열 컬럼으로 변경
# 데이터 프레임은 컬럼이 키 구조를 가지고 있으므로 키 형식으로 색인이 가능합니다.
> df1$name <- as.character(df1$name) # data frame 생성 시 factor 형으로 저장된 name 컬럼을 문자형으로 변환
> str(df1)
'data.frame': 4 obs. of 4 variables:
$ no : num 1 2 3 4
$ name : chr "apple" "banana" "peach" "berry"
$ price: num 500 200 200 50
$ qty : num 5 2 7 9
> df1 <- rbind(df1,c(5,'mango',100,10))
> df1
no name price qty
1 1 apple 500 5
2 2 banana 200 2
3 3 peach 200 7
4 4 berry 50 9
5 5 mango 100 10 # factor형 컬럼을 문자형 컬럼으로 변환 후 데이터 추가
# 3. 이미 생성된 data frame의 문자열 컬럼을 factor형으로 변경
> df1$name <- factor(df1$name) # 다시 문자형 컬럼을 factor형 컬럼으로 변환
> str(df1)
'data.frame': 5 obs. of 4 variables:
$ no : chr "1" "2" "3" "4" ...
$ name : Factor w/ 5 levels "apple","banana",..: 1 2 5 3 4
$ price: chr "500" "200" "200" "50" ...
$ qty : chr "5" "2" "7" "9" ...
# factor가 적용된 df1 에서 banana 를 대문자로 변경
> df1[2,2] <- 'BANANA'
Warning message:
In `[<-.factor`(`*tmp*`, iseq, value = "BANANA") :
invalid factor level, NA generated
> df1
no name price qty
1 1 apple 500 5
2 2 <NA> 200 2 # factor가 적용된 상태에서 데이터를 변경하게되면 데이터가 NA로 변경되어버립니다.
3 3 peach 200 7
4 4 berry 50 9
5 5 mango 100 10
# factor가 적용되어있다면, 다시 문자형으로 변환 후 데이터를 변경해주어야 합니다.
> df1$name <- as.character(df1$name) # 일반 문자열 컬럼으로 변경
> df1[df1$name == 'banana','name'] <-'BANANA' # 다시 수정
> df1
no name price qty
1 1 apple 500 5
2 2 BANANA 200 2
3 3 peach 200 7
4 4 berry 50 9
5 5 mango 100 10
데이터 프레임(date frame) 컬럼 추가
# 컬럼 추가
> df1$area <- c('a','b','c','a','b')
> str(df1) # 컬럼 추가 시에는 문자열 컬럼이 factor로 생성되지 않습니다.
'data.frame': 5 obs. of 5 variables:
$ no : chr "1" "2" "3" "4" ...
$ name : chr "apple" "BANANA" "peach" "berry" ...
$ price: chr "500" "200" "200" "50" ...
$ qty : chr "5" "2" "7" "9" ...
$ area : chr "a" "b" "c" "a" ...
> df1 <- cbind(df1,c('a','b','c','a','b')) # 하지만! cbind함수로 문자열 컬럼 생성 시 factor로 생성
> str(df1)
'data.frame': 5 obs. of 6 variables:
$ no : chr "1" "2" "3" "4" ...
$ name : chr "apple" "BANANA" "peach" "berry" ...
$ price : chr "500" "200" "200" "50" ...
$ qty : chr "5" "2" "7" "9" ...
$ area : chr "a" "b" "c" "a" ...
$ c("a", "b", "c", "a", "b"): Factor w/ 3 levels "a","b","c": 1 2 3 1 2
> df1
no name price qty area c("a", "b", "c", "a", "b")
1 1 apple 500 5 a a
2 2 BANANA 200 2 b b
3 3 peach 200 7 c c
4 4 berry 50 9 a a
5 5 mango 100 10 b b
컬럼과 행의 이름 지정(행렬과 같은 방법)
> x <- data.frame(1:5)
> x
X1.5
1 1
2 2
3 3
4 4
5 5
> colnames(x) <- 'val' # 컬럼 이름 지정
> rownames(x) <- c('a','b','c','d','e') # 행 이름 지정
> x
val
a 1
b 2
c 3
d 4
e 5
차원의 축소 : 높은 차원에서 낮은 차원으로 데이터가 변경되서 출력되는 현상
# (3차원 -> 2차원) 또는(2차원 -> 1차원)
> dim(df1)
[1] 5 6 # 2차원(5행x6열)
> df1$name # 2차원 구조이지만 1차원으로 출력 (단 하나의 행, 컬럼은 1차원으로 출력 가능하므로 자체적으로 차원을 축소)
[1] "apple" "BANANA" "peach" "berry" "mango"
# 차원 축소를 원치 않는 경우 drop 옵션을 F로 설정(단, 색인 기호의 맨 마지막 인자에 옵션으로 넣어줘야합니다.)
> df1[,'name',drop = F]
name
1 apple
2 BANANA
3 peach
4 berry
5 mango
# 참고. 파이썬에서는 슬라이스옵션을 통해 방지 m1[,2:2]
#차원의 축소를 사용해야하는 경우 => 교차곱
> m1 <- matrix(1:20, c(4,5))
> m1
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
[3,] 3 7 11 15 19
[4,] 4 8 12 16 20
> m1[1,]
[1] 1 5 9 13 17
> m1 %*% m1[1,] # (4x5)*(5x1)
[,1]
[1,] 565
[2,] 610
[3,] 655
[4,] 700
데이터 프레임의 색인(행렬과 동일)
> df2
no name price qty
1 1 apple 500 5
2 2 banana 200 2
3 3 peach 200 7
4 4 berry 50 9
5 5 mango 100 10
> df2[1,] # 1번째 행 출력
no name price qty
1 1 apple 500 5
> df2[c(1,5),2] # 1,5번째 행의 2번째 컬럼 출력
[1] "apple" "mango"
> df2[-5,-4] # 5번째 행과 4번째 컬럼을 제외한 데이터 출력
no name price
1 1 apple 500
2 2 banana 200
3 3 peach 200
4 4 berry 50
> df2[,c('name','price')] # 이름색인
name price
1 apple 500
2 banana 200
3 peach 200
4 berry 50
5 mango 100
# %in% 연산자
# 이름이 apple과 peach인 행 선택. Oracle = where name in ('apple','peach')
# 사용 목적에 알맞는 방법을 선택
> c('apple','peach') %in% df2$name # apple과 peach가 name 컬럼에 있는지 여부 확인
[1] TRUE TRUE
> df2$name %in% c('apple','peach') # name의 각 행이 c('apple','peach')에 있는지 여부 확인
[1] TRUE FALSE TRUE FALSE FALSE #
> !df2$name %in% c('apple','peach') # 특정 컬럼 제외
[1] FALSE TRUE FALSE TRUE TRUE
데이터 프레임의 유용한 함수
> colnames(df2) # 어떤 데이터 구조도 사용 가능
[1] "no" "name" "price" "qty"
> names(df2) # 벡터랑 data frame에서 사용 가능
[1] "no" "name" "price" "qty"
head(객체, 결과 값의 크기) : 객체 처음부분 미리보기(대량의 데이터 사용 시)
> head(df2, 2) # 앞에서 2번째 행까지만 출력
no name price qty
1 1 apple 500 5
2 2 banana 200 2
tail(객체, 결과 값의 크기) : 객체 뒷부분 미리보기(대량의 데이터 사용 시)
> tail(df2,2) # 뒤에서 2번째 행까지만 출력
no name price qty
4 4 berry 50 9
5 5 mango 100 10
View(객체) : 데이터 프레임을 뷰어를 통해 출력
> View(df2)
class(객체) : 데이터 타입(구조) 확인
> class(df2) # 데이터 타입 혹은 구조 확인
[1] "data.frame"
> class(c('apple','banana'))
[1] "character"
str(객체) : 데이터 구조 확인
> str(df2)
'data.frame': 5 obs. of 4 variables:
$ no : chr "1" "2" "3" "4" ...
$ name : chr "apple" "banana" "peach" "berry" ...
$ price: chr "500" "200" "200" "50" ...
$ qty : chr "5" "2" "7" "9" ...
Q.
> getwd() # 작업 디렉토리 확인
> emp <- read.csv('emp.csv') # 외부 csv파일 불러오기
> str(emp)
'data.frame': 14 obs. of 8 variables:
$ EMPNO : int 7369 7499 7521 7566 7654 7698 7782 7788 7839 7844 ...
$ ENAME : Factor w/ 14 levels "ADAMS","ALLEN",..: 12 2 14 7 9 3 4 11 8 13 ...
$ JOB : Factor w/ 5 levels "ANALYST","CLERK",..: 2 5 5 3 5 3 3 1 4 5 ...
$ MGR : int 7902 7698 7698 7839 7698 7839 7839 7566 NA 7698 ...
$ HIREDATE: Factor w/ 13 levels "1980-12-17 0:00",..: 1 2 11 3 7 4 5 12 8 6 ...
$ SAL : int 800 1600 1250 2975 1250 2850 2450 3000 5000 1500 ...
$ COMM : int NA 300 500 NA 1400 NA NA NA NA 0 ...
$ DEPTNO : int 20 30 30 20 30 30 10 20 10 30 ...
> emp
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
1 7369 SMITH CLERK 7902 1980-12-17 0:00 800 NA 20
2 7499 ALLEN SALESMAN 7698 1981-02-20 0:00 1600 300 30
3 7521 WARD SALESMAN 7698 1982-02-22 0:00 1250 500 30
...
13 7902 FORD ANALYST 7566 1981-12-03 0:00 3000 NA 20
14 7934 MILLER CLERK 7782 1982-01-23 0:00 1300 NA 10
# 1. empno가 7900인 사원의 이름, sal 출력
> emp[emp$EMPNO == 7900, c('ENAME','SAL')]
ENAME SAL
12 JAMES 950
# 2. 1월에 입사한 사람의 이름, 입사일, 연봉 출력
> as.character(as.Date(emp$HIREDATE,'%Y-%m-%d %H:%M'),'%m')
[1] "12" "02" "02" "04" "09" "05" "06" "04" "11" "09" "05" "12" "12" "01"
> as.character(as.Date(emp$HIREDATE,'%Y-%m-%d %H:%M'),'%m') == '01'
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
> emp[as.character(as.Date(emp$HIREDATE,'%Y-%m-%d %H:%M'),'%m') == '01', c('ENAME','HIREDATE','SAL')]
ENAME HIREDATE SAL
14 MILLER 1982-01-23 0:00 1300
# 3. SMITH와 SCOTT의 연봉 출력
> emp[emp$ENAME == 'SMITH' | emp$ENAME == 'SCOTT', c('ENAME','SAL')]
ENAME SAL
1 SMITH 800
8 SCOTT 3000
> emp[emp$ENAME %in% c('SMITH','SCOTT'), c('ENAME','SAL')]
ENAME SAL
1 SMITH 800
8 SCOTT 3000
# 4. 다음의 계산식으로 퇴직금 계산 후 R_PAY 컬럼으로 추가
(퇴직금 = 현재 SAL * trunc(근속년수/12))
> var1 <- Sys.Date() - as.Date(emp$HIREDATE,'%Y-%m-%d %H:%M') # 총 근무일수
> wyear <- trunc(var1/365)
> class(var1)
[1] "difftime"
> emp$R_PAY <-as.numeric(emp$SAL * trunc(wyear/12))
> emp
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO R_PAY
1 7369 SMITH CLERK 7902 1980-12-17 0:00 800 NA 20 2400
2 7499 ALLEN SALESMAN 7698 1981-02-20 0:00 1600 300 30 4800
3 7521 WARD SALESMAN 7698 1982-02-22 0:00 1250 500 30 3750
...
12 7900 JAMES CLERK 7698 1981-12-03 0:00 950 NA 30 2850
13 7902 FORD ANALYST 7566 1981-12-03 0:00 3000 NA 20 9000
14 7934 MILLER CLERK 7782 1982-01-23 0:00 1300 NA 10 3900
관련 참고 글
[R] 리스트(list) <- Key-value 형태로 저장되는 데이터 구조
[R] 행렬(Matrix) <- 행과 열의 구조를 갖는 2차원 배열 구조
[R] 배열(Array) <- 동일한 데이터 타입으로 구성된 다차원 데이터구조
[R] 데이터 프레임(Date Frame) <- 엑셀 시트와 유사한 표 형태를 가진 데이터 구조
참고: KIC 캠퍼스 머신러닝기반의 빅데이터분석 양성과정
'R > Process' 카테고리의 다른 글
[R] 조건문 - if, else if, ifelse (0) | 2018.12.31 |
---|---|
[R] 데이터 타입 변환 함수 (0) | 2018.12.27 |
[R] 배열(Array) (0) | 2018.12.27 |
[R] 행렬(Matrix) (0) | 2018.12.26 |
[R] 리스트(list) (0) | 2018.12.26 |