Learn & Record

Python (넘파이 Numpy, 배열 생성, 배열의 연산, 배열 인덱싱과 슬라이싱, 판다스 Pandas) 본문

Dev/Python

Python (넘파이 Numpy, 배열 생성, 배열의 연산, 배열 인덱싱과 슬라이싱, 판다스 Pandas)

Walker_ 2024. 3. 11. 17:09

 

 - Pandas 라이브러리 설치 (Numpy도 자동으로 설치됨)

 

1. 넘파이 Numpy

 - 배열 데이터를 효과적으로 다룰 때 사용

 - 파이썬으로 과학 연산을 쉽고 빠르게 할 수 있게 만든 패키지

 - Numpy를 이용하면 파이썬의 기본 데이터 형식과 내장 함수를 이용하는 것보다 다차원 데이터를 효과적으로 처리 가능

 - Numpy 홈페이지 : http://numpy.org/ 

 

NumPy -

Use the interactive shell to try NumPy in the browser

numpy.org

 

 - 배열 Array 이란 1) 순서가 있는 2) 같은 종류의 데이터가 저장된 집합

 - Numpy를 이용해 배열을 처리하기 위해서는 우선 Numpy로 배열을 생성해야 함

 

 - 다양한 방법으로 배열 생성

# 1. 배열 생성하기
# Numpy는 파이썬의 내장 모듈이 아니라서 별도로 설치

import numpy as np

# 1) 시퀀스 데이터로 부터 배열 생성하기. array()
# 시퀀스 데이터 seq_data를 인자로 받아 Numpy의 배열 객체 array object를 생성
# arr_obj = np.array(seq_data)

data1 = [0,1,2,3,4,5]
print(data1) # [0,1,2,3,4,5]
a1 = np.array(data1)
print(a1) # [0 1 2 3 4 5]
print(a1.dtype) # data type이 int 32

# 정수와 실수가 혼합된 경우
data2 = [0.1, 5, 4, 12, 0.5]
a2 = np.array(data2)
print(a2) # [ 0.1 5. 4. 12. 0.5 ]
print(a2.dtype) # float64. 정수와 실수가 혼합돼 있을 때 모두 실수로 변환

# 숫자와 문자가 있는 경우
data3 = [0.1, 5, 4, 12, 'test']
a3 = np.array(data3)
print(a3) # ['0.1', '5', '4', '12', 'test']
print(a3.dtype) # <U32 -> 길이가 32인 유니코드 문자열

# array()에 직접 리스트를 넣어서 배열 객체도 생성 가능
a3 = np.array([0.5, 2, 0.01, 0])
print(a3) # [0.5, 2.  0.01  0 ]

# 다차원 배열의 생성 예
a4 = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(a4)
# [[1 2 3]
#  [4 5 6]
#  [7 8 9]]

# 2) 범위를 저장해 배열 생성. arange()
# arange()를 이용해 Numpy 배열을 생성. 파이썬의 range()와 사용방법이 비슷
# arr_obj = np.arange([start,] stop[, step])
# start부터 시작해서 stop 전까지 step 만큼 계속 더해 NumPy 배열을 생성
# start가 0인 경우에는 생략가능
# step이 1인 경우에는 생략가능

a1 = np.arange(0, 10, 2)
print(a1) # [0 2 4 6 8]

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

a3 = np.arange(5)
print(a3) # [0 1 2 3 4]

# NumPy 배열의 arange()를 이용해 생성한 1차원 배열에 reshape(m, n)을 추가하면 m*n 형태의 2차원 배열(행렬)로 변경
# 주의할 점은 arange()로 생성되는 배열의 원소 개수와 reshape(m, n)의 m*n의 개수가 같아야 함
a4 = np.arange(12).reshape(4,3)
print(a4)

# NumPy 배열의 형태를 알기 위해서는 'ndarray.shape'를 실행
print(a4.shape) # (4,3)

# 1차원 배열의 경우 '(n, )'처럼 표시
print(a1.shape) # (5,)

# ndarray.linspace()
# 범위의 시작과 끝을 지정하고 데이터의 개수를 지정해 배열을 생성
# arr_obj = np.linspace(start, stop[, num])
# linspace()는 start부터 stop까지 num개의 배열을 같은 간격으로 생성. num을 지정하지 않으면 50이 기본값

a1 = np.linspace(1, 10, 10)
print(a1) # [ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. ]
a2 = np.linspace(1, 10, 4)
print(a2) # [1. 4. 7. 10.] 간격이 3

