데이터분석/R

R언어 공부 - 1

환성 2022. 12. 26. 15:47
728x90

R은 동적 타입 언어(Dynamically typed language)이기 때문에 변수의 자료형을 마음대로 바꿀 수 있다는 장점이 있다. 

또한 다양한 통계, 시각화 패키지들이 존재하여 손쉽게 꺼내쓸 수 있다는 점이다. 또한 오픈소스이고 직관적이고 쉽게 데이터 전처리가 가능하다는 점이다.

하지만 단점으로는 모든 데이터를 메모리에 로딩한 후 처리하기에 속도 측면에서 불리하다. 불필요한 데이터 저장으로 메모리 부족 현상이 일어난다.

 

 

1) Cat 

cat 함수는 print의 대안으로, 여러 개의 항목을 묶어서 출력할 때 쓰임

추가로 한 줄을 끝내고 싶을 때에는 \n 개행 문자 삽입

하지만 행렬이나 리스트 같은 데이터 구조는 출력할 수 없다는 점 

> cat(pi, 2*pi, sqrt(3))
3.141593 6.283185 1.732051

# 하지만 행렬이나 리스트 같은 데이터 구조는 출력 불가능
> cat(list("a", "b", "c"))
Error in cat(list("a", "b", "c")) : 
  argument 1 (type 'list') cannot be handled by 'cat'

 

 

2) ls, ls.str()

변수들의 목록을 보고 싶을 때에는 ls 함수를 사용

ls.str()로 각 변수의 자세한 내용을 볼 수 있다. 만약 작업공간이 비어 있는 경우에서 ls함수를 사용 시 character(0)을 반환한다. 즉 작업공간에 정의 된 것이 없기에 빈 벡터를 반환한다.

# ls함수를 사용하여 변수 목록을 볼 수 있다.
# 더 자세하게 보려면 ls.str()
> x <- 10
> y <- 50
> z <- c("three", "blind", "mice")
> f <- function(n, p) sqrt(p * (1-p) / n)

> ls()
 [1] "airquality" "economics"  "exdata1"    "f"          "fib"       
 [6] "geo_code"   "geo_data"   "gg_daejeon" "gr_cyl"     "idx"       
[11] "melt_test"  "mp_rank"    "mtcars"     "pre.rf"     "r.f"       
[16] "test.data"  "train.data" "x"          "x_inter"    "y"         
[21] "z"

> ls.str()
x :  num 10
x_inter :  Date[1:1], format: "2005-07-01"
y :  num 50
z :  chr [1:3] "three" "blind" "mice"

 

3) 벡터 생성 c(...)

벡터를 생성할 떄 c(...) 연산자를 사용

벡터는 숫자, 문자열, 논리값 중 한 가지만 포함하고 이들을 서로 섞어서 쓸 순 없다, 섞는 경우 둘 중 하나의 데이터 형식으로 통일 된다.

추가적으로 c는 제네릭 연산자로써, 벡터뿐만 아니라 다른 많이 데이터 형식과도 작동한다는 것이다.

# c(...) 연산자를 이용하여 생성
# 벡터는 숫자, 문자열, 논리값 중 한 가지만 포함하여 이들을 섞을 수 X
> c(1,1,2,3,5,8,13,21)
[1]  1  1  2  3  5  8 13 21
> c(TRUE,TRUE,FALSE)
[1]  TRUE  TRUE FALSE

# 벡터 하나로 합치기
> v1 <- c(1,2,3)
> v2 <- c(4,5,6)
> c(v1, v2)
[1] 1 2 3 4 5 6

# 데이터 형식을 섞어서 만들 수는 없음, 섞는다면 둘 중 하나로 데이터 형식이 통일됨
> v1 <- c(1,2,3)
> v3 <- c("A", "B", "C")
> c(v1,v3)
[1] "1" "2" "3" "A" "B" "C"  # 문자열로 통일됨

 

4) 통계량 확인

통계량을 알아보고 싶을 떄에는 mean, sd, cor, median 등 함수를 사용하면 된다

