본문 바로가기
Robot/22년도 자율주행 테크니션 양성과정 일지록

[파이썬] DAY13 Numpy(복습완료)

by 9루트 2022. 2. 4.

C에서도 배열의 이름은 배열의 시작 주소이지만

C와 달리 파이썬 배열은 동적 할당이므로

배열의 사이즈를 미리 지정할 필요가 없고

자료형 또한 지정해줄 필요가 없다는 점에서 차이가 있다.

 

그러나 파이썬은 데이터가 많아질수록 C에 비해 처리 시간이 어마어마하게 길어진다.

무수히 많은 데이터를 일괄적으로 처리해야하는 기계 학습 분야에서는 파이썬의 기본 리스트로 데이터를 배열하는 데 충분하지 않다. 시간이 매우 오래 걸리기 때문이다.

따라서 많은 영역의 데이터를 빠르게 처리할 순 없을까 고민에서 나온 것이 'Numpy'이다.

즉, 데이터의 연산 속도를 중요시 하면서 데이터 과학자들은 기본 리스트 대신에 넘파이를 사용하게 되었다.

 

파이썬의 리스트는 객체(리스트의 칸막이 공간)에 각 데이터의 주소값을 저장하지만,

넘파이의 배열은 객체(배열의 칸막이) 에 아예 데이터의 값을 저장하여 시간을 단축한다. (JAVA의 배열 구조 비슷하다.)

 

 

수업 중에 사용했던 코랩은 인공지능에서의 데이터 처리 과정을 용이하게 하기 위해 만들어진 IDE(보조 프로그램)으로 NUMPY 같은 외부 모듈을 따로 설치해야할 필요 없이 모두 셋팅 되어 있다. (감사하게도 open CV도 이미 셋팅되어 있다.)

반면 아나콘다나 실행파일에서는 Numpy는 외부모듈이 없으므로  PIP 호출명령으로 넘파이 설치하며 환경 구축을 해야하는 번거로움이 있다.

따라서 수업에서는 코랩을 사용하여 Numpy를 익혀보도록 한다.

 

 

 

cf) 코딩할 때 유용한 팁 :  키워드 자동완성이 안뜬다면 ctrl + space을 하자

 

1. 넘파이 기본 지식

1. Numpy란?

파이썬을 위한 행렬 라이브러리

다차원 구현과 연산이 가능하다. (차원은 이해하기 쉽게 주머니로 생각하자)

리스트와 달리 가변 배열이 불가능하여  넘파이의 배열은 연산을 할 때 각 차원마다의 사이즈가 동일하게 대응 되어야 한다.(이건 리스트도 마찬가지)

 

2. Numpy의 특징

과학적인 계산을 위해 만들어진 형태(선형 대수와 관련된 다양한 기능이 가능하고 특히 행렬 연산에 특화되어있다.)

일반 리스트에 비해 빠르고 메모리 효율적으로 사용(행렬 연산 시에 반복문 사용을 생략할 수 있다.)

정적 할당 방식으로 사이즈가 고정되어 있다.

 


3. 넘파이 배열 a = np.array(데이터)

데이터는 리스트 형태로 입력을 받는다.

numpy를 np로 쓰겠다.

배열 [1, 2, 3, 4]를 넘파이 배열로 만드는 과정이다.

튜플 형태의 데이터도 리스트로 인식하여 넘파이 배열로 만들어준다.

turple을 넣어도 list로 받는다.

 

a1과 괄호(  )가 있는 a2 모두 튜플 데이터이고

a1 뿐만 아니라 a2 형태도 np.array(  )에 넣으면 list로 받는다.

 

단 데이터는 단 하나의 구조만 받는다.

예를 들면

a = np.array([1,2,3],[4,5,6])

은 에러가 뜬다.

넘파이 배열을 만들 때는 구조를 단 하나만 받아 넘파일 배열로 만든다.

따라서 여러 개의 구조를 데이터 부분에 넣지 말자


2. 넘파이의 여러 함수

1. 배열.ndim

몇 차원으로 이루어졌는지 나온다. (최대 차원)

이름(arr)에 가까우면 고차원이고 이름(arr)에서 멀면 저차원으로 기억하자

차원은  [ ] (주머니)의 갯수로 보면 편하다.

[ [ 0, 0, 0] [ 0, 0, 0] ] 을 보면 2차원 [ ]  안에 1차원인 [0, 0, 0]가 나열되어 있으므로 2차원이다.

 

2. 배열.shape

각 차원별로 크기(차원의 형상)를 보여준다.

arr..ndim을 통해 해당 데이터가 4차원이라는 것을 보여준다.

해당 데이터의 차원별로 크기 (데이터의 형상)은 다음과 같다.

3개의 4차원 안에 각각 2개의 3차원이 있고

각 3차원 안에 3개의 2차원이 있고 각 2차원 안에 10개의 1차원이 있음을 의미한다.

따라서 arr.shape를 하면 (3, 2, 3, 10)이 나타난다.

 

 

3.np.zeros([4,3])

0으로 채워진 4 X 3 배열(행렬)을 만들겠다.

 

