Numpy

장범준·2023년 2월 3일
0

데이터분석

목록 보기
2/2

NumPy

  • ndarray
    • 다차원 배열 객체
    • 모든 원소가 같은 자료형이어야 함
    • shape으로 행과 열 리턴
    • dtype으로 안에 들어있는 데이터 타입 리턴
np.arrange(n) //n까지 저장하는 numpy 배열

data = np.random.randn(2,3) //2*3 만큼의 ndarray 생성
data.shape //몇 곱하기 몇 배열인지
data.dtype //안에 무슨 자료형이 들어있는지
np.array(파이썬 배열) //파이썬 배열을 numpy 배열로 변환 가능

np.zeros(10) //길이 100으로 구성된 배열
np.zeros((3, 6)) //3 * 6, 0으로 구성된 이차원 배열
np.zeros((2, 3, 2)) //2 * 3 * 2, 0으로 구성된 삼차원 배열

np.arrange(15) //0부터 14까지 있는 일차원 배열

arr1 = np.array([1,2,3], dtype=np.int32) //배열의 원소 데이터 타입을 int32로 명시
arr1.astype(float) //배열의 원소 타입을 float로 변경

배열의 중요한 특징은 for문 없이 데이터를 일괄 처리할 수 있다는 것

이를 벡터화라고 함

같은 크기의 배열 간의 산술 연산은, 각 배열의 각 원소 단위로 적용

numpy 배열에 슬라이싱으로 배열 조각을 가져올 수 있고, 여기에 스칼라값을 대입하면, 해당 영역의 값들이 전파(또는 브로드캐스팅) 된다.

이때 배열 조각에 대한 변형은 원본 배열에 반영된다.

numpy의 다차원 배열에 접근 할 때는, 인덱스를 콤마로 구분해도 된다.

불리언 값으로 선택하기

In [60]: names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])

In [61]: data = np.random.randn(7, 4)

In [62]: names
Out[62]: array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')

In [63]: data
Out[63]:
array([[-1.09449543,  1.33842269,  0.4367005 ,  0.45852453],
       [ 0.71963332, -1.25159804, -0.35109454, -0.85526839],
       [ 0.01268187,  0.46265082, -1.03517927, -0.2739274 ],
       [ 0.327757  ,  0.0494705 , -1.06467629, -1.1558889 ],
       [ 1.58155799, -0.99390044,  0.36420652, -1.75531138],
       [-0.929551  , -0.40280585,  0.5611649 , -0.19757007],
       [ 1.02814787,  1.23568885,  0.22188382, -0.38510986]])

In [64]: names == 'Bob'
Out[64]: array([ True, False, False,  True, False, False, False])

In [65]: data[names=='Bob']
Out[65]:
array([[-1.09449543,  1.33842269,  0.4367005 ,  0.45852453],
       [ 0.327757  ,  0.0494705 , -1.06467629, -1.1558889 ]])

팬시 색인

//특정한 순서로 로우 선택 가능

In [74]: arr
Out[74]:
array([[0., 0., 0., 0.],
       [1., 1., 1., 1.],
       [2., 2., 2., 2.],
       [3., 3., 3., 3.],
       [4., 4., 4., 4.],
       [5., 5., 5., 5.],
       [6., 6., 6., 6.],
       [7., 7., 7., 7.]])

In [75]: arr[[4, 3, 0, 6]]
Out[75]:
array([[4., 4., 4., 4.],
       [3., 3., 3., 3.],
       [0., 0., 0., 0.],
       [6., 6., 6., 6.]])

팬시 색인은 슬라이싱과 달리, 선택된 데이터를 새로운 배열로 복사한다

arr.reshape(튜플) //다차원 배열을 원하는 형태로 재구성
arr.T //이차원 배열을 전치. 행과 열을 바꿈

np.dot(arr.T, arr) //행렬의 내적

arr.transpose(튜플) //축 번호를 원하는대로 바꿈
arr.swapaxes(1,2) //축 번호를 받아서 배열을 뒤바꿈?

유니버설 함수 : 배열의 각 원소를 빠르게 처리

In [4]: arr
Out[4]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [5]: np.sqrt(arr)
Out[5]:
array([0.        , 1.        , 1.41421356, 1.73205081, 2.        ,
       2.23606798, 2.44948974, 2.64575131, 2.82842712, 3.        ])

In [6]: np.exp(arr)
Out[6]:
array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,
       5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,
       2.98095799e+03, 8.10308393e+03])