# 0부터 파이까지 동일한 가격으로 20개를 나눈 배열 생성
a3 = np.linspace(1, np.pi, 20)
print(a3)
# [1.         1.1127154  1.22543081 1.33814621 1.45086161 1.56357701
#  1.67629242 1.78900782 1.90172322 2.01443863 2.12715403 2.23986943
#  2.35258483 2.46530024 2.57801564 2.69073104 2.80344645 2.91616185
#  3.02887725 3.14159265]

# 3) 특별한 형태의 배열 생성
# 모든 원소가 0 혹인 1인 다차원 배열을 만들기 위해서는 zeros()와 ones()를 이용

# 원소가 0이고 개수가 10개인 1차원 배열 생성
a1 = np.zeros(10)
print(a1)

# 3 * 4의 2차원 배열을 생성
a2 = np.zeros((3,4))
print(a2)
# [[0. 0. 0. 0.]
#  [0. 0. 0. 0.]
#  [0. 0. 0. 0.]]

a3 = np.ones(5)
print(a3) # [1. 1. 1. 1. 1.]

# 4) 배열의 데이터 타입 변환
# 배열은 숫자뿐만 아니라 문자열도 원소를 가질 수 있음

# 문자열이 원소인 배열 생성 예
a1 = np.array(['1.5', '0.62', '2', '3.14', '3.141592'])
print(a1) # ['1.5' '0.62' '2' '3.14' '3.141592']
print(a1.dtype) # <U8. 데이터 형식이 유니코드이며 문자의 수는 최대 8개라는 것을 의미

# NumPy 데이터의 형식.
# b : 불. bool
# i : 기호가 있는 정수. (signed) integer
# u : 기호가 없는 정수. unsigned integer
# f : 실수. floating-point
# c : 복소수. complex-floating point
# M : 날짜. datetime
# O : 파이썬 객체. (Python) objects
# S or a : 바이트 문자열. (byte) string
# U : 유니코드. Unicode

# 배열이 문자열(숫자 표시)로 돼 있다면 연산을 위해서는 문자열을 숫자(정수나 실수)로 변환해야 함
# 형 변환은 astype()로 가능
# num_arr = str_arr.astype(dtype)

# 실수가 입력된 문자열을 원소로 갖는 배열을 실수타입으로 변환하는 예
str_a1 = np.array(['1.567', '0.123', '5.123', '9', '0'])
num_a1 = str_a1.astype(float)
print(num_a1) # [1.567 0.123 5.123 9.    0.   ]
print(str_a1.dtype) # <U5
print(num_a1.dtype) # float64

# 정수를 문자열 워소로 갖는 배열을 정수로 변환하는 예
str_a2 = np.array(['1', '3', '5', '7', '9'])
num_a2 = str_a2.astype(int)
print(num_a2)
print(str_a2.dtype)
print(num_a2.dtype)

# 5) 난수 배열의 생성
# NumPy에서 난수를 발생시킬 수 있는 다양한 함수가 있음
# rand() 함수를 이용하며 실수 난수를 요소로 갖는 배열을 생성
# randint() 함수를 이용하면 정수 난수를 요소로 갖는 배열을 생성
# rand_num = np.random.rand([d0, d1 ..., dn])
# rand_num = np.random.randint([low,] high [, size])

# rand() 함수는 [0,1) 사이의 시수 난수를 갖는 배열을 생성
# * [a,b)의 펴현은 값의 범위가 a이상이고 b 미만이라는 의미

# randint() 함수는 [low, high) 사이의 정수 난수를 갖는 배열을 생성
# size는 배열의 형태 지정
# low가 입력하지 않으면 0으로 간주
# size가 입력되지 않으면 1로 간주

a1 = np.random.rand(2, 3)
print(a1)
# [[0.04033988 0.92889488 0.50857354]
#  [0.78680406 0.68580141 0.68657928]]

a3 = np.random.rand(1, 2, 3)
print(a3)
# [[0.24795877 0.63317149 0.19529521]
#  [0.26287849 0.44237606 0.93189269]]
# [[[0.31005606 0.45917568 0.51642832]
#   [0.35282887 0.49928523 0.89060892]]]

a4 = np.random.randint(10, size=(3,4)) # 0부터 9까지의 정수 난수를 요소로 가지는 3 * 4 배열을 생성
print(a4)

