04. 벡터 Vector




* 본 블로그의 모든 게시물은 전문적인 내용이 아님을 알려드립니다.

 * 내용에 오류가 있거나 불친절한 설명이 있는 경우 언제든지 댓글로 의견을 남겨주세요!





목차

0. R의 자료구조
1. 벡터의 생성 
2. 벡터의 연산
3. 벡터의 Recycling
4. 벡터함수, non-벡터 함수
5. 벡터의 인덱싱, 필터링
* 사용함수 정리
#rep()
#seq()
#round()
#diff()
#length()
#NA,NULL,Inf,NaN



0. R의 자료구조


R의 자료구조에는  1차원 자료 구조인 벡터, 리스트

 2차원 자료구조인 행렬(Matrix), 데이터 프레임(Data frame)

 다차원 자료구조인 배열(Array)이 있습니다.










서로 다른 타입의 값을 저장할 수 있는 List와 Data.frame은 차후 게시할 예정이며 이 게시글에선 동일한 타입의 값을 저장하는 구조에 대해 설명하겠습니다.


우선 Vector, Matrix, Array는 각 요소의 값들이 전부 동일한 타입을 지닙니다.


요소 하나가 숫자형이면 나머지 값도 전부 숫자형, 문자형이면 전부 문자형으로 들어가야 합니다.


쉽게 그림으로 표현하자면 다음과 같습니다.



# 벡터 생성

> x <- c(1,2,3)

# 행렬 생성

y <- matrix(c("a","b","c","d","e","f","g","h",9), nrow = 3)

# 배열 생성

> z <- array(c(0,3,0,1,2,0,2,5,8), dim = c(3,3,3))







위의 내용에서 볼 수 있듯이 vector, matrix, array는 동일한 타입의 값을 갖는 요소만 받을 수 있으며


만약 다른 타입의 값을 사용자가 할당하는 경우 자동으로 형태를 변환 후 값을 저장합니다.




#숫자형과 논리형을 같이 입력할 경우 형변환 (논리 -> 숫자)

> x <- c(1,2,TRUE)                        

> x

[1] 1 2 1


#숫자, 논리, 문자형을 같이 입력할 경우 형변환 (논리 -> 문자, 숫자 -> 문자)

> x <- c(1, "y", FALSE)                    

> x

[1] "1" "y" "FALSE"



즉 숫자와 논리형이 있을 땐 숫자로 문자와 비문자형이 있을 땐 문자로 형변환을 시켜서 저장합니다.




1. 벡터의 생성




벡터를 생성하는 방법엔 3가지가 있습니다. 


c()를 이용해 값들을 벡터로 결합해주는 방법, 기본적으로 R에서 여러개의 요소를 묶어줄 때 사용합니다.


*rep() 반복 함수를 통해 생성,


*seq(), ':' 와 같이 범위를 지정하는 함수를 통해 생성하는 방법이 있습니다.


여기에 추가적으로 앞에서 배웠던 모든 데이터 타입들의 하나의 값은 벡터로 취급됩니다.  ex) 1, "abc", TRUE


> x <- c(1,2,5)                     

> x

[1] 1 2 5


#1을 5번 반복하라

> y <- rep(1,5)                    

> y

[1] 1 1 1 1 1 


#1부터 5까지 출력하라

> z <- seq(1,5)                    

> z

[1] 1 2 3 4 5


#1부터 5까지 출력하라, ':' 는 seq의 디폴트 값이라 생각하면 된다.

> z <- 1:5                            

> z

[1] 1 2 3 4 5


# 숫자 뿐 아니라 변수로도 가능하다

> a <- 7                    

> 1:a                                    

[1] 1 2 3 4 5 6 7








2. 벡터의 연산





벡터는 모든 요소에 연산을 적용한다는 개념을 기본으로 합니다. 


가령 두 벡터를 합하는 연산을 할 경우엔


> a <- c(1,2,3)                   

> b <- c(2,3,4)


> a + b

[1] 3 5 7