4. np.ones([4,3])

4개의 2차원 안에 3개의 1차원을 만들겠다. ( 총 2 차원)

1로 채워진 4 X 3배열(행렬)을 만들겠다.

 

 

5. arange(시작값, 끝값, 증감값(생략가능))

시작값을 입력하지 않으면 자동적으로 0 부터 시작하고

끝값을 포함하지 않는다.

0부터 9까지의 순차적으로 수가 나온다.
1부터 9까지의 홀수만 나온다.

 

6. full(차원의 형상, 특정숫자)

차원의 형상 안에 각 차원의 크기 만큼 특정 숫자로 채워넣는다.

1차원인 넘파이 배열을 만드려면 다음과 같다.

2로 3칸이 채워진다.

2차원인 넘파이 배열은 다음과 같다. 차원의 형상이라고 구분 짓기 위해 ( ) 괄호를 쓴다.

2로 채워진 3X4 행렬이 만들어진다.

7. eye(행, 열)

행x열의 단위행렬을 생성한다.

3X3 단위행렬 생성

 

 

8. reshape(차원의 형상)

 

몇 개의 데이터를 가지고 있는 지 shape를 알아야 reshape도 가능하다.

기존 배열의 형상을 바꾸는 역할을 하므로 기존 배열이 총 몇 개의 데이터를 가지고 있는 지 알고 있어야 reshape를 할 수 있다.

차원의 형상으로 알아낸 총 데이터의 갯수와 같도록 차원의 형상을 구상해준다.

예를 들면 기존 배열의 총 데이터 수가 100개인 1차원 100개 짜리 배열이라면

100 = 10 x 10으로 10개의 2차원 안에 각각 10개씩의 데이터로 구성되는 넘파이 배열로 변환이 가능하다.

 

차원의 형상은 2차원 이상일 시에 괄호로 구분지어주자.

reshape((A, B, C, D, E ))이면

A개의 차원(고차원) 안에 B개의 차원이 있고

B개의 차원 안에 C개의 차원이 있고

C개의 차원 안에 D개의 차원이 있고

D개의 차원 안에 E개의 차원이 있다.

여기서 차원은 점, 선, 면, 공간 등의 개념이 아니라

주머니로 생각하면 편하다.

 

100 = 5 x 2 x 1 x 10로 해줄 수도 있다.

 


3. 연산

1. 단순 스칼라 연산 += 1

넘파이가 아닌 리스트로는 아래처럼 for문을 쓰지 않는 이상  list += 1의 연산이 불가하다.

넘파이가 아닐 때는 연산 불가

하지만 넘파이에서는 arr += 1 로 단순 연산이 가능하다.

넘파이에서는 배열 안의 모든 데이터에 대한 동시 연산 가능하다.

 

 

2. 벡터의 연산: 배열의 각 인덱스끼리의 연산)

마찬가지로 리스트에서는 for문을 써야만 각 인덱스에 특정 값을 개별적으로 더해주는 것이 가능하다.

넌파이를 안 썼을 때

반면 넘파이에서는 단순히 arr ++ arr만 해도 행렬의 벡터 연산이 가능하다.

넌파이 썼을 때

위의 넘파이 배열을 보면 1+1, 2+2, 3+3, 4+4, 5+5로 각 인덱스 간의 개별 연산이 for문이 바로 실행되고 있다.

 

 

아래와 같이 1차원 넘파이 배열은 벡터처럼 연산된다.

따라서 1차워 넘파이 배열은 연산을 할 때 서로 사이즈가 맞아야 할 수 있다.

현업에서 보통 넘파이는 2차원을 주로 다루는데 2차원 넘파이 배열은 행렬의 곱과는 다르게 연산이 된다. 

 행렬의 곱과 달리 넘파이는 각 자리끼리의 연산이 된다.

1행 2열의 값은 2행 1열의 값과 곱해지는 것이 아니라

1행 2열의 값과 곱해진다.

 

 

연습1) 0으로 된 2*3의 행렬 만들기

 

연습2) 1~100까지 2씩 간격으로 있는 행렬 만들기

꼭 100이 아닌 100을 포함하도록 101로 해주자!

 

 

3. 평균 구하기:  arr.mean( )

2차원 이상의 배열은 for문으로 평균값을 계산하기 어려우므로

넘파이의 평균 구하기 기능이 유용해진다.

arr[1].mean( )처럼 1 인덱스의 해당 차원에 있는 데이터들의 평균값을 따로 구할 수도 있다.

1차원 배열 평균 구하기
다차원 배열 선택적 평균 구하기

 


4. 넘파이의 슬라이싱

 

넘파이의 슬라이싱을 하면 다차원 배열에서 원하는 부분만 잘라올 수 있다.

주어진 데이터의 특정 위치의 값들만 추출하고 싶다면 어떻게 해야할까

리스트에서는 아래와 같이 [i[1] for i in list]를 이용하여 빼낼 수 있다.

하지만 다차원에서는 리스트의 슬라이싱이 불가능하다.