a5 = np.random.randint(1, 30)
print(a5)

a6 = np.random.randint(1, 30, 3)
print(a6) # [ 6 14  8]

 

 - 2. 배열의 연산

# 1) 기본 연산
# 배열의 형태 shape가 같다면 덧셈과 뺄셈, 곱셈과 나눗셈 연산을 할 수 있음

arr1 = np.array([10, 20, 30, 40])
arr2 = np.array([1, 2, 3, 4])

# 각 배열의 같은 위치의 원소끼리 더함
print(arr1 + arr2) # [11 22 33 44]

# 두 배열의 차는 같은 위치의 원소끼리 뺌
print(arr1 - arr2) # [ 9 18 27 36 ]

# 배열에 상수를 곱하면 각 원소에 상수를 곱함
print(arr1 * 2) # [20 40 60 80 ]

# 배열의 거듭제곱은 배열의 각 원소에 거듭제곱
print(arr1 ** 2) # [100 400 900 1600 ]

# 두 배열끼리의 곱셈은 각 원소끼리 곱함
print(arr1 * arr2) # [ 10 40 90 160 ]

# 두 배열의 나눗세은 각 원소끼리 나눔
print(arr1 / arr2) # [10. 10. 10. 10.]

# 배열은 비교 연산도 가능. 원소별로 조건과 일치하는지 검사한 후 일치하면 True를, 그렇지 않으면 False를 반환
print(arr1 > 20) # [False False True True]

# 2) 통계를 위한 연산
# NumPy에는 배열의 합, 평균, 표준 편차, 분산, 최솟값, 최댓값, 누적 곱 등 주로 통계에서 많이 이용하는 메서드가 있음
# 각각 sum(), mean(), std(), var(), min(), max(), cumsum(), cumprod()

arr3 = np.arange(5)
print(arr3) # [0 1 2 3 4]

# 합
print(arr3.sum()) # 10
# 평균
print(arr3.mean) # 2.0
# 표준 편차
print(arr3.std()) # 1.4142135623730951
# 분산
print(arr3.var()) # 2.0
# 최솟값
print(arr3.min()) # 0
# 최댓값
print(arr3.max()) # 4

arr4 =np.arange(1, 5)
print(arr4) # [1 2 3 4]
# 누적 합
print(arr4.cumsum()) #[ 1  3  6 10]
# 누적 곱
print(arr4.cumprod()) #[ 1  2  6 24]

 

- 3. 배열의 인덱싱과 슬라이싱

# 배열의 인덱싱
# 1차원 배열에서 특정 위치의 원소를 선택하려면 원소의 위치를 지정
# 배열명[위치]
# 배열 원소의 위치는 0부터 시작

import numpy as np

a1 = np.array([0, 10, 20, 30, 40, 50])

print(a1[0])
print(a1[4])

# 배열을 변경
a1[5] = 70
print(a1) # [0 10 20 30 40 70]

# 1차원 배열에서 여러 개의 원소를 선택
# 배열명[위치1, 위치2, ... , 위치n]

print(a1[[1,3,4]]) # [10 30 40]

# 2차원 배열에서 특정 위치의 원소를 선택하려면 행과 열의 위치를 지정
# 배열명[행_위치, 열_위치]

a2 = np.arange(10, 100, 10).reshape(3,3)
print(a2)
# [[10 20 30]
#  [40 50 60]
#  [70 80 90]]

# 행 위치가 0이고, 열 위치가 2인 원소를 반환
print(a2[0, 2]) # 30
print(a2[0][2])

# 2차원 배열의 행과 열의 위치를 지정해서 원소를 선택한 후 값을 변경할 수 있음
a2[2,2] = 95
print(a2)
# [[10 20 30]
#  [40 50 60]
#  [70 80 95]]

# 2차원 배열의 여러 원소를 선택하기 위해서 아래와 같이 지정
# 배열명[행.위치1, 행,위치2, ... , 행.위치n], [열_위치1, 열_위치2, ... , 열_위치n]]

print(a2[[0,2], [0,1]])
# [10 00]

# 배열에 조건을 지정해 조건을 만족하는 배열을 선택
# 배열명[조건]
a = np.array([1, 2, 3, 4, 5, 6])
print(a[a > 3]) # [4 5 6]

# 짝수만 선택하는 예
print(a[(a % 2) == 0]) # [2 4 6]

# -인덱스도 사용가능
print(a1[-2]) # 40