3 5 7 이란 값이 나옵니다. 이는 a와 b의 첫번째 요소의 합 (1+2) = 3, a와b의 두번째 요소의 합 (2+ 3) = 5, 마찬가지로 마지막 요소 3과 4를 더해 7이 나옵니다.





이와 같이 각각의 요소에 동일 연산을 한번씩 적용시키는 개념은 덧셈이 아닌 다른 연산에서도 동일하게 적용됩니다.



> a * b

[1] 2 6 12


> a%%b

[1] 1 2 3


> a ^ b

[1] 1 8 81


> a > b

[1] FALSE FALSE FALSE


> a > 2 | b < 3     

[1] TRUE FALSE TRUE

#코드가 복잡하고 이해가 잘 안가는 경우엔 하나하나 살펴보셔야 합니다.

#우선 크게 조건1 | 조건2 형식으로 되어 있습니다. 

#조건1인 a>2에선 FALSE FALSE TRUE가

#조건2인 b < 3 에서는 TRUE FALSE FALSE가 나옵니다. 즉 결론적으론

#c(FALSE,FALSE,TRUE) | c(TRUE,FALSE,FALSE) 연산을 하는것과 같고 각각을 OR연산해주시면 위와같은 결과가 나옵니다.

#결국 핵심은 연산을 할때 벡터는 모든 요소를 반복해서 적용하는구나 입니다.



이와 같이 연산시 모든 요소를 반복하여 적용하는 것을 Vectorization이라고 합니다.


앞서 연산자에서 다뤘던 &&와 ||는 벡터의 첫번째 요소만 적용하는 연산자이기에 non-vectorized operator라고도 합니다.








3. 벡터의 Recycling



지금까지는 피연산자인 두 벡터의 크기가 동일할 때를 다뤄봤는데 그렇지 않은 경우엔 어떻게 연산처리가 되는지 알아보겠습니다.



> a <- c(1,2,3)

> a+2

[1] 3 4 5



앞서 말했듯 2라는 숫자형 값 하나도 벡터로 취급합니다. 이와같이 연산되는 벡터의 크기가 다른경우의 처리과정을 알아보도록 하겠습니다.





크기가 다른 두 벡터를 연산할 때 R은 반복을 사용해서 상대 벡터와 크기를 맞추어 준 다음 연산을 수행합니다.


예를 하나 더 들어보자면



> a <- c(1,2,3)

> x <- c(1,2)

> a + x

[1] 2 4 4

Warning message:

In a + x : longer object length is not a multiple of shorter object length



긴 벡터의 길이가 짧은 것의 배수가 아니라는 경고 문구가 뜨긴 하지만 2 4 4 라는 결과 값이 나왔습니다.


2 4 4 는 다음과 같은 과정을 통해서 나오게 됩니다.




즉 R에서는 크기가 다른 두 벡터를 연산할 경우 반복을 사용해서 크기를 맞추어 준 다음 연산을 수행합니다.









4. 벡터 함수, non-벡터 함수




위에서 기술했듯이 모든 요소에 연산을 적용하는 것을 Vectorization라고 했습니다.


이와 같이 벡터의 모든 요소에 적용되는 함수를 Vectorized Function 이라 하며, 그렇지 않은 함수들을 non-vectorized Function이라 합니다.


각각의 예시는 다음과 같습니다.




4-1) 모든 요소에 적용되는 벡터 함수, 일반적으로 math.function 수학적 계산을 하는 함수




 

함수 

설명 

 

 

 

#이외에도 많이 존재 

 

 

sqrt 

제곱근 

sqrt(x)

 

 

 

 

 

abs

절대값

abs(x)

 

 

 

 

 

round

반올림

round(x)

 

 

 

 

 

log

자연로그

log(x)

 

 

 

 

 

log10

상용로그

log10(x)

 

 

 

 

 

exp

지수함수

exp(x)

 

 

 

 

 

trunc

소수점 버림 

trunc(x)

 

 

 



> x <- 1:3

> sqrt(x)

[1] 1.000000 1.414214 1.732051

> log(x)

[1] 0.0000000 0.6931472 1.0986123


> x <- -1:1

> abs(x)

[1] 1 0 1


> x <- c(1.55,1.53,1.88)

> *round(x)

