ㅅㅇ

numpy _ 04_2 범용함수(Ufunc, Universal function) 본문

AI_STUDY/Numpy

numpy _ 04_2 범용함수(Ufunc, Universal function)

SO__OS 2022. 6. 24. 00:27
플레이데이터 빅데이터캠프 공부 내용 _ 6/23

numpy _ 04_2 범용함수(Ufunc, Universal function)

1. 범용함수란

- 벡터화를 지원하는 넘파이 연산 함수들.


    - 유니버셜 뜻이 "전체에 영향을 미치는" 이다.

       그래서 이 함수는 배열의 원소 전체에 영향을 미치는 기능을 제공하는 함수다.

   - 배열의 원소별로 연산 을 처리하는 함수들


- 반복문을 사용해 연산하는 것 보다 유니버셜 함수를 사용하는 것이 속도가 빠르다.

 

2. 주요 범용함수

2.1 단항 범용함수 (unary ufunc)

매개변수로 한개의 배열을 받는다.
    - 한 배열내의 원소별로 연산

 

2.2  이항 범용함수

매개변수로 두개의 배열을 받는다.
    - 두 배열의 같은 index 원소별로 연산

 

- 단항 함수 예제

# 단항함수
a = np.array([-3.5, 2.8, 4.2])

# 절대값 반환
print(np.abs(a))

# 제곱근 반환
# print(np.sqrt(a)) # 음수 -3.5의 제곱근 계산이 안되므로 non(결측치)를 반환
print(np.sqrt(np.abs(a))) # 음수일 때, abs()와 함께 쓰면 해결.

# 실수부, 정수부 나눠서 반환
print(np.modf(a))

# np.nan : 결측치를 표현하는 numpy 변수
b = np.array([10, 5, np.nan, 2, np.nan])

# 각 원소별로 결측치 여부를 확인
print(np.isnan(b))

# 결측치의 갯수 # T:1 , F:0 로 변환해서 합계를 구한다.
print(np.sum(np.isnan(b)))
[3.5 2.8 4.2]
[1.87082869 1.67332005 2.04939015]
(array([-0.5,  0.8,  0.2]), array([-3.,  2.,  4.]))
[False  False  True False  True]
2
 

- 이항 함수 예제

# 이항함수
x = np.arange(1,6)
y = np.arange(11,16)

print(np.add(x,y))
print(np.subtract(x,y))
print(np.multiply(x,y))

# 나누기 연산자 x/y
print(np.divide(x,y))

# 몫 연산자 y//x
print(np.floor_divide(y,x))

# 나머지 연산자 x%y
print(np.mod(x,y))

# 같은 index의 값 중 큰 것 / 작은 것 반환
print(np.maximum(x,y), np.minimum(x,y))

# x > y 결과 bool 
print(np.greater(x,y))
[-10 -10 -10 -10 -10]
[11 24 39 56 75]
[0.09090909 0.16666667 0.23076923 0.28571429 0.33333333]
[11  6  4  3  3]
[1 2 3 4 5]
[11 12 13 14 15] [1 2 3 4 5]
[False False False False False]

 

2.3 연산결과 출력 지정

 

- 범용함수의 연산은 계산 결과를 담은 새로운 배열을 생성해서 반환한다.
    - - > 연산결과를 특정 배열에 넣을 수 있다.

 

- 0으로 채워진 (3,3) 구조인 result 배열에 연산 결과를 넣는다.

a = np.arange(11,20).reshape(3,3)
b = np.arange(1,10).reshape(3,3)
result = np.zeros(shape = (3,3)) # 0으로 채워진 (3,3) 구조

np.add(a,b, out = result)
result

 

3. 누적 연산 함수

3.1 누적연산함수 - reduce()

 

- 결과가 하나만 남을 때 까지 해당 연산을 배열의 모든 요소에 반복 해서 적용


- 구문
    - np.이항범용함수이름.reduce(배열, axis=0)


- 처리결과의 축의개수(rank)는 하나 줄어 든다.
     - 1차원 -> 스칼라
     - 2차원 - 1차원
         - axis 0 방향으로 연산 또는 axis 1 방향으로 연산
     - 3차원 - 2차원
     - n 차원 - n-1차원

 

 

1) 예제 : 1차원 배열 = > 스칼라

x = np.arange(1,11) # [ 1  2  3  4  5  6  7  8  9 10]
print(x)

# 누적합계
r = np.add.reduce(x)
print(r)

