SKN/04. Data Analysis

02. numpy [통계] [정렬] [병합]

claovy☘️ 2025. 2. 28. 21:37

1. 통계 기초

01. 모집단과 표본모집단(Population): 연구 대상 전체를 의미하며, 모든 데이터를 포함한다.

    • ex) 특정 나라의 모든 사람의 키 데이터
  • 표본(Sample): 모집단의 일부를 추출한 데이터를 의미하며, 모집단의 특성을 추정하는 데 사용된다.

02. 기술통계와 추론통계

  • 기술통계 : 데이터를 요약하고 설명하는 데 사용되는 통계 기법이다. 평균, 중앙값, 최빈값, 표준편차 등이 포함
  • 추론통계 : 표본 데이터를 사용하여 모집단에 대한 추론을 수행하는 통계 기법이다. 가설 검정, 신뢰 구간 등이 포함

03. 이산값과 연속값

  • 이산값
    • 특정한 값을 가지는 데이터로, 정해진 간격이나 구간 안에서만 나타난다
    • 값들이 셀 수 있는 숫자처럼 구분되어 있어 중간값이 없다
    • ex) 주사위 눈(1, 2, 3, 4, 5, 6), 사람 수(1명, 2명, 3명 등)
    • 데이터의 값은 유한하거나 명확하게 구분될 수 있다.
  • 연속값
    • 측정할 수 있는 모든 값을 포함하는 데이터로, 구간 내의 어떠한 값도 가능하다.
    • 무한한 소수점 단위까지 값을 가질 수 있어, 값 사이에 중간값이 존재할 수 있다
      • ex )몸무게(55.5kg, 60.7kg 등), 온도(20.3°C, 21.8°C 등) 
    • 데이터의 값은 연속적이어서 값들 간의 경계가 모호하다

04. 중심 경향 측도

# 평균
arr = np.array([10, 20, 30, 40])
print(np.mean(arr))  # 25.0

# 중앙값
print(np.median(arr))  # 25.0

# 최빈값
from scipy import stats #. NumPy에는 내장 함수가 없지만, scipy.stats 패키지를 이용해 계산할 수 있다.

arr = np.array([10, 20, 20, 30, 40])
print(stats.mode(arr))  # Mode: 20

 

🤔 그렇다면, 우리반의 평균 키와 최빈값을 구해보자!

height = np.array([160, 170, 180, 150, 150, 155, 165, 175, 185, 180, 175, 170, 173, 164, 189, 175])

# 평균값
print(np.mean(height))

# 정렬
print(np.sort(height))

# 중앙값
print(np.median(height))

# 최빈값 --> 중복값을 제외하고 고유한 값 / 그 갯수 
values, count = np.unique(height, return_counts = True)
print(values,count)

# 최빈값 
most = np.max(count)
print(most == count) # boolean으로 해당값의 True, False 여부를 확인해줌 
print(values[count == most])

[출력]
169.75
[150 150 155 160 164 165 170 170 173 175 175 175 180 180 185 189]
171.5
[150 155 160 164 165 170 173 175 180 185 189] [2 1 1 1 1 2 1 3 2 1 1]
[False False False False False False False  True False False False]
[175]

 

05. 산포 측도

# 분산 : 데이터가 평균으로부터 얼마나 떨어져있는지 / 클수록 퍼져있음
print(np.var(arr))  # 125.0

# 표준편차 : 분산의 제곱근
print(np.std(arr))  # 11.1803

# 범위 : 데이터의 최댓값과 최솟값의 차이
print(np.max(arr) - np.min(arr))  # 30

 

06. 확률과 확률분포

  • 확률 : 특정 사건이 발생할 가능성을 0과 1의 사이의 값으로 나타낸다. 1에 가까울수록 가능성이 크다
  • 확률분포 : 확률 변수가 가질 수 있는 값과 그 값이 나올 확률을 나타내는 함수
    • ex) 각 경우가 나올 확률이 균등한 균등분포 (주사위)

07. 정규분포와 균등분포

  • 정규분포 : 평균을 중심으로 데이터가 대칭적으로 분포하며, 종 모양의 분포를 나타낸다. 정규분포에서는 평균 근처의 값이 자주 나타나고, 양 끝으로 갈수록 빈도가 감소한다.
arr = np.random.randn(1000)  # 평균 0, 표준편차 1인 정규분포 난수 1000개
print(np.mean(arr), np.std(arr))
[ 68-95-99.7 규칙 ]
정규 분포를 나타내는 규칙으로, 경험적인 규칙(empirical rule)이라고도 한다.

3시그마 규칙(three-sigma rule)이라고도 하는데 이 때는 평균에서 양쪽으로 3표준편차의 범위에 거의 모든 값들(99.7%)이 들어간다는 것을 나타낸다.