[1] 1 2 2




4-2) 누적함수 cum~



 

함수 

설명 

 

 

 



 

cumsum 

누적합 

cumsum(x)

 

 

 

 

 

cumprod

누적곱

cumprod(x)

 

 

 

 

 

cummax

누적 최대값

cummax(x)

 

 

 

 

 

cummin

누적 최소값

cummin(x)

 

 

 




- cum~함수는 누적해서 연산하는 함수이다. 이또한 벡터함수와 유사하게 처음부터 끝까지 모든 요소를 고려한다. 순서대로 예를 들어보자


> x <- 1:5

> cumsum(x)                        

[1] 1 3 6 10 15

#1, 1+2, 1+2+3, 1+2+3+4, 1+2+3+4+5


> cumprod(x)                        

[1] 1 2 6 24 120

#1, 1*2, 1*2*3, 1*2*3*4, 1*2*3*4*5


> y <- c(1:3,2,4,2:4)

> y

[1] 1 2 3 2 4 2 3 4


> cummax(y)                        

[1] 1 2 3 3 4 4 4 4

#1, 1과 2중 최대값 2, 1과 2와 3중 최대값 3 ... 1 2 3 2 4 2 3 4 중 최대값 4


> cummin(y)                          

[1] 1 1 1 1 1 1 1 1

#1, 위와 같은 내용으로 해당 번째까지의 최소값 출력




4-3) non-벡터 함수, 일반적으로 stat.function, 요소들의 통계적 요약



 

함수 

설명 

 

 

 

#이외에도 많이 존재 

 

 

mean

      평균

mean(x)

 

 

 

 

 

median

      중앙값

median(x)

 

 

 

 

 

range

범위 출력

range(x)

 

 

 

 

 

sd

표준편차

sd(x)

 

 

 

 

 

var

분산

var(x)

 

 

 

 

 

sum

sum(x)

 

 

 

 

 

min,max

최소,최대 

min,max(x)

 

 

 


 

            iqr

      사분위 편차 

      iqr(x) 

    
             diff

       x의 차분

      diff(x)     



> x <- seq(1,100, length = 7)

> x

[1] 1.0  17.5  34.0  50.5  67.0  83.5 100.0


> mean(x)

[1] 50.5

> sum(x)

[1] 353.5

#range는 해당 벡터의 최대값과 최소값을 출력한다.

> range(x)                    

[1]   1 100


> x <- c(0,1,3,6,10,15)

> *diff(x)

[1] 1 2 3 4 5




4-4) 집합 함수, Set functions




벡터의 규모가 작은경우 벡터간의 비교가 수월합니다.


그러나 만약 방대한 양의 두 벡터를 비교하려면 눈으로는 택도 없겠죠 이럴 때 사용하는 함수에 대해서 알아보겠습니다.




 

함수 

설명 

 

 

 


 

 

union

      합집합

union(x,y)

 

 

 

 

 

intersect

      교집합

intersect(x,y)

 

 

 

 

 

setdiff

차집합,

(방향 고려)

setdiff(x,y)

 

 

 

 

 

setequal

동일한가?

setequal(x,y)

 

 

 

 

 

is.element

포함 여부

is.element(x,y)

 

 

 

 



> x <- seq(1,10,by = 2)

> x

[1] 1 3 5 7 9

> y <- 5:10


#x와 y벡터의 합집합 union()

> union(x,y)                                    

[1] 1 3 5 7 9 6 8 10


#x와 y벡터의 교집합 intersect()

> intersect(x,y)                                

[1] 5 7 9


#setdiff()는 왼쪽의 벡터가 기준이다

#x벡터에서 y벡터 요소를 빼고 출력

>setdiff(x,y)                                        

[1] 1 3

>setdiff(y,x)                                    

[1] 6 8 10


#두 벡터가 동일한가? setequal()

> setequal(x,y)                                

[1] FALSE


#is.element()또한 왼쪽의 벡터가 기준이다

#x의 n번째 요소가 y벡터에 들어있는가?

> is.element(x,y)                                

[1] FALSE FALSE TRUE TRUE TRUE            