sqrt, exp 등의 함수는 기본적으로 전체 원소에 적용된다. 이런걸 단항 유니버설 함수라고 한다.

In [9]: x
Out[9]:
array([ 0.13334442,  0.47961467,  0.34854219, -1.15060949,  0.67819017,
       -1.0815493 , -1.85802155, -1.00336541])

In [10]: y
Out[10]:
array([-0.40564506, -0.12126072,  1.03362326,  1.02822596, -1.18462256,
        0.91493542,  0.62956396,  0.71171703])

In [11]: np.maximum(x,y)
Out[11]:
array([0.13334442, 0.47961467, 1.03362326, 1.02822596, 0.67819017,
       0.91493542, 0.62956396, 0.71171703])

In [12]: np.add(x,y)
Out[12]:
array([-0.27230064,  0.35835395,  1.38216545, -0.12238353, -0.50643239,
       -0.16661389, -1.22845759, -0.29164838])

add, maximum은 배열을 반환한다

In [14]: arr
Out[14]:
array([ -1.38433615,  -1.08860093,   0.43396342, -13.07077085,
        -2.6481159 ,  -0.14308658,   2.23040492])

In [15]: remainder, whole_part = np.modf(arr)

In [16]: remainder
Out[16]:
array([-0.38433615, -0.08860093,  0.43396342, -0.07077085, -0.6481159 ,
       -0.14308658,  0.23040492])

In [17]: whole_part
Out[17]: array([ -1.,  -1.,   0., -13.,  -2.,  -0.,   2.])

몫과 나머지로 다른 두개 이상의 배열을 반환하는 함수도 있다.

In [19]: points = np.arange(-5, 5, 0.01)

In [20]: xs, ys = np.meshgrid(points, points) 
//meshgrid는 두 개의 1차원 배열을 받아서,
(x,y) 순서쌍을 만들 수 있는 2차원 배열 두 개를 반환한다

In [21]: ys
Out[21]:
array([[-5.  , -5.  , -5.  , ..., -5.  , -5.  , -5.  ],
       [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
       [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
       ...,
       [ 4.97,  4.97,  4.97, ...,  4.97,  4.97,  4.97],
       [ 4.98,  4.98,  4.98, ...,  4.98,  4.98,  4.98],
       [ 4.99,  4.99,  4.99, ...,  4.99,  4.99,  4.99]])

In [22]: xs
Out[22]:
array([[-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       ...,
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99]])

In [23]: z = np.sqrt(xs ** 2 + ys ** 2)
//sqrt 함수를 이용해 모든 이차원 배열의 원소에 대해 연산을 시행

In [24]: z
Out[24]:
array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,
        7.06400028],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
        7.05692568],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       ...,
       [7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,
        7.04279774],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
        7.05692568]])
In [30]: xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])

In [31]: yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])

In [32]: cond = np.array([True, False, True, True, False])

//기본 파이썬의 리스트 표기법을 사용한 예
In [33]: result = [(x if c else y) for x,y,c in zip(xarr, yarr, cond)]

In [34]: result
Out[34]: [1.1, 2.2, 1.3, 1.4, 2.5]

//numpy의 where를 활용한 예
In [35]: result = np.where(cond, xarr, yarr)

In [36]: result
Out[36]: array([1.1, 2.2, 1.3, 1.4, 2.5])

np.where()

  • np.where(조건, 배열, 배열)
  • 조건에는 bool 배열이 올 수 있고, 두번째와 세번째 인자는 배열이 아니라 값이 올 수도 있다.
In [37]: arr = np.random.randn(4, 4)

In [38]: arr
Out[38]:
array([[ 0.24329842, -0.30894191,  1.06130437,  1.13809259],
       [-2.25949561, -1.02842952, -0.38979807, -0.32690165],
       [ 2.21799434, -0.63429216, -0.59617981, -0.17275839],
       [ 0.42650363,  2.04844863,  0.66940995, -0.83949312]])

In [39]: np.where(arr>0, 2, -2)
Out[39]:
array([[ 2, -2,  2,  2],
       [-2, -2, -2, -2],
       [ 2, -2, -2, -2],
       [ 2,  2,  2, -2]])
arr.mean()
np.mean(arr) //둘다 평균 리턴
arr.sum() //합 리턴

arr.mean(axis=1) 
arr.sum(axis=0) //원하는 axis에 대한 통계만 계산