# 누적 제곱 (첫번째 배열을 두번째 배열로 제곱)
r = np.power.reduce(x)
r
[ 1  2  3  4  5  6  7  8  9 10]
55
1

 

 

 2) 예제 : 2차원 배열 => 1차원 배열

x = np.arange(1,16).reshape(3,5)
print(x.shape)
x
(3, 5)
 
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15]])

 

- axis = 0 (def)

r = np.add.reduce(x) # axis = 0
print(np.shape(r))
r
(5,)
 
array([18, 21, 24, 27, 30])

 

- axis = 1

r = np.add.reduce(x, axis = 1)
print(np.shape(r))
r
(3,)
 
array([15, 40, 65])

 

- axis = None  :   flatten(1차원배열) 후 처리 : 전체 합계 

r =np.add.reduce(x, axis = None)
r
120

 

 

3.2 누적연산함수 - accumulate()

 

- 배열의 원소들에 해당연산을 누적해 적용


- 처리경과의 축의개수(rank)는 피연산자배열과 동일하다.


- 구문
    - np.이항범용함수이름.accumulate(배열, axis=0)

 

 

(1)  1차원 배열

x = np.arange(1,11) # array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
np.add.accumulate(x)
array([ 1,  3,  6, 10, 15, 21, 28, 36, 45, 55], dtype=int32)

 

(2) 2차원 배열

x2 = np.arange(1,16).reshape(3,5)
print(x2.shape)
x2
(3, 5)
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15]])

 

- axis = 0 (def)

r = np.add.accumulate(x2) # axis = 0
print(r.shape)
r
(3, 5)
 
array([[ 1,  2,  3,  4,  5],
       [ 7,  9, 11, 13, 15],
       [18, 21, 24, 27, 30]], dtype=int32)

 

- axis = 1

r = np.add.accumulate(x2, axis = 1)
print(r.shape)
r
(3, 5)
 
array([[ 1,  3,  6, 10, 15],
       [ 6, 13, 21, 30, 40],
       [11, 23, 36, 50, 65]], dtype=int32)

 

- accumulate 는 axis를 None으로 지정할 수 없다.
   r = np.add.accumulate(x2, axis = None)

 

 

(3) .accumulate   .reduce  활용 예제

 

- 과일별 판매량 조회

  axis =0 : 날짜,   axis 1: 과일

# 열 : 판매수량 [사과, 배, 귤]
# 행 : 날짜별 판매

amt = [
    [10,5,7],
    [15,3,10],
    [1,23,10],
    [10,12,50]
]
amt_arr = np.array(amt)

 

- 과일별 총 판매량, 날짜별 총 판매량

# 과일별 총 판매량
np.add.reduce(amt_arr)

# 날짜별 총 판매량
np.add.reduce(amt_arr, axis =1)
array([36, 43, 77])
array([22, 28, 34, 72])

 

-  날짜별로 총판매량 (과일별, 날짜별 누적판매량)

np.add.accumulate(amt_arr)
array([[10,  5,  7],
       [25,  8, 17],
       [26, 31, 27],
       [36, 43, 77]], dtype=int32)

 

4. 기술통계함수

- 배열 원소를 대상으로 통계 결과를 계산해 주는 함수들


- 구문
    1. np.전용함수(배열)
        - np.sum(x)


    2. 일부는 `배열.전용함수()` 구문 지원
        - x.sum()


- 배열의 원소 중 누락된 값(NaN - Not a Number)이 하나라도 있을 경우 연산의 결과는 NaN으로 나온다.      

  
- 안전모드 함수
    - 배열내 누락된 값(NaN)을 무시하고 계산
    - np.전용함수(배열) 구문만 가능

 

4.1 1차원 배열 

 

(1) 기본 예제 

x = np.random.randint(1,100,5) 

# max, min
print(np.max(x), np.min(x),sep=',')
print(x.max(), x.min(), sep=',')

# argmax, argmin : 최대/최소값의 index
print(np.argmax(x), np.argmin(x), sep=',')

 

- 가중평균  :   np.average(값, weights= 가중치)

   =  (값과 가중치의 가중합) / 가중치 총합

   =  s @ w / w.sum

w = np.array([2,3,1])
s = np.array([100,80,90])

# 산술평균
print(np.mean(s), s.mean())

# 가중평균 : (값과 가중치의 가중합)을 (가중치총합)으로 나눈다.
# s@w/w.sum()
print(np.average(s, weights = w))

 

- 분위수  :  quantile(), percentile()

   - > 오름차순 정렬 후 등분했을 때 등분된 위치의 값

 

     - quantile()   :    q = 분위 0 ~ 1 비율

x = np.random.randint(1, 1000, 11)