> is.element(y,x)

[1] TRUE FALSE TRUE FALSE TRUE FALSE









5. 벡터의 인덱싱, 필터링




우리가 데이터가 있을 때 어디에 위치해 있는지(인덱싱) 원하는 조건의 정보를 뽑아내는것(필터링)은 매우 중요합니다.


벡터의 인덱싱은 변수명 옆에 '[ ]' 를 사용합니다.


파이썬, 자바와 같은 타 프로그래밍 언어와 달리 첫번째 값은 1부터 시작합니다.


> x <- c(1,5,6,8,2)

> x

[1] 1 5 6 8 2


#x벡터의 첫번째 값 출력

> x[1]                    

[1] 1

#x벡터의 3번째 값 출력

> x[3]                    

[1] 6


#x벡터의 2~4번째 값 출력

> x[2:4]                    

[1] 5 6 8 



반대로 역순으로 출력, 혹은 원하는 순서에 맞게 출력시키는 것 또한 가능합니다.


즉 인덱싱을 통해서 벡터 요소들의 순서를 변경하는것 또한 가능합니다.


> x <- 1:5

 #x벡터의 5번째 요소~첫번째 요소 값 출력,

> x[5:1]                            

[1] 5 4 3 2 1

#x벡터의 마지막요소~첫번째 요소 값 출력, *length(x), x의 요소 개수를 말하며 여기선 5를 의미한다. 

> x[length(x):1]                    

[1] 5 4 3 2 1


> y <- c(5,1,2)

#y의 2번째, 3번째, 1번째 요소를 출력하라

> y[c(2, 3, 1)]                

[1] 1 2 5



x는 현재 5개의 요소를 갖고 있기 때문에 이외의 인덱싱을 호출하면 *NA가 출력됩니다.



> x[6]

[1] NA



인덱싱을 통해서 원하는 자리 값에 값을 할당하는 것 또한 가능합니다. 


현재 x는 5개 요소를 갖고 있어 6번째 요소는 NA로 나오는데 6번째 자리에 3이라는 값을 대입해 보겠습니다.


값을 할당하는 방법은 지금까지 했던 방법과 동일합니다.



> x[6] <- 6

> x

[1] 1 2 3 4 5 6




다음은 벡터의 필터링입니다. 원하는 조건에 해당하는 것만 뽑아내는 역할을 하며 인덱싱안에 논리형 값을 직접 대입(거의 사용 안함)하거나 연산의 결과가 논리형으로 나오는 조건식을 대입하는 방식으로 사용합니다.


> x <- c(1,5,6,8,2)


# 인덱싱에서 TRUE에 해당하는 것만 추출한다, X에서 첫번째와 5번째만 뽑아라

> x[c(TRUE,FALSE,FALSE,FALSE,TRUE)]                

[1] 1 2



# x 에서 3보다 작은 값을 출력하라

> x[x<3]                      

[1] 1 2                          

# x<3의 자리에 조건의 결과인 논리형 값 T F F F T 가 들어가서 첫번째,5번째 결과값 출력

> x < 3

[1] TRUE FALSE FALSE FALSE TRUE



> x <- c(1,2,3,4)

> y <- c(10,9,8,2)

> y[x^2 > 10]                           

[1] 2                                    

# x^2 > 10 의 결과는 F F F T 이다. (4의 제곱만이 10을 넘음)

# 따라서 y벡터의 1~3번째 요소는 출력하지 않고 4번째 요소만 출력해 2가 나온다.



 필터링을 통해서 원하는 값을 변경시킬 수 있습니다. 가령 1 2 3 4 로 구성되어 있는 x에서 2보다 큰 값을 0으로 바꾸고 싶다면



> x[x>2] <- 0 

# 2보다 큰 x에 0을 할당, x의 3번째 4번째 요소가 2보다 크니 그 값에 0을 할당

> x

[1] 1 2 0 0




데이터 전처리에서 '조건에 맞는 값을 뽑아낸다'는 매우!! 중요합니다. 앞으로 자주 다루게 될 데이터 프레임에서도 마찬가지로 인덱싱, 필터링 개념이 등장하기에 깊이 있는 이해가 필요합니다. 