# 산술평균 : mean(x)  표준편차 : sd(x)  상관계수 : cor(x,y)
# 중앙값 : median(x)  분산 : var(x)    공분산 : cov(x,y)

> x <- c(0,1,1,2,3,5,8,13,21,34)
> mean(x)
[1] 8.8
> median(x)
[1] 4
> sd(x)
[1] 11.03328
> var(x)
[1] 121.7333

# 상관계수, 공분산
> x <- c(0,1,1,2,3,5,8,13,21,34)
> y <- log(x + 1)
> cor(x,y)
[1] 0.9068053
> cov(x,y)
[1] 11.49988

# 결측치 : NA, 결측치 포함시 모든 함수에서 NA 반환
> x <- c(0,1,1,2,NA)
> mean(x)
[1] NA

# na.rm = TRUE로 결측치 제거
> x <- c(0,1,1,2,NA)
> mean(x, na.rm=TRUE)
[1] 1

 

5) 수열 생성

수열을 생성할 때에는 :, rep, seq를 쓴다

숫자 : 숫자 사용시에는 공차가 1인 등차수열을 만들 수 있고 역으로도 가능하다

rep의 의미는 repetition 반복한다는 의미로, 특정값을 반복할 떄 쓰인다.

추가로 rep은 숫자 뿐만 아니라 문자열도 반복이 가능하다.

seq은 시작숫자, 끝 숫자를 정해주면 숫자를 생성한다. from과 to인자를 통해 시작과 끝을 정하고 

length.out을 통해 값 길이를 지정할 수 있다.

# n:m 표현식을 사용
> 1:5
[1] 1 2 3 4 5
> 5:1
[1] 5 4 3 2 1

# 1이 아닌 수치로 증가하는 수열에는 seq 함수 사용
> seq(from = 1, to = 5, by = 2)
[1] 1 3 5

# rep 함수를 사용해 반복되는 값들로 된 수열 생성
> rep(1, times = 10)
 [1] 1 1 1 1 1 1 1 1 1 1

# 수열 결과 값 길이 지정
> seq(from = 0, to = 7, length.out = 6)
[1] 0.0 1.4 2.8 4.2 5.6 7.0

6) 벡터에 있는 원소 선택하기

주로 인덱스를 사용하는 방법이 있다.

예를 들어 v의 4번쨰 원소를 선택하려면 v[4]

여기서 중요한 점은 python이나 다른 인덱스 처럼 인덱스가 0부터 시작하는게 아닌 1부터 시작한다는 점이다.

원소를 제외할 떄에는 인덱스를 음수로 쓰고 이름이 붙여진 원소에 접근하려면 이름을 사용하면 된다.

# 원소 선택시 인덱스 사용[]
# 이름 붙여진 원소에 접근하려면 이름을 사용
# 원소를 제외하고 싶으면 인덱스를 음수로 씀
> fib <- c(0,1,1,2,3,5,8,13,21,34)
> fib[1]
[1] 0
> fib[5]
[1] 3
> fib[6]
[1] 5
> fib[1:3]
[1] 0 1 1
> fib[-1]
[1]  1  1  2  3  5  8 13 21 34
> fib[c(1,2,4,8)]
[1]  0  1  2 13

# 인덱스 응용
# 비교, 논리 연산자, 벡터의 인덱스를 합쳤을 떄 
> v <- c(3,6,1,9,11,16,0,3,1,45,2,8,9,6,-4)
> v[v > median(v)] # 중앙값 보다 큰 모든 원소 선택
[1]  9 11 16 45  8  9
> v[(v < quantile(v,0.05)) | (v > quantile(v,0.95))]  # 상, 하위 5% 안에 있는 모든 원소 선택
[1] 45 -4
> v[abs(v - mean(v)) > sd(v)] # 평균에서 +-1 표준편차를 넘는 모든 원소 선택
[1] 45 -4

# 인덱스를 이름으로 선택
> years <- c(1960, 1975, 1990)
> names(years) <- c("Kennedy", "Carter", "Clinton")
> years
Kennedy  Carter Clinton 
   1960    1975    1990  
> years["Carter"]
Carter 
  1975

 