반면 넘파이는 아래처럼 슬라이싱이 가능하다.

,로 차원을 나눌 수 있다.

x[:, 1]

은 [[1,11], [2,12], [3,13]]의 2차원 주머니 안에 있는 전체 3개의 1차원 주머니에서 1인덱스의 값들만 추출해오자는 코드이다.

따라서 [1,11]의 1인덱스인 11과

[2,12]의 1인덱스인 12와

[3,13]의 1인덱스인 13이 추출되어 [11 12 13] 이 나오게 된다.

넘파이는 간단하게 특정 위치의 데이터를 선별하여 추출할 수 있다.

새 리스트를 만드는 리스트의 슬라이싱과 달리

넘파이의 슬라이싱은 새 넘파이 배열을 만들지 않는다.

따라서 아래 예시처럼 기존의 데이터가 변할 수 있다는 것을 늘 유의해야 한다.

넌파이의 슬라이싱은 원본 데이터를 변화시킨다.

b = [20 40 60]에서 40을 10으로 변환하였더니 기존 넘파이 배열이었던 a의 40값도 10으로 바뀌어있다.

이처럼 기존 데이터의 변경을 막기 위해 b = np.array(a[1:6:2])처럼 b의 넘파이 배열을 따로 만들어줘야 한다.

즉 ,반드시 넘파이 배열로 하나 더 만들고 값을  사용해야 한다.

a의 40이 변경되지 않는다.


5. Numpy의 심화 연산

1. math의 sqrt()

넘파이에는 math가 자체적으로 있기 때문에 import math를 따로 선언할 필요 없다.(참 편해)

np.sqrt(리스트)를 하면 리스트의 각 데이터에 루트2의 연산이 행해진다.

2. 2개의 넘파이 배열 간의 계산

2 + 4 = 6과

5 + 7 = 12가 출력된다.

 

 

3. 특정 인덱스만 추출

추출하고 싶은 값의 인덱스들을 리스트 형태로 나열하고

arr[인덱스의 리스트]를 하면 인덱스 마다의 값들이 추출된다.

 

 

4. 센서가 정상 작동한 데이터만 빼내기

센서가 정상(True)인 것만 빼내기

False 자리인 9를 제외하고 모두 추출된다.

아래 예시를 통해

arr % 2 == 1과

arr [ arr % 2 == 1] 의 차이를 잘 고려해보자

홀수인 부분만 True가 나오고, True인 부분만 추출된다.

 

 

 

연습) 주어진 데이터를 이용하여 BMI를 출력하고 정상, 과체중, 비만이 나오도록 코드를 짜보자.

각 데이터 리스트를 넘파이 배열로 만들어 BMI의 계산식에 넣고 BMI 넘파이 배열을 출력하는 것까진 괜찮았다.

그러나 각 리스트의 범위가 정상/과체중/비만에서 참 거짓을 판명하는 코드를 짜는데 애먹었다.

과체중 = (25 <= bmi) * (bmi <= 29)처럼 더하기 연산 + 이나 && 가 아닌

곱셈 연산 *을 해야한다는 것을 새로 알았다.

 

 

5. 랜덤 넘파이 배열 만들기

배열을 랜덤하게 만든다.

1) a = np.random.random(차원의 형상)

0-1까지의 실수를 랜덤으로 준다.

원하는 범위 안에서 랜덤으로 실수값을 찾고 싶으면 a에 10의 제곱수를 곱해서 범위를 설정해주면 된다.

2) randint(시작값, 끝값, 형상의 크기)

randint의 끝값인 10은 나올 수 없다.

경계값을 포함하지 않는 randrange처럼 넘파이의 randint도 끝값은 포함하지 않는다.

(넘파이가 아닌 randint는 경계값을 포함하므로 randint(1,100)로 쓴다.)

100이 나오도록 하려면 np.random.randint(1,101,10)로 해줘야 한다.

 

 

3) all / any

all은 모두 만족해야, any는 하나라도 만족하면 True가 나온다.

all, any는 데이터 분석에서 아래의 예시처럼 쓰인다.

all : 모든 데이터가 정상값을 가질 때에만 계속 동작해야해

any: 특수한 상황(발열이 심함)이 하나라도 일어나면 동작이 멈춰야해

 

연습) 난수(0~100)를 이용하여 100명의 학생들의 점수를 만들고, 조건에 맞게 출력하는 프로그램을 만들어보자.
1. 100명의 평균이 50점 이상이면 전원 통과 출력
2. 100명 모두가 50점 이상이면 학년 1등반 출력
3. 1명이라도 100점이 있다면 전교 1등반 출력

처음 코드를 짰을 때 아래 처럼 false 값인데 모두 50점 이상이 출력되었다.

if문을 추가하여 상황 마다 출력문을 올바르게 입력하니 

원하는 모습으로 코드가 작동되었다.

 

 


 

6. 전치 행렬

transpose()를 써서 전치행렬을 구한다.

역행렬 구할 때나 미, 적분 할 때 쓴다.

 

해당 수업에서는 전치행렬에 대해 자세히 배우지 않기로 하였다.