* 사용 함수 정리


*01. rep()

- rep는 기본적으로 값을 반복하는 함수이다.

- rep(a,b) = a를 b만큼 반복하라.

- each 파라매터를 통해 각각 n번 반복할 수 있다.


#1부터 3까지를 2회 반복하라
> rep(1:3,2)                                
[1] 1 2 3 1 2 3

#1부터 3까지를 각각 2번씩 2회 반복하라
> rep(1:3,2, each = 2)                    
[1] 1 1 2 2 3 3 1 1 2 2 3 3





*02. seq()



- seq는 어디부터 어디까지, 일정 범위의 값을 출력시킬때 사용하는 함수이다.


- seq(a,b) = a부터 b까지


- default 값으로 1씩 증가, 감소를 사용한다.


> seq(1,5)

[1] 1 2 3 4 5


> seq(5,2)

[1] 5 4 3 2


- 증가,감소의 크기를 by를 통해 조정가능하다.


#1부터 5까지 2씩 건너 띄어서 출력

> seq(1,5, by = 2)                        

[1] 1 3 5



- 나오는 개수를 정할 수 있는데 length를 통해 가능하다. 가령 1부터 2까지 5개를 출력시키고 싶다면 다음과 같이 사용하면 된다.


> seq(1,2, length = 5)

[1] 1.00 1.25 1.50 1.75 2.00




*03. round()



round는 반올림을 하는 함수이다.


- 반올림 하려는 대상값, 자리수 두개의 파라매터가 있다.


- round(x, digit = 0) digit은 생략 가능하며 자리수가 양수일 땐 소수점의 반올림, 음수일 땐 정수의 반올림을 실행한다.


> x <- c(1.55,1.53,1.88)

> round(x,1)

[1] 1.6 1.5 1.9


> x <- 123.456

> round(x,-1)

[1] 120


- 그런데 여기에 한가지 오류가 있다.


> x <- c(1.05,1.15,1.25,1.35,1.45,1.55,1.65,1.75,1.85,1.95)

> round(x,1)

 [1] 1.1 1.1 1.2 1.4 1.4 1.6 1.6 1.8 1.8 2.0


> x <- c(105,115,125,135,145,155,165,175,185,195)

> round(x,-1)

 [1] 100 120 120 140 140 160 160 180 180 200



- 정상적인 결과로는 1.1 1.2 1.3 1.4 1.5 ... 2.0까지 나와야 하나 중간에 반올림이 되지 않는 경우가 있다. ?round를 통해 원인을 알아보자.



> ?round


Rounding of Numbers


...(중략)...


Details


Note that for rounding off a 5, the IEC 60559 standard is expected to be used, ‘go to the even digit’. Therefore round(0.5) is 0 and round(-1.5) is -2. However, this is dependent on OS services and on representation error (since e.g. 0.15 is not represented exactly, the rounding rule applies to the represented number and not to the printed number, and so round(0.15, 1) could be either 0.1 or 0.2).


해석을 해보면 다음과 같다.


5를 반올림하는 경우, IEC60559 표준이 사용될 것으로 예상되며,'짝수로 이동하십시오'. 따라서 원형(0.5)은 0이고 원형(-1.5)은-2이다. 그러나 이는 OS서비스와 표현 오류에 따라 달라진다(예:0.15는 정확히 표시되지 않으므로, 반올림 규칙은 숫자에 적용되지 않으며, 따라서 반올림 규칙은 0.1또는 0.2이 될 수 있다.)


- 모든 반올림 연산에서 동일한 결과가 나온다면 큰 문제는 없을것으로 보이나 정확을 기하고 싶다면 이와 같은 내용을 사용할 때 한번 확인하는 작업이 필요해 보인다.




*04. diff()



- diff(x)는 x의 2번째 요소에서 1번째 요소를, x의 n+1번째 요소에서 x의 n번째 요소를 빼준 값이다.


> x <- c(0,1,3,6,10,15)

> diff(x)

[1] 1 2 3 4 5