7) 벡터의 연산 수행 

기본적인 산술 연산자들은 모두 벡터 쌍에 대해 적용 가능하며 각 원소별로 연산을 수행한다.

여기서 주의할 점은 결과값의 길이가 원본 벡터의 길이와 일치해야 된다.

> v <- c(11,12,13,14,15)
> w <- c(3,4,5,6,7)
> v + w
[1] 14 16 18 20 22
> v - w
[1] 8 8 8 8 8
> v / w
[1] 3.666667 3.000000 2.600000 2.333333 2.142857
> v - 2
[1]  9 10 11 12 13
> v - mean(w)
[1]  6  7  8  9 10


> x <- 1 : 10
> sqrt(x)
 [1] 1.000000 1.414214 1.732051 2.000000 2.236068 2.449490 2.645751
 [8] 2.828427 3.000000 3.162278

8) 연산자의 우선순위 

R에서는  연산자 우선순위가 다음 표와 같다.

연산자
[ [[  인덱스
:: ::: 네임스페이스
$ @ 요소 뽑아내기, 슬롯 뽑아내기
^ 지수
- + 단항 마이너스, 플러스 부호
: 수열 생성
%any%(%>%포함) 특수 연산자
* / 곱하기, 나누기
+ - 더하기, 빼기
== != < > <= >= 비교
! 논리 부정
& && 논리 "and"
|  || 논리 "or"
-> ->> 오른쪽 대입
= 대입(오른쪽을 왼쪽으로)
<- <<- 대입 (오른쪽을 왼쪽으로)
? 도움말

 

9) 함수 호출 파이프라인 만들기

파이프 연산자(%>%)를 사용해 표현식을 읽고 쓰기 쉽게 만든다.  수많은 tidyverse 함수에서도 폭넓게 사용되고 있다.

> library(tidyverse)
> data(mpg)
> mpg %>%
+ filter(cty > 21) %>%
+ head(3) %>%
+ print()
# A tibble: 3 × 11
  manufacturer model  displ  year   cyl trans  drv     cty   hwy fl   
  <chr>        <chr>  <dbl> <int> <int> <chr>  <chr> <int> <int> <chr>
1 chevrolet    malibu   2.4  2008     4 auto(… f        22    30 r    
2 honda        civic    1.6  1999     4 manua… f        28    33 r    
3 honda        civic    1.6  1999     4 auto(… f        24    32 r    
# … with 1 more variable: class <chr>

x %>% head()는 head(x)와 기능적으로 동일하다

두 경우 모두 x는 head의 인자이고 추가적인 인자 전달이 가능하지만, x는 언제나 첫 번째 인자가 된다.

x %>% head(n = 10)
head(x, n = 10)

위의 경우 기능적으로 동일한 예시이다. 하지만 예제가 복잡해질수록 이점이 늘어나며 작업 와중에 filter를 사용해서 데이터를 값으로 한정하고, select를 사용해서 특정 값들만 남겨 두고, ggplot에 보내서 간단한 그래프를 그린다고 할 때  중간 단계 변수를 사용 할 수 있다.

library(tidyverse)

filtered_mpg <- filter(mpg, cty > 21)
selected_mpg <- select(filtered_mpg, cty, hwy)
ggplot(selected_mpg, aes(cty, hwy)) + geom_point()

mpg %>%
+ filter(cty > 21) %>%
+ select(cty, hwy) %>%
+ ggplot(aes(cty,hwy)) + geom_point

추가적으로 앞의 코드는 mpg 데이터세트에서 filter 함수로 파이프하며 도심 mpg 값인 cty 변수가 21보다 큰 레코드들만 남겨 두는 것이다. 확실히 파이프라인을 사용하는 것이 더 가독성이 좋고 더 편한 점이 있다.

 

 

 

'데이터분석 > R' 카테고리의 다른 글

R언어 공부 - 6  (0) 2022.12.30
R언어 공부 - 5  (3) 2022.12.29
R언어 공부 - 4  (0) 2022.12.27
R언어 공부 - 3  (0) 2022.12.27
R언어 공부 - 2  (0) 2022.12.26