# 중앙값/중위수 (오름차순 정렬 후 2등분했을 때 등분된 위치의 값)
np.median(x)

# 4분위수  q = 분위 0 ~ 1 비율
np.quantile(x, q = [0.25, 0.5, 0.75])

# 10분위수
np.quantile(x, q = np.arange(0.1,1.0,0.1))

 

    -  percentile()  :  백분위 기준으로 분위수를 계산 - q = 0~100 사이 실수

x = np.arange(0,101)
np.percentile(x, q =10), np.quantile(x, q = 0.1)
np.percentile(x, q =[1,2]), np.quantile(x, q = [0.01, 0.02])
(10.0, 10.0)
(array([1., 2.]), array([1., 2.]))

 

(2) 예제 : 결측치가 있는 배열

-  x.nanmean() 안됨

# 결측치가 있는 배열
x = np.array([10,2,20,7,np.nan,90,100])

# 결측치가 있으면 결과는 nan (결측치를 포함해서 계산하기 때문)
np.sum(x), np.mean(x), np.max(x), np.min(x), np.var(x), np.std(x)

# 안전모드. 결측치 빼고 계산
np.nansum(x), np.nanmean(x), np.nanmax(x), np.nanmax(x)
(nan, nan, nan, nan, nan, nan)

(229.0, 38.166666666666664, 100.0, 100.0)
 

 

4.2 다차원 배열

- axis(계산 기준 축) 지정해야 함.

   = None (def ) :  flatten 후 계산. 전체통계

 

(1) 예제 : 2차원 배열 

x = np.arange(24).reshape(4,6)

# 기본값 axis = None 전체기준 통계값(합계)
np.sum(x)

# axis = 0 (합계)
np.sum(x, axis = 0)

# axis =1 (평균)
np.mean(x, axis = 1)

 

 

(2) 예제 : 결측치가 있는 배열

 

-  x.nanmean() 안됨

# 결측치가 있는 배열
x = np.arange(12).reshape(3,4)
x = x.astype(np.float32)
x[0,0] = np.nan
array([[nan,  1.,  2.,  3.],
       [ 4.,  5.,  6.,  7.],
       [ 8.,  9., 10., 11.]], dtype=float32)

 

- 결측치 포함하면 결과도 결측치

np.sum(x, axis = 0)
np.sum(x, axis = 1)
array([nan, 15., 18., 21.], dtype=float32)
array([nan, 22., 38.], dtype=float32)
 
 
- 안전모드
np.nansum(x, axis = 0)
np.nansum(x, axis = 1)
array([12., 15., 18., 21.], dtype=float32)
array([ 6., 22., 38.], dtype=float32)

 

 

 
- 결측치 갯수 세기  :  axis=None 전체 isnan 에 대해 
np.sum(np.isnan(x))
1

 

- 결측치 갯수 세기 :   0 축 기준 결측치 개수

np.sum(np.isnan(x), axis=0)
array([1, 0, 0, 0])
 

 

5. boolean indexing 과 sum()/mean()

- sum(boolean indexing) : 특정 조건을 만족하는 원소의 개수
- mean(boolean indexing) : 특정 조건을 만족하는 원소의 비율

 

1) boolean indexing

 

# 원소 중 50 이상의 값을 조회
x[x>=50]

# 원소 중 50 이상의 값의 위치(index) 조회
np.where(x>=50)

 

 

2)  sum(boolean indexing) : 특정 조건을 만족하는 원소의 개수

 

-  boolean 타입 배열 - > 계산(sum)  : True=1, False=0

# 월소 중 50 이상의 값의 개수
np.sum(x >=50)

 

 

3)  mean(boolean indexing) : 특정 조건을 만족하는 원소의 비율

 

# 원소 중 50 이상의 값의 비율
# true=1 을 다 더해서 / 원소 전체 갯수
np.mean(x>=50)

 

 

4) .any : 원소 중 한 개라도 만족하는가? 

    .all : 모든 원소가 만족하는가?

 

# 원소 중에 50 이상인 값이 한 개 이상 있는지 여부
np.any(x>=50)
# 모든 원소들이 50이상인지 여부
np.all(x>=50)

 

'AI_STUDY > Numpy' 카테고리의 다른 글

numpy _ 04_3 브로드캐스팅  (0) 2022.06.24
numpy _ 04_1 벡터 연산  (0) 2022.06.24
numpy _ 02_2 정렬  (0) 2022.06.24
numpy _ 02_1 배열의 원소 조회  (0) 2022.06.24
numpy _ 01_2 배열 생성  (0) 2022.06.23