- 1 2 3 4 5 가 나온 이유는 1-0 =1 , 3-1 = 2 , ... 15-10 = 5 와 같은 과정을 통해 나왔다.


- lag = , 파라매터를 통해 차분의 간격을 지정할 수 있다.


> x <- c(0,1,3,6,10,15)

> diff(x, lag = 2)

[1] 3 5 7 9


- lag = 2 로 조정을 하여 3-0 = 3, 6-1= 5, 10-3 = 7, 15-6 = 9 과정을 통해 다음과 같이 나왔다.




*05. length()


- 벡터, 행렬, 배열에서 length()는 요소의 개수(=길이)를 의미한다.


> x <- 1:9

> y <- matrix(1:9,nrow=3);y

> z <- array(1:9, dim = c(3,3,3))

> length(x)

[1] 9

> length(y)

[1] 9

> length(z)

[1] 27


- 리스트, 데이터 프레임에서 length()는 칼럼의 개수를 의미한다. 이는 해당 포스트에서 다시 작성하겠다.



*06. NA, NULL, Inf, NaN


NA : 결측값, 값이 정의되지 않은 상태이나 데이터의 자리 값은 차지 (아직 값을 입력하지 않은 개념), NA가 있을 시 숫자적인 계산 불가


- NULL : 값이 없음, 값이 존재하지 않기 때문에 자리 값 또한 없음, NULL값이 존재해도 숫자 계산 가능


- Inf : 무한대, 1/0, -1/0 과 같이 무한대로 발산하는 경우


- NaN : 숫자가 아님, 숫자로 정의 되지 않음(Not a Number), 0/0과 같은 경우



> x <- c(10,100,NA,50)

> y <- c(10,100,NULL,50)

> mean(x)                            

[1] NA

#NA또한 하나의 자리값을 갖기 때문에 수치적 계산이 불가하다

> mean(y)                            

[1] 53.33333

# NULL은 자리값을 갖지 않기 때문에 수치적 계산이 가능하다. 빼고 계산



- 이렇게 NA를 갖고 있는 경우 수치적 계산이 되지 않는다. 그래서 모델링을 들어가기전 데이터 전처리과정을 거치며 NA값을 제거 시켜주는데 이때 사용하는 방법에 대해서 알아보자.


*is.~ (~의 존재여부)


# x에 NA값이 존재하는가?

> is.NA(x)                                    

[1] FALSE FALSE TRUE FALSE

# x에 NULL이 존재 하는가?

> is.NULL(Y)                                

[1] FALSE FALSE TRUE FALSE



인덱싱을 통해서 값을 선택한 후 다른 값으로 치환하자. NA값은 0으로 바꾸거나 평균값으로 대체하곤 하는데 이는 상황에 맞게 판단해야 한다

이렇게 인덱싱을 통해 제거하는 방법은 나중에 전처리시 중요하게 사용되므로 반드시 알아 두어야 한다.


> x[is.NA(x)] <- 0

> x

[1] 10 100 0 50

> mean(x)

[1] 40


> y[is.NULL(y)] <- mean(y)

> y

[1] 10 100 53.33333, 50


na는 수치적 계산시 함수내부 파라매터를 통해 제거하는 방법도 있다. 이땐 위와 같이 값을 영구적으로 치환하는게 아니라 na값을 무시하고 값을 출력하는 방법이다. 


주의 할 점은 na값을 0으로 대체한 경우와 평균값이 달라진다. na를 무시하고 평균을 계산하면 분모가 3이되고 0으로 값을 치환한 후 평균을 계산하면 분모가 4이기 때문이다.



> x <- c(10,100,NA,50)

# x를 평균내라, na를 무시한채로

> mean(x, na.rm = TRUE)                

[1] 53.33333


'R 기초' 카테고리의 다른 글

[R기초] 06. 리스트 List  (0) 2018.01.18
[R기초] 05. 행렬과 배열 Matrix & Array  (0) 2018.01.17
[R기초] 03. 연산자 Operator  (1) 2018.01.10
[R기초] 02. 변수 Variable  (1) 2018.01.10
[R기초] 01. R/R studio 설치하기  (0) 2018.01.04

+ Recent posts