- 약 68%의 값들이 평균에서 양쪽으로 1 표준편차 범위 '1시그마' 에 존재한다.
- 약 95%의 값들이 평균에서 양쪽으로 2 표준편차 범위 '2시그마' 에 존재한다.
- 거의 모든 값들(실제로는 99.7%)이 평균에서 양쪽으로 3표준편차 범위 '3시그마' 에 존재한다.
  • 균등분포 : 모든 값이 동일한 확률로 발생하는 분포를 의미한다.
    • 0.0 이상 ~ 1.0 미만 수에서 균등하게 난수 추출 
    • np.random.randint(start, end, size) => start 이상 end 미만의 난수를 size 만큼 추출
arr = np.random.uniform(0, 1, 1000)  # 0과 1 사이의 균등분포 난수 1000개
print(np.mean(arr), np.std(arr))

2. ndarray 정렬

01. 기본 배열 정렬

1차원 배열 정렬
arr = np.random.randint(1, 11, 10)
print(arr)

[출력]
[10  1  2  1  4  4 10  2  2  2]
# np.sort(arr) : 정렬된 ndarray를 반환
print(np.sort(arr))
print(np.sort(arr)[::-1]) # 내림차순 정렬
print(arr)

[출력]
[2 2 3 3 4 6 8 9 9 9]
[9 9 9 8 6 4 3 3 2 2]
[4 3 9 9 2 6 8 2 3 9]

-1 인덱싱을 사용하여 내림차순 정렬도 가능하다

2차원 배열 정렬
arr = np.random.randint(10, size=(3, 4)) # 0 이상 10 미만
print(arr)

[출력]
[[1 5 7 9]
 [8 9 2 8]
 [8 6 4 7]]

 

02. 특정 축을 기준으로 정렬 

print(np.sort(arr, axis=0)) # 행 방향 정렬 (같은 열 안에서 정렬)
print(np.sort(arr, axis=1)) # 열 방향 정렬 (같은 행 안에서 정렬) ⭐기본값 
print(np.sort(arr, axis=None).shape) # axis = None 축 무시 (행/열 구분없이 모든 값 정렬)

[출력]
[[1 5 2 7]
 [8 6 4 8]
 [8 9 7 9]]
[[1 5 7 9]
 [2 8 8 9]
 [4 6 7 8]]
(12,)
(12,)

 

03. 인덱스를 반환하는 정렬

💡np.argsort
- 배열의 값을 정렬했을 때, 각 값의 원래 인덱스를 반환
- 정렬할 때 어떤 순서로 값을 배치해야 하는지 알려주는 인덱스를 반환
- 배열의 값을 정렬한 후, 정렬된 순서에 해당하는 인덱스를 반환

(1) 1차원 배열에서 argsort 사용

names = np.array(['리사','로제','제니','지수'])
album_sales = np.array([900, 870, 1000, 670])

result = np.argsort(album_sales)
print(names[result][::-1])

[출력]
['제니' '리사' '로제' '지수']

 

(2) 2차원 배열에서 argsort 사용

# 2차원 배열에서 argsort
arr = np.array([[2025, 2, 28],[17, 18, 30]])
print(arr)
print(np.argsort(arr))
print(np.argsort(arr, axis=1)) # 열 방향 정렬의 순서 (같은 행 안에서 정렬)
print(np.argsort(arr, axis=0)) # 행 방향 정렬의 순서 (같은 열 안에서 정렬)

[출력]
[[2025    2   28]
 [  17   18   30]]
[[1 2 0]
 [0 1 2]]
[[1 2 0]
 [0 1 2]]
[[1 0 0]
 [0 1 1]]

3. ndarray 병합

01. 배열 병합이란

배열 병합은 여러 개의 배열을 연결하여 하나의 배열로 만드는 방법이다. NumPy에서 배열을 병합하는 방법은
np.concatenate(), np.vstack(), np.hstack() 등의 함수를 사용한다.

 

02.  np.append()

arr1 = np.arange(1, 13).reshape(3,4)
arr2 = np.arange(13, 25).reshape(3,4)
arr1, arr2

[출력]
(array([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9, 10, 11, 12]]),
 array([[13, 14, 15, 16],
        [17, 18, 19, 20],
        [21, 22, 23, 24]]))
print(np.append(arr1,arr2))
print(np.append(arr1, arr2, axis=0)) # 행 기준 병합 
print(np.append(arr1, arr2, axis=1)) # 열 기준 병합

[출력]
[ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24]
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]
 [13 14 15 16]
 [17 18 19 20]
 [21 22 23 24]]
[[ 1  2  3  4 13 14 15 16]
 [ 5  6  7  8 17 18 19 20]
 [ 9 10 11 12 21 22 23 24]]

 

03. 수직 수평 배열병합

  • vstack, hstack에서 병합 대상은 튜플 또는 리스트 형태로 묶어줘야 한다