//cumsum과 cumprod는 중간 계산값을 담고 있는 배열을 반환
//rod는 누적곱

In [45]: arr = np.array([1, 2, 3, 4, 5, 6, 7])

In [46]: arr.cumsum()
Out[46]: array([ 1,  3,  6, 10, 15, 21, 28])

In [48]: arr
Out[48]:
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [49]: arr.cumprod(axis=0)
Out[49]:
array([[ 0,  1,  2],
       [ 0,  4, 10],
       [ 0, 28, 80]])

In [50]: arr.cumprod(axis=1)
Out[50]:
array([[  0,   0,   0],
       [  3,  12,  60],
       [  6,  42, 336]])
In [52]: arr = np.random.randn(100)
In [54]: (arr>0).sum()
Out[54]: 48

//arr>0 이라는 조건을 이용해, 01로만 이루어진 배열로 강제로 바꾼다.
//이 배열의 총합을 구하면, 조건에 맞는 원소의 수를 카운트할 수 있다.

In [55]: bools = np.array([False, False, True, False])

In [56]: bools.any() //bool 배열에서 하나 이상의 값이 True인지 확인
Out[56]: True

In [57]: bools.all() //bool 배열에서 모든 값이 True인지 확인
Out[57]: False

정렬

In [59]: arr
Out[59]:
array([ 0.49588864, -0.3139628 ,  1.5493912 ,  0.34864308,  0.01327596,
        1.50687672])

In [60]: arr.sort()

In [61]: arr
Out[61]:
array([-0.3139628 ,  0.01327596,  0.34864308,  0.49588864,  1.50687672,
        1.5493912 ])

In [62]: arr = np.random.randn(5,3)

In [63]: arr
Out[63]:
array([[-1.07267959,  0.77191415, -0.423504  ],
       [ 0.66999513, -2.22217556, -0.70034757],
       [ 1.47669576, -0.09384004,  0.88055938],
       [-0.28634861,  0.1511579 , -0.31502024],
       [-0.44688005, -0.12262832, -0.15140229]])

In [64]: arr.sort(1)

In [65]: arr
Out[65]:
array([[-1.07267959, -0.423504  ,  0.77191415],
       [-2.22217556, -0.70034757,  0.66999513],
       [-0.09384004,  0.88055938,  1.47669576],
       [-0.31502024, -0.28634861,  0.1511579 ],
       [-0.44688005, -0.15140229, -0.12262832]])

In [66]: arr.sort(0)

In [67]: arr
Out[67]:
array([[-2.22217556, -0.70034757, -0.12262832],
       [-1.07267959, -0.423504  ,  0.1511579 ],
       [-0.44688005, -0.28634861,  0.66999513],
       [-0.31502024, -0.15140229,  0.77191415],
       [-0.09384004,  0.88055938,  1.47669576]])

sort는 배열을 직접 변경하지 않고, 복사본을 반환

배열의 분위수를 구하는 빠른 방법은, 배열을 정렬한 후, 특정 분위의 값을 선택하는 것이다

In [68]: names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])

In [69]: np.unique(names) //중복 제거 함수
Out[69]: array(['Bob', 'Joe', 'Will'], dtype='<U4')

In [70]: sorted(set(names)) //파이썬으로 구현한 집합 제거
Out[70]: ['Bob', 'Joe', 'Will'] 
unique(x) //배열에서 중복된 원소를 제거한 뒤 정렬하여 반환
intersect1d(x,y) //배열 x와 y에 공통적으로 존재하는 원소를 정렬하여 반환
union1d(x,y) //두 배열의 합집합 반환
in1d(x,y) //x의 원소가 y의 원소에 포함되는지 나타내는 bool 배열 반환
setdiff1d(x,y) //x와 y의 차집합을 반환
setxor1d(x,y) //한 배열에는 포함되지만, 두 배열 모두에 포함되지는 않는 원소들의 집합 반환(대칭차집합)

파일 입출력

In [71]: arr = np.arange(10)

//배열 저장
In [72]: np.save('some_array', arr) //확장자를 붙이지 않으면 자동으로 npy를 붙여줌

//배열 불러오기
In [73]: np.load('some_array.npy')
Out[73]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

//키워드 인자 형태로 여러 배열을 입력, 압축해서 저장
In [74]: np.savez('array_archive.npz', a=arr, b=arr)

//불러오면 딕셔너리 형태의 객체로 저장됨
In [75]: arch = np.load('array_archive.npz')

