티스토리 뷰

반응형

데이터 프레임(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인 행 선택. Oraclewhere 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] 스칼라(scalar) + NA, NULL <- 단일 차원의 값(단 하나의 원소값)


[R] 팩터 (factor) <- 범주형 데이터(정의되어있는 카테고리)를 표현하기 위한 데이터 구조


[R] 벡터(vector) <- 1차원에 여러개의 데이터가 모인 데이터의 집합(스칼라의 모임)(=배열)

    

[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
댓글
최근에 올라온 글
최근에 달린 댓글
링크
Total
Today
Yesterday