지난번 포스팅에서는 NumPy 에서 제공하는

 

 - (1) 단일 배열 대상의 범용 함수

       (Unary Universal Functions)

 - (2) 2개 배열 대상의 범용 함수

       (Binary Universal Functions)

 

에 대해서 간략히 소개를 하였습니다.

 

그리고 단일 배열 대상의 범용 함수 중에서 (1-1) '올림 혹은 내림 (Rounding)' 함수들(np.around, np.round_, np.rint, np.fix, np.ceil, np.floor, np.trunc)에 대해서 알아보았습니다.

 

이번 포스팅에서는 단일 배열 대상의 범용 함수(Unary ufuncs) 중에서 (1-2) 배열 원소 간 곱(products), 합(sums), 차분(differences) 범용 함수들에 대해서 알아보겠습니다.  (함수가 많아서 한꺼번에 포스팅하기에 버거우므로 여러번 나누어서 포스팅합니다)

 

 

[ Unary ufuncs : 배열 원소 간 곱 (products), 합 (sums), 차분 (differences) ]

 

 

 

 (1-2) 배열 원소 간 곱(products), 합(sums), 차분(differences), 기울기(gradient) 범용함수

 

1차원 배열 b와 2차원 배열 c를 가지고 예를 들어 설명하겠습니다.

 

 In [1]: import numpy as np


In [2]: b = np.array([1, 2, 3, 4]) # 1 dimension


In [3]: b

Out[3]: array([1, 2, 3, 4])


In [4]: c = np.array([[1, 2], [3, 4]]) # 2 dimension


In [5]: c

Out[5]:

array([[1, 2],
        [3, 4]])

 

 

 

 

 (1-2-1) 배열 원소 간 곱 범용 함수 (products universal funcstions) : np.prod()

 

2차원 배열의 경우 axis=0 이면 같은 열(column)위*아래 방향으로 배열 원소 간 곱하며, axis=1 이면 같은 행(row)의 왼쪽*오른쪽 원소 간 곱을 합니다.

 

 

# (1-2-1) np.prod() : Return the product of array elements over a given axis

 

# 1 dimensional array

In [3]: b

Out[3]: array([1, 2, 3, 4])

 

In [6]: np.prod(b)  # 1*2*3*4

Out[6]: 24

 

# 2 dimensional array

In [5]: c

Out[5]:

array([[1, 2],
        [3, 4]])

 