(1) np.vstack

  • axis = 0 병합과 같다
print(np.vstack((arr1, arr2)))

 

(2) np.hstack

  • axis = 1 병합과 같다
print(np.hstack([arr1, arr2]))

 


4. ndarray 분할 

01. np.split()

print(np.split(arr, 2)) # 원본배열, 분할할 갯수, axis 
print(np.split(arr, 2, axis=0))
print(np.split(arr, 2, axis=1))

[출력]
[array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]]), array([[13, 14, 15, 16],
       [17, 18, 19, 20],
       [21, 22, 23, 24]])]
[array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]]), array([[13, 14, 15, 16],
       [17, 18, 19, 20],
       [21, 22, 23, 24]])]
[array([[ 1,  2],
       [ 5,  6],
       [ 9, 10],
       [13, 14],
       [17, 18],
       [21, 22]]), array([[ 3,  4],
       [ 7,  8],
       [11, 12],
       [15, 16],
       [19, 20],
       [23, 24]])]

5. ndarray 형태변경

01. 1차원 => 2차원 형태 변경

arr = np.arange(12)
print(arr.ndim, arr)

[출력]
1 [ 0  1  2  3  4  5  6  7  8  9 10 11]
arr = arr.reshape(3, 4)
# arr = arr.reshape(2, 7) # error !!! 2행 7열을 만들기 위한 요소가 부족하다 
print(arr.ndim, arr.shape)
print(arr)

[출력]
2 (3, 4)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

 

02. 2차원 => 다차원 형태 변경

arr = arr.reshape(2,2,3)
# arr = arr.reshape(2,2,2) 얘는 안돼요!!
print(arr.ndim, arr.shape)
print(arr)

[출력]
3 (2, 2, 3)
[[[ 0  1  2]
  [ 3  4  5]]

 [[ 6  7  8]
  [ 9 10 11]]]

 

03. 다차원 => 1차원

reshape(-1)
# reshape() -> -1
arr = arr.reshape(-1)
print(arr)

[출력]
[ 0  1  2  3  4  5  6  7  8  9 10 11]

arr = arr.reshape(4, -1)
print(arr)

[출력]
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]

arr = arr.reshape(-1, 4)
print(arr)

[출력]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

 

np.ravel()
arr1 = np.arange(50).reshape(5,10)
print(arr)
print(np.ravel(arr))

[출력]
[[ 0  1  2  3  4  5  6  7  8  9]
 [10 11 12 13 14 15 16 17 18 19]
 [20 21 22 23 24 25 26 27 28 29]
 [30 31 32 33 34 35 36 37 38 39]
 [40 41 42 43 44 45 46 47 48 49]]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
 48 49]

 

04. 차원 확장

np.expand_dims 
  • 요소의 변화는 없지만, 차원의 수를 늘려 shape을 구성한다
# 1차원 -> 2차원
arr2 = np.arange(10)
print(arr2.shape, arr2)
print(np.expand_dims(arr2, axis=0))
print(np.expand_dims(arr2, axis=0).shape)
print(np.expand_dims(arr2, axis=1))
print(np.expand_dims(arr2, axis=1).shape)

[출력]
(10,) [0 1 2 3 4 5 6 7 8 9]
[[0 1 2 3 4 5 6 7 8 9]]
(1, 10)
[[0]
 [1]
 [2]
 [3]
 [4]
 [5]
 [6]
 [7]
 [8]
 [9]]
(10, 1)
# 2차원 => 3차원
arr3 = np.array([[1, 2],[3, 4]])
print(arr2.shape, arr2)

print(np.expand_dims(arr3, axis=0))
print(np.expand_dims(arr3, axis=0).shape)  # 0번 인덱스에 차원 추가 
print(np.expand_dims(arr3, axis=1))
print(np.expand_dims(arr3, axis=1).shape) # 1번 인덱스에 차원 추가 
print(np.expand_dims(arr3, axis=2))
print(np.expand_dims(arr3, axis=2).shape)

[출력]
(2, 2) [[1 2]
 [3 4]]
[[[1 2]
  [3 4]]]
(1, 2, 2)
[[[1 2]]

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

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

 

05. 차원 축소

np.sqeeze()
  • 차원의 값이 1일 때 제거
# np.sqeeze()
arr = np.array([[1, 2]])
print(arr.shape)

arr2 = np.squeeze(arr)
arr2 = np.squeeze(arr, axis = 0)
# arr2 = np.squeeze(arr, axis = 1) # 차원의 값이 2라서 제거 불가능능
print(arr2.shape)

[출력]
(1, 2)
(2,)

 

'SKN > 04. Data Analysis' 카테고리의 다른 글

05. matplotlib  (0) 2025.03.06
04. 데이터 결측치 확인  (0) 2025.03.06
03. pandas overview  (0) 2025.03.04
01. numpy overview  (1) 2025.02.28