//키로 접근 가능
In [76]: arch['b']
Out[76]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [77]: arch['a']
Out[77]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

//압축이 잘 되는 형식의 데이터라면 compressed를 붙인 함수를 이용
In [78]: np.savez_compressed('arrys_compressed.npz', a=arr, b=arr)

선형 대수

행렬의 곱셈, 분할, 행렬식, 그리고 정사각 행렬 수학 같은 선형대수는, 배열을 다루는 라이브러리에서 중요한 부분이다.

두 개의 2차원 배열을 * 연산자로 곱하면, 행렬곱이 아니라 대응하는 각각 원소의 곱을 계산한다.

행렬 곱셈은, 배열 메서드이자 numpy 네임스페이스 안에 있는 dot 함수를 이용해 계산한다.

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

In [80]: y = np.array([[6., 23.], [-1, 7], [8,9]])

In [81]: x
Out[81]:
array([[1., 2., 3.],
       [4., 5., 6.]])

In [82]: y
Out[82]:
array([[ 6., 23.],
       [-1.,  7.],
       [ 8.,  9.]])

In [83]: x.dot(y) //행렬곱
Out[83]:
array([[ 28.,  64.],
       [ 67., 181.]])

In [84]: np.dot(x,y) //행렬곱의 다른 표현
Out[84]:
array([[ 28.,  64.],
       [ 67., 181.]])

행렬 다시 공부할것! 다 까먹었다

//2차원 배열과 곱셈이 가능한 크기의 1차원 배열 간의 행렬 곱셈의 결과는 1차원 배열

In [86]: np.dot(x, np.ones(3))
Out[86]: array([ 6., 15.])

In [87]: x @ np.ones(3) //@로 행렬 곱셈을 수행할 수 있음
Out[87]: array([ 6., 15.])

numpy.linalg

행렬의 분할과 역행렬, 행렬식과 같은 것들 포함하고 있음

난수 생성

In [88]: samples = np.random.normal(size= (4, 4))
//normal을 사용하면, 표준 정규분포로부터 표본을 생성할 수 있음
 
In [89]: samples
Out[89]:
array([[ 0.43673236,  0.89294536,  0.4536767 , -1.18139694],
       [-0.60390971,  0.19476738,  1.48935697,  0.74082633],
       [ 0.91817605, -0.60832071,  2.19186236, -0.67472785],
       [-1.39867968, -1.10843721,  0.19343346, -0.1347002 ]])

In [90]: np.random.seed(1234) //numpy.random에서 사용하는 시드값을 바꿀 수 있음

In [91]: rng = np.random.RandomState(123) 
//RandomState로, 원하는 시드값을 가지는 격리된 난수 생성기를 만들 수 있음

In [92]: rng.randn(10)
Out[92]:
array([-1.0856306 ,  0.99734545,  0.2829785 , -1.50629471, -0.57860025,
        1.65143654, -2.42667924, -0.42891263,  1.26593626, -0.8667404 ])

In [93]: np.random.randn(10)
Out[93]:
array([ 0.47143516, -1.19097569,  1.43270697, -0.3126519 , -0.72058873,
        0.88716294,  0.85958841, -0.6365235 ,  0.01569637, -2.24268495])
seed난수 생성기의 시드 지정
permutation순서를 임의로 바꾸거나 임의의 순열을 반환
shuffle리스트나 배열의 순서를 뒤섞음
rand균등분포에서 표본을 추출
randint주어진 최소/최대 범위 안에서 임의의 난수 추출
randn표준편차가 1이고 평균값이 0인 정규분포 안에서 표본 추출
binomial이항분포에서 표본을 추출
normal정규분포(가우시안)에서 표분 추출
beta베타분포에서 표본 추출
chisquare카이제곱분포에서 표본 추출
gamma감마분포에서 표본 추출
uniform균등 [0, 1) 분포에서 표본 추출

계단 오르기

In [103]: def stairs():
     ...:     position = 0
     ...:     walk = [position]
     ...:     steps = 100
     ...:     for i in range(steps):
     ...:         step = 1 if random.randint(0,1) else -1
     ...:         position += step
     ...:         walk.append(position)
     ...:     return walk
     ...:

In [104]: stairs()

np.random.randint(a, b) //a 이상 b 미만의 랜덤 정수

np.where(bool 배열, a, b) //bool 배열의 값이 true면 a, false면 b인 배열 반환

profile
안녕하세요!

0개의 댓글