In [7]: np.prod(c, axis=0# [1*3, 2*4]  ↓

Out[7]: array([3, 8])


In [8]: np.prod(c, axis=1# [1*2, 3*4]  →

Out[8]: array([ 2, 12])

 

 

 

 

 (1-2-2) 배열 원소 간 합치기 범용 함수 (sum universal functions) : np.sum()

 

keepdims=True 옵션을 설정하면 1 차원 배열로 배열 원소 간 합을 반환합니다.

 

 

# (1-2-2) np.sum() : Sum of array elements over a given axis

 

# 1 dimensional array

In [3]: b

Out[3]: array([1, 2, 3, 4])

 

In [9]: np.sum(b) # [1+2+3+4]

Out[9]: 10

 

# the axes which are reduced are left in the result as dimensions with size one

In [10]: np.sum(b, keepdims=True)

Out[10]: array([10])  # 1 dimension array

 

In [11]: np.sum(b, keepdims=True).shape  # 1 dimension array

Out[11]: (1,)

 

 

 

2차원 배열의 경우 axis=0 을 설정하면 같은 열(column)의 위+아래 원소 값을 더하며, axis=1 을 설정하면 같은 행(row)의 왼쪽+오른쪽 원소 값을 더하여 1차원 배열을 반환합니다.

 

 

# 2 dimensional array

In [5]: c

Out[5]:

array([[1, 2],
        [3, 4]])

 

In [12]: np.sum(c, axis=0)  # [1+3, 2+4]  ↓

Out[12]: array([4, 6])


In [13]: np.sum(c, axis=1)  # [1+2, 3+4]  →

Out[13]: array([3, 7])

 

 

 

 

 (1-2-3) NaN 이 포함된 배열 원소 간 곱하기 범용 함수 : np.nanprod()

 

np.nanprod() 함수는 NaN (Not a Numbers) 을 '1'(one)로 간주하고 배열 원소 간 곱을 합니다.

 

 

# (1-2-3) np.nanprod() : Return the product of array elements

#                             over a given axis treating Not a Numbers (NaNs) as ones

 

In [14]: d = np.array([[1, 2], [3, np.nan]])


In [15]: d

Out[15]:

array([[  1.,   2.],
        [  3.,  nan]])


In [16]: np.nanprod(d, axis=0)  # [1*3, 2*1]  ↓

Out[16]: array([ 3., 2.])


In [17]: np.nanprod(d, axis=1)  # [1*2, 3*1]  →

Out[17]: array([ 2., 3.])

 

 

 

 

 (1-2-4) NaN이 포함된 배열 원소 간 더하기 범용 함수 : np.nansum()

 

np.nansum() 함수는 NaN (Not a Numbers)을 '0'(zero)으로 간주하고 배열 원소 간 더하기를 합니다.

 

 

In [15]: d

Out[15]:

array([[  1.,   2.],
        [  3.,  nan]])

 

# (1-2-4) np.nansum() : Return the sum of array elements

#                             over a given axis treating Not a Numbers (NaNs) as zero

 

In [18]: np.nansum(d, axis=0)  # [1+3, 2+0]  ↓

Out[18]: array([ 4., 2.])


In [19]: np.nansum(d, axis=1)  # [1+2, 3+0]  →

Out[19]: array([ 3., 3.])

 

 

 

 

 (1-2-5) 배열 원소 간 누적 곱하기 범용 함수 : np.cumprod()

 

axis=0 이면 같은 행(column)의 위에서 아래 방향으로 배열 원소들을 누적(cumulative)으로 곱해 나가며, axis=1 이면 같은 열(row)에 있는 배열 원소 간에 왼쪽에서 오른쪽 방향으로 누적으로 곱해 나갑니다.

 

 

In [20]: e = np.array([1, 2, 3, 4])


In [21]: e

Out[21]: array([1, 2, 3, 4])


In [22]: f = np.array([[1, 2, 3], [4, 5, 6]])


In [23]: f

Out[23]:

array([[1, 2, 3],
        [4, 5, 6]])

 

 

# (1-2-5) np.cumprod() : Return the cumulative product of elements along a given axis

In [24]: np.cumprod(e)  # [1, 1*2, 1*2*3, 1*2*3*4]

Out[24]: array([ 1, 2, 6, 24], dtype=int32)


In [25]: np.cumprod(f, axis=0)  # [[1, 2, 3], [1*4, 2*5, 3*6]]  ↓

Out[25]:

array([[ 1,  2,  3],
        [ 4, 10, 18]], dtype=int32)


In [26]: np.cumprod(f, axis=1)  # [[1, 1*2, 1*2*3], [4, 4*5, 4*5*6]]  →

Out[26]:

array([[  1,   2,   6],
        [  4,  20, 120]], dtype=int32)

 

 

 

 

 (1-2-6) 배열 원소 간 누적 합 구하기 범용 함수 : np.cumsum()

 

axis=0 이면 같은 행(column)의 위에서 아래 방향으로 배열 원소들을 누적(cumulative)으로 합해 나가며, axis=1 이면 같은 열(row)에 있는 배열 원소 간에 왼쪽에서 오른쪽 방향으로 누적으로 합해 나갑니다.

 

 

In [21]: e

Out[21]: array([1, 2, 3, 4])

 

# (1-2-6) np.cumsum(a, axis) : Return the cumulative sum of the elements along a given axis

 

In [27]: np.cumsum(e)  # [1, 1+2, 1+2+3, 1+2+3+4]

Out[27]: array([ 1,  3,  6, 10], dtype=int32)

 

 

In [23]: f

Out[23]:

array([[1, 2, 3],
        [4, 5, 6]])

 

In [28]: np.cumsum(f, axis=0)  # [[1, 2, 3], [1+4, 2+5, 3+6]]  ↓

Out[28]:

array([[1, 2, 3],
        [5, 7, 9]], dtype=int32)


In [29]: np.cumsum(f, axis=1)  # [[1, 1+2, 1+2+3], [4, 4+5, 4+5+6]]  →

Out[29]:

array([[ 1,  3,  6],
        [ 4,  9, 15]], dtype=int32)

 

 

 

 

  (1-2-7) 배열 원소 간 n차 차분 구하기 : np.diff()

 

 

# (1-2-7) diff(a, n, axis) : Calculate the n-th discrete difference along given axis

 

In [30]: g = np.array([1, 2, 4, 10, 13, 20])


In [31]: g

Out[31]: array([ 1, 2, 4, 10, 13, 20])

 

 

# 1차 차분 (1st order differencing)

In [32]: np.diff(g)  # [2-1, 4-2, 10-4, 13-10, 20-13]

Out[32]: array([1, 2, 6, 3, 7])

 

 

# 2차 차분 (2nd order differencing) => 1차 차분 결과 Out[32] 를 가지고 한번 더 차분

In [33]: np.diff(g, n=2)  # [2-1, 6-2, 3-6, 7-3]  <- using Out[32] array (1st order difference)

Out[33]: array([ 1, 4, -3, 4])

 

 

# 3차 차분 (3rd order differencing) => 2차 차분 결과 Out[33] 을 가지고 한번 더 차분

In [34]: np.diff(g, n=3)  # [4-1, -3-4, 4-(-3)]  <- using Out[33] array (2nd order diffenence)

Out[34]: array([ 3, -7, 7])

 

 

 

2차원 배열의 경우 axis=0 이면 같은 열(column)의 아래에서 위 방향으로 차분(difference)을 하며,

axis=1 이면 같은 행(row)의 오른쪽에서 왼쪽 방향으로 차분을 합니다.

 

 

#---- 2 dimentional arrays

 

In [35]: h = np.array([[1, 2, 4, 8], [10, 13, 20, 15]])


In [36]: h

Out[36]:

array([[ 1,  2,  4,  8],
        [10, 13, 20, 15]])

 

In [37]: np.diff(h, axis=0)  # [10-1, 13-2, 20-4, 15-8] ↑

Out[37]: array([[ 9, 11, 16, 7]])


In [38]: np.diff(h, axis=1)  # [[2-1, 4-2, 8-4], [13-10, 20-13, 15-20]] ←

Out[38]:

array([[ 1,  2,  4],
        [ 3,  7, -5]])

 

 

# n=2 이면 1차 차분 결과인 Out[38] 배열에 대해 한번 더 차분

 

In [39]: np.diff(h, n=2, axis=1)  [[2-1, 4-2], [7-3, -5-7]] ←

Out[39]:

array([[  1,   2],
        [  4, -12]])

 

 

 

 

 (1-2-8) 차분 결과를 1차원 배열(1 dimensional array)로 반환해주는 함수 : ediff1d()

 

2차원 배열에 대한 차분인 np.diff(h, axis=1) 의 경우 Out[38] 처럼 2차원 배열을 반환합니다. 반면에 ediff1d(h) 함수를 사용하면 Out[41] 처럼 차분 결과를 1차원 배열로 반환합니다.

 

 

# (1-2-8) ediff1d(ary[, to_end, to_begin])

#           : The differences between consecutive elements of an array

 

In [31]: g

Out[31]: array([ 1, 2, 4, 10, 13, 20])

 

In [40]: np.ediff1d(g)

Out[40]: array([1, 2, 6, 3, 7])

 

 

# 2 dimensional array

 

In [36]: h

Out[36]:

array([[ 1,  2,  4,  8],
        [10, 13, 20, 15]])

 

# The returned array is always 1D

In [41]: np.ediff1d(h)

Out[41]: array([ 1, 2, 4, 2, 3, 7, -5])  # 1D array, not 2D array

 

 

 

np.ediff1d() 함수의 시작부분과 끝 부분의 값을 to_begin, to_end 로 설정해줄 수도 있습니다.

 

 

In [42]: np.ediff1d(h, to_begin=np.array([-100, -99]), to_end=np.array([99, 100]))

Out[42]: array([-100, -99, 1, 2, 4, 2, 3, 7, -5, 99, 100])

 

 

 

 

  (1-2-9) 기울기(gradient) 구하기 범용 함수 : np.gradient()

 

gradient는 1차 편미분한 값들로 구성된 배열입니다. 아래 예제에 np.gradient() 함수가 어떻게 계산되는지를 수식을 적어놓았으니 참고하시기 바랍니다.  말로 설명하기가 쉽지가 않네요. ^^; 

 

 

In [31]: g

Out[31]: array([ 1, 2, 4, 10, 13, 20])

 

 

# [(2-1), {(2-1)+(4-2)}/2, {(4-2)+(10-4)}/2, {(10-4)+(13-10)}/2, {(13-10)+(20-13)}/2, (20-13)]

In [43]: np.gradient(g)

Out[43]: array([ 1. , 1.5, 4. , 4.5, 5. , 7. ])

 


# N scalars specifying the sample distances for each dimension

# x축 1단위가 '2'이므로 양쪽 옆으로 x축 변화에 따른 y값 변화를 보는 것이므로 2(단위)*2(방향)으로 나누어 줌

# [(2-1)/2, {(2-1)+(4-2)}/2*2, {(4-2)+(10-4)}/2*2, {(10-4)+(13-10)}/2*2, {(13-10)+(20-13)}/2*2, (20-13)/2] 

In [44]: np.gradient(g, 2)

Out[44]: array([ 0.5 , 0.75, 2. , 2.25, 2.5 , 3.5 ])

 


# Gradient is calculated using N-th order accurate differences at the boundaries

# 양 옆에만 2차 차분 : 1 - (1.5 -1) = 0.5,   7 + (7-5) = 9

In [45]: np.gradient(g, edge_order=2)

Out[45]: array([ 0.5, 1.5, 4. , 4.5, 5. , 9. ])

 

 

 

아래는 2차원 배열에 대한 gradient 구하는 예제입니다. np.gradient(h, axis=0)과 np.gradient(h, axis=1)을 짬뽕해 놓은 것이 np.gradient(h) 라고 보면 되겠습니다.  gradient 방법은 위의 1차원에서 소개한 방법과 같습니다.

 

 

# 2 dimensional array

 

In [36]: h

Out[36]:

array([[ 1,  2,  4,  8],
        [10, 13, 20, 15]])

 

 

# the first array stands for the gradient in rows and the second one in columns direction

In [46]: np.gradient(h)

Out[46]:

[array([[  9.,  11.,  16.,   7.],
         [  9.,  11.,  16.,   7.]]),

 array([[ 1. ,  1.5,  3. ,  4. ],
         [ 3. ,  5. ,  1. , -5. ]])]

 


# The axis keyword can be used to specify a subset of axes of which the gradient is calculated

 

In [47]: np.gradient(h, axis=0)  # ↑

Out[47]:

array([[  9.,  11.,  16.,   7.],
        [  9.,  11.,  16.,   7.]])


In [48]: np.gradient(h, axis=1)  # ←

Out[48]:

array([[ 1. ,  1.5,  3. ,  4. ],
        [ 3. ,  5. ,  1. , -5. ]])

 

 

 

다음번 포스팅에서는 지수함수, 로그함수, 삼각함수에 대해서 다루어보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

 

반응형
Posted by Rfriend

댓글을 달아 주세요

통계는 크게 표본의 (a) 도수 분포와 중심화 경향, 그리고 퍼짐 정도를 측정하여 집단의 특성에 대해서 기술하는 기술통계(descriptive statistics)와, (b) 기술통계량을 가지고 모집단의 parameter 값 (모평균, 모분산 등)을 추정하고 가설을 검증하는 추정통계(inferential statistics)로 구분할 수 있습니다.

 

이번 포스팅에서는 R에서 벡터를 대상으로 사용할 수 있는 기술 통계 관련 함수에 대해서 알아보겠습니다.

 

R 기술통계 함수

 

-- 분포 및 중심화 경향 --

 

(1) 평균 : mean(x)

 

> x <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
> mean(x)
[1] 5.5 

 

 

(2) 중앙값 : median(x)

 

> x <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
> median(x)
[1] 5.5
> y <- c(1, 2, 3, 4, 5, 6, 7, 8, 9)
> median(y)
[1] 5

 

벡터 x가 홀수개이면 정 가운데 값을 중앙값을 가져오지만, 위의 case와 같이 x가 짝수개 이면 정가운데의 양쪽 두개의 값을 가져다가 평균을 내서 중앙값을 계산합니다.

 

 

(3) 최소값 : min(x)

 

> min(x)
[1] 1
> min(y)
[1] 1 

 

 

which.min(my_vec) 은 최소값이 있는 위치의 index 를 반환합니다. NA가 포함되어 있는 vector의 경우 min(my_vec) 이 NA를 반환한데 반해서 (NA에 대한 전처리 필요), my_vec[wich.min(my_vec)] 처럼 최소값을 ndexing을 해오면 '-12'를 반환했습니다.

 

 

> my_vec <- c(-5, 3, 10, 3, -12, NA)
> my_vec
[1]  -5   3  10   3 -12  NA
> 
> min(my_vec)
[1] NA
> 
> which.min(my_vec) # index of min value in 'my_vec' vector
[1] 5
> 
> my_vec[which.min(my_vec)]
[1] -12

 

 

 

 

(4) 최대값 : max(x)

 

> max(x)
[1] 10
> max(y) 

 

> my_vec <- c(-5, 3, 10, 3, -12, NA)
> my_vec
[1]  -5   3  10   3 -12  NA
> 
> max(my_vec)
[1] NA
> 
> which.max(my_vec) # index of max value in 'my_vec' vector
[1] 3
> 
> my_vec[which.max(my_vec)]
[1] 10 

 

 

 

(5) 범위 : range(x)

 

> range(x)
[1]  1 10
> range(y)
[1] 1 9 

 

 

(6) IQR(Inter-Quartile Range) : IQR(x)

 

> IQR(x)
[1] 4.5
> IQR(y)
[1] 4 

 

 

(7) 중심화 경향 및 분포 요약 : summary(x)

 

> summary(x)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1.00    3.25    5.50    5.50    7.75   10.00 

 

숫자형 벡터의 경우 summary() 함수가 위의 1번에서 6번까지 함수를 한번에 처리할 수 있는 유용한 함수가 되겠습니다.

 

 

-- 퍼짐 정도 --

 

(8) 분산 : var(x)

 

> var(x)
[1] 9.166667
> var(y)
[1] 7.5 

 

 

(9) 표준편차 : sd(x)

 

> sd(x); sd(y)
[1] 3.02765
[1] 2.738613 

 

참고) 세미콜론 ';' 을 사용하면 같은 줄에 R 명령어를 연속으로 해서 쓸 수 있습니다

 

 

-- 확률분포의 비대칭 정도 --

 

(10) 왜도

 

> install.packages("fBasics") # 왜도, 첨도 분석 가능한 package 설치 > library(fBasics) # package 호출 > hist(mtcars$mpg)

 

 

 

 

 

 

> skewness(mtcars$mpg) [1] 0.610655 attr(,"method") [1] "moment"

 

 

R에 왜도와 첨도를 위한 함수가 내장되어 있지 않기 때문에 별도 패키지(fBasics)를 설치해야 합니다.

자동차 정보가 들어있는 mtcars 데이터 프레임의 연비에 대해서 히스토그램을 그려보니 평균보다 왼쪽으로 치우쳐 있고 오른쪽으로 꼬리가 긴 분포를 띠고 있네요. 그러면 왜도(skewness) 가 '0'보다 크게 나타납니다. (공식이 평균에서 관측치를 뺀 값을 3제곱 하기 때문이예요) 위 예에서는 왜도가 0.61로 '0'보다 크게 나왔지요. 정규분포의 평균과 일치하면 왜도는 '0'이 되고, 반대로 평균보다 오른쪽으로 값이 치우쳐 있고 왼쪽으로 꼬리가 길면 왜도는 '0'보다 작은 값이 나옵니다.

 

 

(11) 첨도

 

> kurtosis(mtcars$mpg)
[1] -0.372766
attr(,"method")
[1] "excess"

 

관측값이 정규분포보다 뾰쪽한가 아닌가를 가늠하는 쳑도가 첨도입니다. '3'보다 크면 정규분포보다 더 뾰족한 모양이고, '3'보다 작으면 정규분포보다 덜 뾰족한 모양이라고 해석하면 되겠습니다. (패키지에 따라서는 '3'을 빼서 '0'으로 표준화해서 값을 제시하기도 합니다)

 

 

-- 기타 함수 --

 

(12) 합 : sum(x)

 

> sum(x)
[1] 55
> sum(y)
[1] 45

 

 

(13) n차 차분 : diff(x, lag=n)

 

> diff(x, lag=1)
[1] 1 1 1 1 1 1 1 1 1
> diff(x, lag=2)
[1] 2 2 2 2 2 2 2 2
> diff(x, lag=3)
[1] 3 3 3 3 3 3 3 

 

관측값에서 직전 관측값을 뺀 차분을 구하는 함수입니다. 시계열분석할 때 정상화하기 위해서 차분을 이용하는데요, 시차(lag)를 분석 목적에 따라 또 데이터 특성에 따라서 입력해주면 됩니다. 디폴트는 lag=1 이 되겠습니다.

 

 

(14) 길이, 관측값 개수 : length()

 

> # 벡터에 length() 사용 시
> length(x)
[1] 10
> length(y)
[1] 9 
> 

> # 데이터 프레임에 length()사용 시

> length(mtcars)
[1] 11
> 

> # 데이터 프레임의 특정 변수에 length($) 사용 시

> length(mtcars$mpg)
[1] 32

 

벡터에서 length()는 관측값 개수를 계산해서 보여줍니다.

데이터 프레임에서는 column 개수를 나타내주고요, 데이터 프레임의 특정 변수를 지정하면 그 특정 변수의 관측값의 개수를 세서 보여줍니다.

 

 

(15) 순위 : rank()

 

> rank(x) [1] 1 2 3 4 5 6 7 8 9 10 >
>
rank(-x) [1] 10 9 8 7 6 5 4 3 2 1 >

> mtcars$mpg
 [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5
[23] 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7 15.0 21.4

>

> rank(mtcars$mpg, 
+      na.last = TRUE, 
+      ties.method = c("max"))
 [1] 20 20 25 22 15 14  4 26 25 17 13 11 12  8  2  2  5 31 30 32 23  9  8  3 17 28 27 30 10 18  6 22

 

> ##----------------------- > ## rank() {base package} > ##----------------------- > > # if there are no ties(i.e., equal values), no problem at all > x <- c(1, 5, 9, 7) > rank(x) [1] 1 2 4 3 > > > # if there are ties, ties can be handled in several ways > y <- c(1, 1, 1, 5, 9, 7) > > # returns average, default setting > rank(y) [1] 2 2 2 4 6 5 > rank(y, ties.method = c("average")) [1] 2 2 2 4 6 5 > > # first occurrence wins > rank(y, ties.method = c("first")) [1] 1 2 3 4 6 5 > > # ties broken at random > rank(y, ties.method = c("random")) [1] 3 2 1 4 6 5 > > rank(y, ties.method = c("random")) # ...random one more time [1] 1 3 2 4 6 5 > > rank(y, ties.method = c("random")) # ...random...again [1] 1 2 3 4 6 5 > > # rank by max value as used classically > rank(y, ties.method = c("max")) [1] 3 3 3 4 6 5 > > # rank by min value as in Sports > rank(y, ties.method = c("min")) [1] 1 1 1 4 6 5

 

rank는 순위대로 정렬해주는게 아니라 순위의 색인을 나타내줍니다.

디폴트는 작은 값부터 1을 부여해주고, 큰 것 부터 1을 부여하려면 '-'를 붙여주면 됩니다.

 

동일한 값(Ties, i.e, equal values)이 있을 경우 rank() 함수는 "average" (default), "first", "random", "max", "min" 등의 옵션을 제공합니다.

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡' 단추를 꾸욱 눌러주세요.

 

반응형
Posted by Rfriend

댓글을 달아 주세요