# 2) 배열의 슬라이싱
# 1차원 배열의 경우 슬라이싱은 배열의 시작과 끝 위치를 지정
# 배열[시작_위치:끝_위치]
# 변환되는 원소의 범위는 '시작_위치 ~ 끝_위치 - 1'
# 시작 위치를 지정하지 않으면 0.
# 끝 위치를 지정하지 않으면 배열이 기이

b1 = np.array([0, 10, 20, 30, 40, 50])
print(b1[1:4]) # [10 20 30]. 1 ~ 3

# 1차원 배열에서 '시작_위치'와 '끝_위치'를 지정하지 않고 슬라이싱하는 예
print(b1[:3]) # [ 0 10 20]. 0 ~ 2

print(b1[2:]) # [ 20 30 40 50]. 2 ~

print(b1[:]) # [ 0 10 20 30 40 50]

# 슬라이싱을 이용해 원소를 변경할 수 있음
b1[2:5] = np.array([25, 35, 45])
print(b1) # [ 0 10 25 60 60 60]. 3~5 변경

 

 - 연습문제

# 넘파이 배열을 사용하여 1부터 20까지의 연속된 정수값을 가지는 1차원 배열을 생성하여
# 실행결과와 같이 출력되기 위해 알맞은 코드를 쓰시오.


# 마지막 원소 : 20
# 모든 원소의 합 : 210
# 모든 원소의 평균 : 10.5
# [[ 1  2  3  4  5]
#  [ 6  7  8  9 10]
#  [11 12 13 14 15]
#  [16 17 18 19 20]]
a1 = np.arange(1,21)

print(f'마지막 원소 : {a1[-1]}')
print(f'모든 원소의 합 : {a1.sum()}')
print(f'모든 원소의 평균 : {a1.mean()}')
print(a1.reshape(4,5))

 

- 연습문제2

# 학생들의 근로 장학금이 넘파이 배열에 저장되어 있다.
# 이번 학기 학생들의 근로장학금을 1.5배 올려주려고 한다.
# 다음은 인상된 근로장학금을 출력하고 근로장학금이 평균 근로장학금보다 많은 학생들의 근로장학금을 출력하고
# 원소의 수를 출력하는 프로그램이다.

import numpy as np

salary = [200, 150, 180, 220, 250]


# 인상된 금액 : [300. 225. 270. 330. 375.]
# 평균 금액 : 300.0
# 평균이상인 원소 : [300. 330. 375.]
# 평균이상인 원소의 개수 : 3
salary= np.array(salary)
up_salary = salary*1.5
print(f'인상된 금액 : {up_salary}')
print(f'평균 금액 : {up_salary.mean()}')
print(f'평균이상인 원소 : {up_salary[up_salary>=up_salary.mean()]}')
print(f'평균이상인 원소의 개수 : {up_salary[up_salary>=up_salary.mean()].size}')

 

 

2. 판다스 Pandas

 - 파이썬에서 데이터 분석과 처리를 쉽게 처리할 수 있게 도와줌

 - Numpy를 기반으로 만들어졌지만 좀 더 복잡한 데이터 분석에 특화

 - Numpy가 같은 데이터 타입의 배열만 처리할 수 있는데 반해 pandas는 데이터 타입이 다양하게 섞여 있어도 처리 가능

 - 공식 홈페이지 : https://pandas.pydata.org/

 

 - 1. 구조적 데이터 생성하기

 - pandas에서 데이터를 생성하는 가장 기본적인 방법은 Series()를 이용하는 것

 - Series()를 이용하면 Series 형식의 구조적 데이터(라벨을 갖는 1차원 데이터)를 생성할 수 있음

 - 다음은 Series()를 이용해 Series 형식의 데이터를 생성하는 방법

 - s = pd.Series(seq_data)

 - Series()의 인자로는 시퀀스 데이터가 들어감

 - 시퀀스 데이터로는 리스트와 튜플 타입의 데이터를 모두 사용할 수 있지만 주로 리스트 데이터를 이용

# 1) Series를 활용한 데이터 생성
import pandas as pd

s1 = pd.Series([10, 20, 30, 40, 50])
print(s1)
# 0 10
# 1 20
# 2 30
# 3 40
# 4 50
# dtype: int64

 


공부 과정을 정리한 것이라 내용이 부족할 수 있습니다.

부족한 내용은 추가 자료들로 보충해주시면 좋을 것 같습니다.

읽어주셔서 감사합니다 :)