> ## Content Index
> Fetch the complete content index at: https://www.popit.kr/llms.txt
> Use this file to discover other available public pages before exploring further.

# 개발자가 배우는 R : 3강, 데이터프레임과 파일 입출력
- URL: https://www.popit.kr/developer-learns-r-3-dataframe-file-io/
- Published: 2017-03-27T23:00:28.000Z
- Updated: 2017-03-28T00:15:23.000Z
- Author: 광식 이
- Tags: #소프트웨어, R, #데이터분석, 머신러닝, 알, 기계학습, 통계분석

# 개요

**이번 포스팅에는 R의 객체중 factor와 데이터 프레임을 배우고 파일 import, export를 배워본다.** 객체 자체는 지난 시간에 다뤘지만 리스트와 데이터 프레임은 파일 import/export와 연관이 많아 이번 시간에 설명한다. 코드중심의 설명이기 때문에 본문 보다는 코드의 주석이 집중적으로 추가되어 있으니 참고 바란다.

# R 자료구조(factor, 데이터프레임)

## factor

설문조사의 객관식 처럼 순서와 카테고리가 정해져 있는 자료구조를 factor라고 한다.  

```r
> x <- c(5, 12, 13, 12) # 벡터를 factor로 변환하면 고유값만 가지게 정리된다.
> xf <- factor(x)
> xf
[1] 5  12 13 12
Levels: 5 12 13
 
> xff <- factor(x, levels=c(5,12,13,88)) # levels를 명시적 옵션으로 줄 수 있다.
> xff
[1] 5  12 13 12
Levels: 5 12 13 88
 
> xff[2] <- 88 # xff의 2번째 값을 88로 할당을 바꿈, 레벨 안에서 값의 위치만 바뀜
> xff
[1] 5  88 13 12
Levels: 5 12 13 88
 
> xff[2] <- 28 # 왼쪽과 같이 level값에 없는 것을 지정하면 warning이 발생한다.
Warning message:
In `[<-.factor`(`*tmp*`, 2, value = 28) :
  invalid factor level, NA generated
> xff
[1] 5    <NA> 13   12  
Levels: 5 12 13 88
```

## 리스트

하나의 객체 안에 벡터, 행렬, factor, list등 여러가지 데이터 구조를 담을수 있는 컬렉션 데이터 구조

### 리스트 생성

```r
> j <- list(name="Joe", salary=55000, union=TRUE) # 문자열, 정수, boolean값이 섞여서 들어간다.
 
> j
$name
[1] "Joe"
 
$salary
[1] 55000
 
$union
[1] TRUE
```

### 리스트 원소 접근

원소의 접근은 아래와 같은 방식으로 접근 가능하다.  

```r
> j$salary
[1] 55000
 
> j[["salary"]] # 리스트는 반드시 중괄호를 2개 써야함
[1] 55000
 
> j[[2]]
[1] 55000
```

**주의 할 점은 리스트의 원소값에 접근할때는 \[\]이 아니라 \[\[\]\]를 사용해야 한다는 점이다.** \[\] 기호를 하나만 쓰면 부분 리스트(sub list)로 인식된다.  

```r
> j["salary"] # j[2]는 key, value인 Salary, 55000이 담겨있는 것을 확인 할 수 있다.
$salary
[1] 55000
 
> class(j[2])
[1] "list"
 
> class(j[[2]])
[1] "numeric"
```

### 리스트에 원소 추가

```r
> j$age <- 28 # same as j[["age"]] <- 28
 
> j
$name
[1] "Joe"
 
$salary
[1] 55000
 
$union
[1] TRUE
 
$age
[1] 28
아래와 같이 NULL값으로 원소를 초기화 할 수 있다.

> j$age <- NULL
 
> j
$name
[1] "Joe"
 
$salary
[1] 55000
 
$union
[1] TRUE
```

### 리스트 크기 알아내기

```r
> length(j)
    [1] 3
```

### Apply

리스트도 apply 함수 적용이 가능하다. 코드예제를 보자.  

```r
> x <- list(1:3, 25:29) # 아래와 같이 값이 들어가 있는 리스트를 생성함
 
> x
[[1]]
[1] 1 2 3
 
[[2]]
[1] 25 26 27 28 29
 
> lapply(x, median) # 리스트용 apply 함수, 각각의 index별로 평균을 구함
[[1]]
[1] 2
 
[[2]]
[1] 27
 
> sapply(x, median) # simplified된 lapply 함수
[1]  2 27
```

## Data Frame

데이터 프레임은 행렬과 같은 2차원은 행과 열을 가지는 자료구조이다. 그러나 행렬과 다른점은 각각은 칼럼들은 다른 데이터 타입을 가질 수 있다. 데이터 프레임은 R에서 가장 자주쓰는 자료구조로써 외부 파일을 불러와서 등에서 많이 사용한다.

### 데이터 프레임 생성

```r
> kids <- c("Jack", "Jill")
 
> ages <- c(12, 10)
 
> d <- data.frame(kids, ages)
 
> d
  kids ages
1 Jack   12
2 Jill   10
```

데이터 프레임을 만들때 문자열을 factor로 보지 않게 만드려면 아래와 같이 옵션을 지정해 주면 된다.

```r
> d <- data.frame(kids, ages, stringsAsFactors=FALSE)
```

### 데이터 프레임 원소 접근

데이터 프레임의 원소 접근은 리스트의 원소 접근과 동일하다.

```r
> d[[2]]
[1] 12 10
 
> d$ages
[1] 12 10
```

또한 행렬과 같이 행/렬 개념으로 원소 접근을 할수도 있다.

```r
> d[,2]
[1] 12 10
```

일부 데이터 원소 접근은 행렬 원소 접근 방식만 알고 있으면 새로울 것이 없다.

```r
> exam1 <- c(2.0, 3.3, 4.0, 2.3, 2.3, 3.3)
> exam2 <- c(3.3, 2.0, 4.0, 0.0, 1.0, 3.7)
> exams <- data.frame(exam1, exam2)
> exams
  exam1 exam2
1   2.0   3.3
2   3.3   2.0
3   4.0   4.0
4   2.3   0.0
5   2.3   1.0
6   3.3   3.7
 
> exams[2:5,]
  exam1 exam2
2   3.3     2
3   4.0     4
4   2.3     0
5   2.3     1
 
> exams[exams$exam1 >= 3.0,] # exam1이 3.0보다 큰 행, 모든 열을 가져온다.
  exam1 exam2
2   3.3   2.0
3   4.0   4.0
6   3.3   3.7
 
> subset(exams, exams$exam1 >= 3.0) # exam1이 3.0 이상인 데이터 셋으로 서브셋을 만들어 냄
  exam1 exam2
2   3.3   2.0
3   4.0   4.0
6   3.3   3.7
 
> subset(exams, exam1 >= 3.0) # 바로 위 수식을 더 간단하게 왼쪽과 같이 더 많이 사용한다.
  exam1 exam2
2   3.3   2.0
3   4.0   4.0
6   3.3   3.7
```

### 데이터 프레임에 원소 추가

```r
> rbind(d, data.frame(kids="Laura", ages=19))
       kids ages
    1  Jack   12
    2  Jill   10
    3 Laura   19    

    > diff <- exams$exam2-exams$exam1 # exam2와 exam1의 차이를 diff 벡터로 만듦
    > eq <- cbind(exams, diff) # exams에 diff로 열을 붙임
    > eq
      exam1 exam2 diff
    1   2.0   3.3  1.3
    2   3.3   2.0 -1.3
    3   4.0   4.0  0.0
    4   2.3   0.0 -2.3
    5   2.3   1.0 -1.3
    6   3.3   3.7  0.4

```

### 

### 데이터 프레임에 Apply 함수 적용하기

행렬때와 동일하다.

```r
> apply(exams, 1, mean) # 행별 적용
[1] 2.65 2.65 4.00 1.15 1.65 3.50
 
> apply(exams, 2, mean) # 열별 적용
   exam1    exam2
2.866667 2.333333
```

### 데이터 프레임 Merge

kids 값을 기준으로 매칭하여 merge 한다. DB의 inner join으로 이해하면 된다.

```r
>  kids <- c("Jack", "Jill", "Jillian", "John")
> states <- c("CA", "MA", "MA", "HI")
>  d1 <- data.frame(kids, states)
> d1
     kids states
1    Jack     CA
2    Jill     MA
3 Jillian     MA
4    John     HI
 
> ages <- c(10, 7, 12)
>  kids <- c("Jill", "Jillian", "Jack")
>  d2 <- data.frame(ages, kids)
 
>  d <- merge(d1, d2)
> d
     kids states ages
1    Jack     CA   12
2    Jill     MA   10
3 Jillian     MA    7
```

merge시에 서로 일치하는 key값으로 쓰일 칼럼명을 찾지 못할 경우 명시적으로 각 데이터 프레임에서 어떤것을 key으로 쓸지 명시 할 수 있다.  

```r
>  ages <- c(12, 10, 7)
>  pals <- c("Jack", "Jill", "Lillian")
> d3 <- data.frame(ages, pals)
> merge(d1, d3, by.x="kids", by.y="pals")
  kids states ages
1 Jack     CA   12
2 Jill     MA   10
```

# R에서 파일 다루기

## 외부 데이터 파일 import

외부 데이터 불러오기를 실습하기 위한 샘플 파일은 [github](https://github.com/lks21c/r%5Fsample%5Fdata/tree/master/file%5Fload?ref=popit.kr)에 올려두었다. 아래의 필자의 경로는 무시하고 파일명은 동일하니 활용하면 되겠다.

### TXT 파일 import

외부 데이터 파일을 불러오는 문법은 아래와 같다. 하지만 많이 쓰는 방식은 아니다.

```r
> records <- read.fwf("filename", widths=c(w1, w2, ..., wn))
고정너비는 아래와 같이 사용하면 되는데 자주 사용하는 방법은 아니다.

> records <- read.fwf("file:///home/lks21c/Downloads/ch2_1/fixed-width.txt", widths=c(10, 10, 4, -1, 4))
> records
          V1         V2   V3   V4
1 Fisher     R.A.       1890 1962
2 Pearson    Karl       1857 1936
3 Cox        Gertrude   1900 1978
4 Yates      Frank      1902 1994
5 Smith      Kirstine   1878  193
```

칼럼 이름까지 지정하는 것은 아래와 같다.

```r
> records <- read.fwf("file:///home/lks21c/Downloads/ch2_1/fixed-width.txt", widths=c(10, 10, 4, -1, 4),col.names=c("Last", "First", "Born", "Died") )
> records
        Last      First Born Died
1 Fisher     R.A.       1890 1962
2 Pearson    Karl       1857 1936
3 Cox        Gertrude   1900 1978
4 Yates      Frank      1902 1994
5 Smith      Kirstine   1878  193
```

### 데이터프레임으로 파일 import

데이터 프레임으로 불러오는 문법이다.

```r
> dfrm <- read.table("filename", sep="") # sep는 구분자로 쓸 문자열을 의미한다.
```

데이터 프레임으로 직접 불러오는 코드를 실행해 보자.

```r
> dfrm <- read.table("file:///home/lks21c/Downloads/ch2_1/statisticians.txt", sep="")
> dfrm
       V1       V2   V3   V4
1  Fisher     R.A. 1890 1962
2 Pearson     Karl 1857 1936
3     Cox Gertrude 1900 1978
4   Yates    Frank 1902 1994
5   Smith Kirstine 1878 1939
```

칼럼명을 포함하여 불러오는 방법은 아래와 같다.

```r
> dfrm <- read.table("file:///home/lks21c/Downloads/ch2_1/statisticians.txt", header=TRUE, sep="")
> dfrm
   Fisher     R.A. X1890 X1962
1 Pearson     Karl  1857  1936
2     Cox Gertrude  1900  1978
3   Yates    Frank  1902  1994
4   Smith Kirstine  1878  1939
```

### CSV 파일 import

R에서 가장 많이 사용하는 방식이다. CSV를 불러오는 방법은 아래와 같다. **일반적으로 엑셀파일을 CSV로 변환하여 R에서 불러서 많이 쓴다.**

```r
> tbl <- read.csv("filename")
 
> tbl <- read.csv("filename", header=FALSE)
```

위의 문법대로 실제로 CSV를 한번 불러보자.

```r
> tbl <- read.csv("file:///home/lks21c/Downloads/ch2_1/table-data_h.csv")
> tbl
  label lbound ubound
1   low  0.000  0.674
2   mid  0.674  1.640
3  high  1.640  2.330
 
> tbl <- read.csv("file:///home/lks21c/Downloads/ch2_1/table-data_h.csv", header=FALSE)
> tbl
     V1     V2     V3
1 label lbound ubound
2   low      0  0.674
3   mid  0.674   1.64
4  high   1.64   2.33
```

## CSV 파일로 export

문법은 아래와 같다.

```r
> write.csv(x, file="filename")
```

위의 문법대로 csv로 저장해보자.

```r
> write.csv(tbl, file="/home/lks21c/Downloads/ch2_1/write.csv", row.names=FALSE)
```

## Foreign 패키지

위에서 언급하지 않은 특수한 파일형식을 불러와야 한다면 R에서 제공하는 foreign 패키지를 참조하면 된다.

![](http://www.kwangsiklee.com/wp-content/uploads/2017/03/r_week3_0100.png)