파이썬에서 시각화 할 수 있는 여러 패키지들이 있다. 여러가지가 있지만 대표적으로 사용되는 것들은 다음과 같다.

  • Plotnine: ggplot2에 기반한 라이브러리를 이용하여, 표현이 가능하다.
  • Plotly: 대화식 그레프를 그려주는 라이브러리. 시각화를 위해 D3.js을 사용. 이는 자바스크립트를 기반으로한다. D3는 data driven document 을 의미한다. 
  • Folium: 지도데이터의 플롯팅. 지도 API이다. 지도를 화면에 그레프를 그릴 수 있다. 지도 이외에 오버레이를 할 수 있어서, 추가정보를 입힐 수 있다.
  • Pyecharts: 바이두에서 데이터 시각화를 위해 만든 Echarts.js의 파이선 버전이다.
  • Matplotlib: python 2D 플로팅 라이브러리. 플렛폼(운영체제)에 독립적인 대화형 환경을 제공하고, python 스크립트, python 쉘, 노트북, 웹 응용프로그램 서버에서 사용 가능.

이외 웹에서 시각화 할 수 있는 사이트들이 있는데, highcharts.com 에 소스코드를 뿌려줄 수 있다.  위의 종류중 Matplotlib와 Seaborn만 알아도 훌륭하다.



Matplotlib


matplotlib은 파이썬 2D 플로팅 라이브러리로, 플랫폼에 독립적인 대화형 환경을 제공하며, 고품질의 그림을 생성할 수 있게 해준다. 플랫폼에 독립적이지만, 다양한 환경에서 사용할 수 있어, 파이썬 스크립트, 파이썬 및 아이파이썬(IPython) 쉘, 주피터 노트북, 응용웹프로그램 서버에서도 사용이 가능하다.


시각화를 위한 시작은 아래와같다.


1
2
3
4
5
6
7
8
import matplotlib
import matplotlib.pyplot as plt
 
%matplotlib inline
%config inLineBackend.figure_format = 'retina' 고해상도를 그리기 위한 코드
%lsmagic # 매직키워드의 리스트를 보여준다.
 
 
cs

 

[2] pyplot: 플롯을 그려주는 함수들을 가지고있는 서브페키지. 

[4] %matplotlib inline: 객체의 주소값만 출력되는 것을, 한번에 그레프가 그려진다. 

[5] %config inLineBackend.figure_format = 'retina' 고해상도를 그리기 위한 코드 . png, gif, jpeg, retina 속성들이 있다.

[6] %lsmagic: 매직키워드의 리스트를 보여준다.


%은 매직키워드라고 불리는데, 아래와 같이 두 종류가 있다.

  • %: line magic 이 라인에 대한 실행 시간을 보여준다.
  • %%time 10+20:  cell magic. 셀에 대한 실행시간을 보여준다.

Figure 객체
Matplotlib에서 그래프를 그리기 위한 객체. 그레프를 그리기 위한 도화지라고 생각하면 된다. 이 도화지를 plt.subplots()으로 분할해서 각 부분에 그레프를 그리는 방식으로 시각화한다. subplot도 있고, subplots도 있는데, 도화지를 나눠서 그리고 싶다면, 어쨋든 둘다 사용이 가능한데, 사용하는 방법만 다르다.


Subplot(nrows, ncols, index, **kwargs)
분할하기 위한 row, column을 지정해줘야한다. 예를 들어, 위 아래로 분할하고 싶으면, (2 rows, 1 columns, 1번째) . ( 2 rows, 1 columns, 2번째) 로 나눠서 지정하면된다. 화면을 나눠 가면서, 부르는 것을 axis라고 하는데, 나눠가면서 그릴 때 사용하는게 subplot이다.

args에 입력을 다음과 같이하면 된다.
만약 화면을, 2x2로 나누고 싶다면, (2,2,1), (2,2,2), (2,2,3), (2,2,4) 이렇게 나눌 수 있는데, 221,222,223,224이렇게 연달아서 써도 된다. 
위에 1개. 아래에 2개로 표현하고 싶을 때, 221, 223, 224 이렇게 쪼갤 수 있다.
어찌 되었는 이 함수의 리턴값은 Figure 객체와 axes.Axes 객체를 반환한다. 

1
2
3
4
5
6
7
8
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
 
plt.subplot(211); plt.plot(x, np.sin(x))
plt.subplot(223); plt.plot(x, np.cos(x))
plt.subplot(224); plt.plot(x, np.tan(x))
 
cs


plt.show() 을 쓰면 객체 주소가 나오지 않는다.

Subplots(nrow, ncol, sharex=False, Shrey=False, .... fig_kw)
미리 나눠놓고 한번에 그리는 방법. 이 객체 함수 또한 리턴값으로 figure 객체와 axes 객체가 리턴이 된다. Figure 객체는 도화지이기 때문에, 우리는 그림을 그릴 때, 어느 구역에서 그릴지만 지정해주면 된다. 바로 axis[0,0], axis[0,1] 처럼 몇 번째 구역에 그릴 것인지, 바로 직관적으로 그릴 수 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
 
fig, axes = plt.subplots(22
axes[00].plot(x, np.sin(x))
axes[01].plot(x, np.cos(x))
plt.show() # 그려주기
 
# 행이나 열이 하나면 차원이 하나만 드f어가야한다.
fig, axes = plt.subplots(12
axes[0].plot(x, np.sin(x)) # 축이 한차원
axes[1].plot(x, np.cos(x)) # 축이 한차원
plt.show() # 그려주기
cs



plot(x, y, data=none, [format])

선 그레프를 그려주는 함수. x, y: data가 따로 분리되어있는 경우, x와 y을 따로 따로 지정해주어야 한다. data가 데이터프레임 형식으로 있다면, x, y에 열 이름을 지정해줘도 된다. format에는 색, 점 라인을 지정할 수 있다.



'ro-': red - 실선을 의미한다.

'cv-.':

'b^:'  파란색, ^삼각형, 

같은 축에 플롯을 그리면, 그레프가 덮어써진다.

'kx--': dash 선을 그릴 수 있다.

점만 표현하고 싶으면 , plot+ 'ro'포맷을 쓰거나, scatterplot을 사용할 수 있다.


참고로 ~~plot의 다른 종류의 함수는 다양하게 표현될 수 있다.




Scatterplot(x, y, s=None, c=None, alpha=None)


matplotlib의 scatter함수는 산점도를 그려준다. s는 scale을 의미하며 각 산점도의 크기를 지정할 수 있고, c는 색상을 의미하고, alpha는 산점도의 투명도를 결정한다.


1
2
3
4
5
6
7
8
9
10
11
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
= 50
= np.random.rand(N)
= np.random.rand(N)
colors = np.random.rand(N)
area = (30* np.random.rand(N))**2
 
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
plt.show()
cs


s: 산점도의 크기

c, color: 팔레트에서 인덱스를 적용하여 색깔을 입힘. c을 써도되고, color라고 써도된다. 

marker = plot은 format 과 유사하게, {'o', '*' 등}을 사용할 수 있음


예제로, 화면을 분할에서 위의 scatter()을 이용하여, 여러가지(기본, s포함, c까지 포함, alpha까지 포함)를 그리고자 한다면 subplots, subplot을 이용하면 된다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
= 50
= np.random.rand(N)
= np.random.rand(N)
colors = np.random.rand(N)
area = (30* np.random.rand(N))**2
 
fig, axes = plt.subplots(22)
axes[0,0].scatter(x, y)
axes[0,1].scatter(x, y, s=area)
axes[1,0].scatter(x, y, s=area, c= colors)
axes[1,1].scatter(x, y, s=area, c= colors, alpha=0.5)
 
plt.show()
cs


hist()

boxplot()

violinplot()

히스토그램이 bin의 개수에 따라서, 표현이 많이 달라지는데, 커널밀도함수(kernel density funciton)를 표현해서, 데이터의 분포를 분포를 이용하여 완만하게 그려줄 수 있다. 유사하게 바이올린플롯도 kernel density function으로 이용해서, 각 자료의 구간을 완만하게 표현해주는 그레프이다.


text: 텍스트의 왼쪽 하단의 기준점이 2,0에 해당한다는 것이다.

annotate 글씨와 화살표를 같이 표기해준다. 

xy= 화살표의 끝점, xytext = 텍스트가 표기될 왼쪽하단의 기준점. xycoords, textcoords= 데이터를 가지고, 축/길이를 생성, connectionstyle= 화살표의 스타일, 


이 정도 매개변수랑 함수를 사용할정도면, 그만알아보고, 포토샵으로 하자.



축과 눈금 다루기



Ticker 클레스

Artist 클레스: 미적 속성. 이를 Axis(축)와 tick(눈금)이 상속받는데, Axis는 XAxis, YAxis가 상속받고,  Tick은 XTick, YTick을 상속받는다.

set()은 그레프의 제목과 축의 제목, 눈금, 눈금 레이블 등을 한거번에 설정할 수 있다. 그러나 코드의 가독성이 떨어져서, set_xlim 등 따로 따로 함수를 이용해서 구분하여 그림을 그리는게 더 효과적이다.


set_xlim(), set_ylim(), 

set_xticks() 눈금 위치를 리스트 형식으로 지정. 반드시 표현하고 싶은 눈금을 []리스트 내에 지정해준다.  '|'의 위치를 의미한다.

set_xticklabel, set_ytickslabels: 눈금이 지정된 곳에, 레이블을 적는다.


spines: 박스의 경역

grid(True): 그레프 영역내 눈금을 설정할 경우.



bar(): barplot을 그리는 경우

barh(): barplot을 가로로 그린 경우

xvline(): vertical하게 수직선을 그리는 경우


fill():  폐곡선을 그려서 시작점과 

fill(): 0값을 기준으로 가운데를 채워주는 그레프



축의 공유


하나의 그래프를 영역에 두 개 이상의 그래프를 그리면서, 다른 축을 지정하고 싶은 경우 twinx(), twiny()) 함수를 이용해서 새로운 축 객체를 생성하여 그레프를 그리고 추긍ㄹ다르게 지정할 수 있다.

  • twinx() 함수는 x축을 공유하고,  y축을 오른쪽에 표시해주는 새로운 축객체를 반환
  • twiny() 함수는 y축을 공유하고, x축을 위아래오 표시해주는 새로운 축객체를 반환
1
2
3
4
5
6
7
8
fig, axes = plt.subplots()
x= df['Sepal.Length']
y= df['Sepal.Width']
z= df['Petal.Width']
axes.plot(x, y, 'g^:')
 
ax2 = axes.twinx()
ax2.plot(x, z, 'bv--')
cs


1번 라인처럼 fig객체와 axes 객체를 생성해놓고 일단 axes 객체에 그림을 그린다. 그런데 이 axes 객체에 x, y 축이 있을 텐데, 그 축 중 겹치고 싶은 축을 twin해서 사용하는 것이다(7라인)


Legend





Style


plt.style.available 스타일 찾기

plt.style.use('ggplot') ggplot으로 그리기.



Font

windows/fonts으로 들어가서 글꼴이름으로 한글을 지원하는 글꼴이름복하하면 된다.

그 이후, matplotibrc 파일 내에, font.family : 글꼴 이름을 저장한다음 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#
print(matplotlib.matplotlib_fname()) # rc 폴더내에 설정파일 
 
# 또는 아래와 같아 폰트를 직접 지정
import matplotlib.font_manager as fm
font_path = 'path'
font_prop = fm.FontProperties(fname=font_path)
 
plt.style.use('seaborn-paper')
fig, ax1 = plt.subplots()
ax1.plot(x, y1, 'g^:')
ax1.set_xlabel('X data')
ax1.set_ylabel('Y data', fontproperties = font_prop)
ax1.tick_params(color='white')
ax2 = ax1.twinx()
ax2.plot(x, y2, 'r^:')
ax2.set_ylabel('Y2 data')
plt.savefig('foo.png')
cs


Graph save


savefig(fname, dpi) 함수을 이용. fname: 파일명, dpi: dot per inch

1
plt.savefig('foo.png')
cs




PandasDataframe.plot(x=None, y=None)


x, y, kwwds:


kdwds: line, box, bar, bar 그레프에 따라 열

1
2
3
4
5
6
7
8
9
import numpy as np
import pandas as pd
import seaborn as sns
import satsmodels.api as sm
 
# iris = sns.load_dataset('iris'). [7]번 라인과 같다.
iris = sm.datasets.get_rdataset('iris')
iris_df = iris.data 
plt.show()
cs

[8] data라는 속성을 통해서 데이터 형태를 가지고 온다.


플롯에 x에는 꽃잎의 길이, y에는 꽃잎의 넓이를 표시하여, 산점도, 히스토그램, 라인, 그리고 디폴트로 박스플롯을 그리고자하면, plot에 arguments 해당하는 부분을 입력해주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# scatter plot
iris_df.plot(x='petal_Length', y='Petal.Width', kind='scatter'
 
# histogram
iris_df.plot(x='petal_Length', y='Petal.Width', kind='hist'
 
# linegraph
iris_df.plot(x='petal_Length', y='Petal.Width', kind='line'
 
# Boxplot
iris_df.plot(kind='box'
 
# figsize 변경
iris_df.plot(kind='box', figsize=(3,2)) 
cs




반응형

'Data science > Python' 카테고리의 다른 글

0. Python 이란?: 언어형태, 특징, 메모리관리  (0) 2019.06.16
python 시각화 : Seaborn  (0) 2019.06.10
3. Numpy 한 페이지 요약  (0) 2019.05.13
2. Python: function  (0) 2019.03.19
1. 기본자료형, Python Built-in Code  (0) 2019.03.05

 

 

Numpy는 파이썬을 위한 과학 컴퓨팅 기본 패키지다.

리스트나 다른 배열과의 차이점은 넘파이 배열은 같은 타입만 요소를 가질 수 있다. 즉 동종(Homogenous type)만 요소로 있을 수 있다. 예를 들어, float32면, float32끼리만 요소로 가질 수 있고, int16이면 int16끼리만 가질 수 있다. 넘파이 배열은 보통 ndarray라고 부르는데, 앞서 언급한것처럼 내장 라이브러리에 array와는 다르다. 

 

Numpy객체들을 ndarray라고하는데, 이 객체가 가지고 있는 속성들은 다음과 같다.

- ndarray.ndim: 축의 개수를 출력(=차원의 수)

- ndarray.shape: 배열의 크기를 출력

- ndarray.size: 배열이 가지고 있는 총 요소의 수를 의미한다. 예를 들어 (3,2)의 모양을 가지고 있는 배열의 경우 6이 출력된다.

- ndarray.dtype: 데이터 타입 (형변환은 ndarray.astype()으로 변환)

- ndarray.itemsize: 배열의 각 요소의 바이트 단위의 사이즈. 즉 dtype에서 정의한 타입을 바이트 단위로 출력한다. 

float 64는 나누기 8을 하면되니, itemsize 8이 출력된다. 

 

 

 

 

Nd.arrayDtype: Nan(not a number)데이터타입은실수형(float)으로분류가된다. Integer바꿀, nan있으면못바꿀있다.

itemsize

retype.itemszie: 바이트 단위 사이즈 

 

int는 4byte.

 

long형은 8bytp여서 +_921경

3대는 int와 long의 구분이 없고, int의 자리수의 길이의 제한이 없어서... 그래서 대량 데이터는 최대길이의 숫자에 맞춰서 알아서 메모리를 할당하기 때문에, 공간의 낭비가 심하다.

numpy에서는 적당한 int32, int64 알아서 잡아서 할당해준다.

 

100도 안넘는데도 불구하고, 16가 나을것같은데 32를... 컴퓨터는 4바이트 단위로 짤라서 쓸 때, 속도가 가장빠른데, 32를 기준으로한다. 대부분의 언어도 그렇다.

 

 

dtype의 이해


항목 하나하는 64bit로 늘려서 만드는게 아니고, 두 항목을 64bit로 묶어서, 반환을 한다. 그래서 아래와 같이 이상한 값이 나온다.

32bit가 2개가 모여서 64bit가 되는거여서, 엉뚱한 값이 나온다. 타입의 용량이 부족하다고 맘대로 64bit로 늘리면 안된다.

왜냐하면 타입의 변경할 때, 실제 저장된 데이터의 구조(비트)가 변경되어서 반환이 되기 때문이다. 

Windows시스템의 특성 때문에, 그렇다. 이 는 숫자를 저장할 때, 비트 순서를 뒤바꾸어서 저장을 한다. 0+1을 결합해서 나오는데, 1과 0이 숫자가 뒤바뀌어서 나온다. 

 

예를 들어, 000000000 000000000.  000000000 000000000 <-0

000000000 000000000.  000000000 00000001 <- 1 이다.

이것을 합칠 때,  0다음에 1을 넣는게 아니라 1을 먼저 앞으로 두고, 0을 넣는다. (상위비트와 하위비트를 바꾸어서 저장하도록 되어있다) 만일 64비트 1을 저장한다면, 스텍의 크기 때문에, 먼저 저장한걸 나중에 저장하기 때문에,CPU구조 때문에 16bit->32bit 32비트씩 끊어서 저장을 하게되는데, 예를 순서대로 집어넣으면 반대로 나오기 때문에 뒤짚어서 저장을 한다. 

 

1
2
3
a.dtype = np.int64
# 원래32인 것을, int64로 바꾸면, 엉뚱한 값이 나온다
# 항목 하나 하나를 int64로 바꾸라는 말이 아니라, 전체 a를 int64로 바꾸라는 말로 된다.
cs
 
 
 
배열을 만들기

 

 

 

 

 

 

 


1. array을 통해 만들기.

 

arrary을 통해서 만들꺼면, array()함수 내에 시퀀스형을 넣어야한다. 시퀀스형은 예를 들어서, 튜플이나 리스트 등을 입력값으로 해야 넘파이객체가 만들어진다.

 

 

 

1
2
3
4
5
6
7
8
9
10
# array함수를 이용해서 만들기 
= np.array([2,3,4]) # 타입도 알아서 지정된다.
= np.array([2,3,5.4]) # type: float64
# Complex type
= np.array([[12], [34]), dtype = complex) # 복소수로 만든다.  1 + 0.j
# 기존의 배열을 가지고 만드는 경우
= np.array(c)
id(c), id(d) # id 주소가 서로 다름.
d2 = np.arrary(c, copy=False) # 새로운 배열을 만드는게 아니라, 주소를 그대로 쓸 수 있음.
 
cs

 

 

 

2.기본값 있는 배열 만들기

 

np.zeros(), np.ones(), np.empty()의 세가지 함수를 이용해서 만들 수 있다. 

np.array()는 안에 스퀀스형이 인자로 들어갔지만, 기본값이 있는 배열은 변수에 크기를 입력하면된다.

이렇게 만들어진 배열은 64비트인데, 타입 지정시 속도가 조금씩 차이가 난다.

타입을 지정할 때, 속도도 고려할 수 있는데, 정수는 4바이트 단위가 빨라서 32비트가 빠르다

실수는 64비트가 빠르다. 실수의 표현방법은 IEEE 954-9규약에 부동소수점 표현방법에 따라서 기본적으로, 실수는 64비트로 실수로 계산하게끔 만들어놓아서 32비트면 잘라서 해야되서 64비트가 빠르다.

1
2
3
4
5
6
7
8
9
10
11
np.ones((3,4))
# 정수는 4바이트가 빠르고
# 실수형은 64비트가 빠르다. 
 
np.empty((3,4))
np.arange(10# 1차원으로 반환
np.arange(5,10# 5부터 10미만
np.arage(5203# range(5,20,3)과 같다.
 
# 실수단위로 단위로, 개수를 지정하여 출력하기 위해서
np.linspace(029# 0부터 2까지 9개를 뽑아주세요. (0, 0.25, 0.5, 0.75....2) 마지막 값을 뽑아준다 
cs

3. 연속된 값을 갖는 배열 만들기.

numpy.arange(start, stop, step, dtype=None)

np.arange()을 이용해서 생성하는 방법이다. range()와 유사하게 사용할 수 있다.

또는 np.linespace(start, stop, num= 갯수) 을 이용해서도 출력할 수 있다.

1
2
3
import numpy as np
np.linspace(010, num=10)
np.linspace(02*3.14100
cs

 

 

 

 

배열의 차원 변경하기


np.random.random((3, 4))을 이용해서, (3,4) shape의 랜덤으로 배열을 만들 수 있다.

배열의 차원을 변경하는 함수들은 바로 반환되는게 아니라서, 다시 객체를 리턴값으로 받아주는 할당문이 있어야한다. 

 

np.ravel(): 차원이 모두 풀린 배열을 반환

1
2
= np.floor(10*np.random.random((3,4)))
a.ravel() # 차원이 풀린 1차원으로 배열을 나열한다.
cs

 

np.T: 전치행렬(transpose)을 반환

np.reshape(shape): (x,y) 의 shape을 가진 배열로 변경. 요소의 수(=size)가 같아야 한다. reshape(3,-1) 처럼 shape의 형태가 -1인 경우, 차원의 크기는 앞에 맞춰서 자동으로 계산이 된다. 

np.resize(shape): reshape이랑 같은 기능을 가진 메서드이다. 

 

resize와 reshape의 차이는?

reshape은 그 배열을 바꾸지 못하고, 리턴만해주는데, resize는 배열 자체를 변경한다.

reshape은 -1을 사용가능하지만, resize는 -1을 사용하지 못한다.

1
2
3
4
5
6
7
8
9
>>> import numpy as np
>>> a = np.arange(0,10)
>>> a.reshape(2,5)
>>> print(a)
[0 1 2 3 4 5 6 7 8 9]
>>> a.resize(2,5)
>>> print(a)
[[0 1 2 3 4]
 [5 6 7 8 9]]
cs

 

 

 

 

 

1
2
3
4
5
6
7
= np.arange(24).reshape(2,3,4# axis = 0 열임, 마지막 축은 '깊이가 2개인 행렬'
 
np.set_printoption(threshold=1000# 1000개까지만 출력하게 만듬
np.aragne(1010).reshape(10,101# 1000개가 나오고 10개가 가려지는게 아니라. 그보다 훨씬 더 많이 안보임
 
 
 
cs

Numpy 배열의 연산


행렬의 곱연산은 *이 아니라 dot 또는 @을 이용하여 계산한다. *으로 할 경우, 요소별 연산(element-wise)연산이 되기 때문에 다르다.

 

보통, 행렬을 연산할때, 피연산자의 shape이 다른 경우에는 브로드캐스팅 규칙이 적용되는데, 복합대행연산자(바로 대입하는 연산)를 이용할때는 타입이 같아야한다(라인 16~23). 복합대행연산자는 중간에 객체를 또 만들지 않고, 기존의 배열을 수정하기위해 사용된다. 
그러나, 아래의 예시처럼, a가 int형이고, b가 기본형(기본 dtype= float64)인 경우에는 풀어서 연산을 다시 할당받으면 사용 에러가나지 않고, int가 float32또는 float64의 형태로 상향형변환(upcasting)되지만, 복합대행연산자를 이용하여 할당받으려면, 객체의 타입이 그대로 int인 상태에서 연산이 float형을 받아야하기 때문에(=downcasting)이 되지 않아 에러가 발생한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
b**2 # 각 요소들을 제곱
a<35 # boolean으로 출력
np.sin(a) # 요소별로 사인값을 출력
 
 
# 곱연산
= np.array([[11], [13]])
= np.array([[20], [34]])
A*# Asterik을 쓰면안되고, 각 요소별로 곱이 나온다. 
 
# 행렬의 곱
np.dot(A,B)
A @ B 
 
# 복합대입연산자
= np.ones((2,3), dtype=int)
*= 3
 
= np.random.random((23)) # dtype = float64임.
 
= b + a # float64가 포함할 수 있지만
= b + a # int 을 포함할 수는 없지만, 풀어쓰면 가능하다. a+b을 더해서 실수를 만들어놓고, 추후에 a를 변환
+= b # 안된다. Down casting이 불가능하다. 1:1로 매핑하면서 계산을 해가는데, 동종모음이다보니깐 출력이 안됨
 
cs

 

 

Numpy Axis & Aggregation


넘파이 객체를 쓰다보면, 집계를 해야하는 경우가 있는데, 이럴 때 마다 ,축이 너무 헷갈려서 어느 축에 대해서 연산을 해야할지 모르는 경우가 발생한다. 이럴 때, 축에 대한 의미를 조금 더 공부할 필요가 있다. 

 

간단히 요약하면, axis = 0 은 로우를 하나로 보고 합치는 연산(row-wise)을 의미하고, aixs =1 은 컬럼을 하나로 봐서, 합치는 연산(column-wise)을 의미한다.

numpy의 axis을 어떤축을 합칠 것인지(collapses)를 말해주는 것이다. 

아래의 예시를 보면서 설명을 해보자.

 

1
2
3
4
5
6
>>> b = np.arange(12).reshape(3,4)
>>> print(b.shape)
>>> print(b)
>>> b.sum(axis=0# [12, 15, 18, 21]
>>> b.sum(axis=1# [6,22,38]
>>> b.sum(axis=2# Error
cs

 

 

위의 예를 보면 b의 shape이 (3, 4)인데, axis=0은 기본적으로 shape에서 가장 왼쪽에 있는 축을 의미한다고 생각하면 된다. 따라서 axis=0은 (,4)가 나와야한다고 생각하면 연산의 결과를 이해하기 쉽다. 따라서 요소가 4개가 나와야하니, 열(columns) 별로 연산을 한다고 생각하면 된다(라인4). 반대로, axis=1은 shape의 두번쨰인 (3,)이므로 3개가 나오면 된다고 생각하면되므로, 행별로 연산을 한다고 생각하면된다. 물론 ndim(차원의수)가 2개이니 axis 2는 불가능하다(에러, axis는 0축부터 시작하기 때문). 즉, axis 축이 가르키고있는 shape 숫자와 같은 결과가 출력된다. 

 

1
2
3
4
= np.aragne(24).reshape(2,3,4)
= sum(axis=0# dim 2. except 2 shape, aggregation result (3,4)
= sum(axis=1# dim 3. except 3 shape, aggregation result (2,4)
= sum(axis=2# dim 3, except 4 shape, aggregation result (2,3)
cs

 

 

 

범용함수 


 

1
2
3
4
5
6
7
# python general function
x1 = add(x1, x2)
x1 = np.arange(12).reshape(3,4)
x2 = np.arange(12).reshape(3,4)
x3 = x1 + x2 # 누산기를 통한 합계
add(x1, x2, x1)  # equivalent to 1 line (누산기X)
x1 += x2 # equivalent to 1 line (누산기X
cs

 

 

 

브로드케스팅 & 엘리먼트와이즈


브로드 케스팅 규칙은 '연산의 두 배열에 대한 후미 축의 크기가 동일한 크기이거나 둘 중 하나가 1이어야 한다는 것'이다. 예를 들어, (1, 3)과 (1,1)은 후미축의 크기가 동일하지는 않지만, 후미축이 1이므로 연산값을 동일하게 반복하여, 계산할 수 있다. 라인 6번~9번이 이에대한 설명이다. 그러나, 1) 반대로 후미축의 크기가 1이 아니거나, 2) 연산할 배열의 후미축이 다른경우는 라인 11번과같이 에러가 발생할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# element wise
= np.array([1,2,3])
= np.array([2,2,3])
+ b
 
# Braodcasting
= np.array([1,2,3]) 
= 2 # scala varible 
+ b
 
# Error
= np.array([1,2,3])
= np.array([1,2])
 
 
cs

 

아래의 예시에서도 1번~7번라인처럼 a.shape = (3, 3)이고 b가 (3, 3)이기 때문에 해당 연산이 가능하다. 또한 10번~라인부터처럼 a의 후미축의 크기가 1이고, b의 후미축의 크기가 1이 경우에도 해당 연산이 가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
 
= np.array([[000],
              [123],
               [234]) # shape = (3,3)
= np.array([1,2,3]) # shape = (1,3)
+ b # last dimensions of both variables are equal
 
 
# Broadcasting is possible if dimension of any variabels is 1
from numpy import array, newaxis
= array([0,1,2,3,4])
= array([1,3,2]) 
print(a.shape, b.shape) # (5,), (3,)
print(a[:, newaxis].shape) (5,1)
a[:, newaxis] + b ; 
cs

 

 

 

인덱싱 & 슬라이싱


판다스의 인덱싱과 슬라이싱처럼, 넘파이에서 인덱싱과 슬라이싱이 가능하다. 이를 통해, 할 수 있는 것은, 배열에서의 부분집합을 추출하는 것이다. 리스트와 마찬가지 인덱싱은 0번부터 인덱스가 시작한다. 음수를 적용한 슬라이싱/인덱싱 도 리스트와 동일하다. 

 

차원별 인덱스하는 방법이 조금씩 다른데, 1차원에서는  np.array[0축], 2차원에서는 np.arrary[1축, 0축], 3차원에서는 np.array[2축, 1축, 0축]으로 지정하여 추출할 수 있다. 

 

한편, 축인덱스를 생략해서 출력할 수 있는데, 예들 들어서, 차원의 수가 3이경우에, a[-1] 과 같이하면, a[-1::]와 동일하다.

1
2
3
4
5
6
>>> import numpy as np
>>> a = np.arange(24).reshape(2,3,4)
>>> a[-1::]
array([[[12131415],
        [16171819],
        [20212223]]])
cs

 

'...'을 이용해서 인덱스를 생략할수도 있다.  

1
2
3
4
5
6
# a[:,:,2] vs  a[::2] 비교
>>> print(a)
a[0::] # 2축에 대해서 시작이 0, 맨 뒤까지 뽑겠단 코드
a[::2# 2추게 대해서, 시작이 0, 2step 단위로
a[0,:,:] # 2축에 대해서 0번인덱스이고 모든 인덱스를 포함한 서브셋을 출력
a[0,...]
cs

 

 

 

Stack

 


축에 대한 이해가 필요하다.  종류로는 hstack, vstack, dstack 이 있다. hstack은 옆으로 쌓는 것이기 때문에 0축의 개수가 늘어나며, vstack은 아래에 row을 하나 더 붙이는 것이기에, 1축의 개수가 늘어난다. dstack은 dimension이 늘어나는것인데, (3, 4)짜리 2개를 nstack하면 (3, 3, 4)의 모양의 배열이 출력된다.

 

vstack:

hstack

nstack: 첫 번째 배열의 0번과 두 번째 배열의 0번을 조합하여 하나의 마지막 축에 해당하는 요소를 하나 더 늘린다.

stack((넘파이배열, 넘파이배열, 넘파이배열...), axis = 축): axis에 따라 범용으로 사용

축에 대한 파라미터가 없으면, 0축으로 합쳐진다.  (3,4) shape인 2개의 넘파이가 0축을 기준으로 합쳐지면 (2,3,4)가 된다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# hstack: 배열을 옆에 추가하는 방식. horizontal 옆으로 쌓는다
= np.arange(3)
= np.arange(3,6)
 
np.hstack((a,b)) #
print(np.hstack((a,b)).shape) # (6,)
# vstack
np.vstack((a,b)) 
print(np.vstack((a,b)).shape) # (2,3)
# dstack: 깊이별로 쌓는다. 차원이 하나 증가한다. '[]' 대괄호가 증가한다
np.dstack((a,b))
print(np.dstack((a,b)).shape) # (1,3,2)
 
# newaxis
# 1차원이 newaxis을하면 2차원이 되고, 
# 2차원이 newaxis을하면 3차원이 된다.
= a[:, np.newaxis]
= b[:, np.newaxis]
np.hstack((a,b))
cs

 

 

dstack은 같은 배열에서, 0축이 2배로 증가하는 것과 같다. 

 또한, 축에 숫자를 넣을 때, 축의 숫자는 shape에서 순서가 변하는 것과 같다. (3, 4)의 2개의 배열이 합쳐질 때, axis = 0이면, shape의 첫요소 2가 되어서 (2,3,4)이며, axis =1이면 (3,2,4)가 되며, axis =2 이면 (3,4,2)가 된다.

 

r_(), c()

r_(): R에서의 rbind와 유사하다.

c_(): R에서의 cbind와 유사하다 .

 
1
2
3
4
5
6
7
8
9
10
11
import numpy as np
= np.array((1,2,3,4)) # shape (4,)
= np.array((5,6,7,8))
= np.array((9,10,11,12))
 
# r_()
np.r_[a,b,c] # R bind와 유사하게, 길이를 늘려준다. shape (12,)
np.r_[[a],[b],[c]] # 리스트로 구분하고 싶다면..
np.vstack((a,b,c)) # vstack과 동일
print(a.shape, b.shape, c.shape) # (4,) 을 vstack하면 (3,4)
print(np.vstack((a,b,c)).shape) # (3,4)
cs

 

 

Split

split은 array 배열을 받아서, 리스트로 반환한다.split은 n개로 나누어서 나머지가 0이 아니면 에러가 나온다.

  • hsplit: 0축을 기준으로 나누어 반환함. hsplit 은 split(~, axis=1)과 같다. 두 번째 shape을 기준으로 잘라서 나온다. 2, 3, 4를 자르면 (2,1,4)가 출력됨.
  • vsplit: 가장 맨 앞의 shape 기준으로 나누어서 반환함. (3, 4)을 split하면 (1,4)가 요소인 배열이 나옴. split(~, axis=0). (2,3,4)을 2로 나누면 (1,2,4)가 나온다.
1
2
3
4
5
6
7
8
# Split
= np.arange(12).reshape(3,4)
print(a)
 
# np.vsplit
a_vsplit = np.vsplit(a, 3# (3,4) shape짜리를 vertical로 붙여준다.
print('shape:', a_vsplit[0].shape) # (1,4)가 3개, (4,)이 3개가 아님.
 
# np.hsplit 
a_hsplit = np.hsplit(a, 4) # (3,4) shape짜리를 4개로 쪼개어
print('shape:', a_hsplit[0].shape) # (3,1)이 4개
cs

 

3차원으로 확장하면, 다음과 같다.

 

튜플형식으로 나누자고하면, 다음과같다

예를 들어, hsplit (2,5,6)은 0~1까지 하나, 2~4까지하나 5~6에서하나 6부터 끝까지 출력된다.

 

 

  • Numpy.array_split(array, num_section, axis = 0)

 

 

split은 나눠 떨어지지 않으면, 오류가 나온다. 그러나, 나눠 떨어지지 않는 정수를 이용하여, 배열을 분리한다.

SQL에의 NTILE처럼, n개로 나눈후에 나눈 나머지는 앞에서부터 순차적으로 가져간다. 예를 들어 13개를 3개로 나누면, 5, 4, 4개로 나누어진다.

 

 

 

 

 

데이터복사(View, Copy)


Numpy.view() = 동일 주소값의 데이터 + 형태만 다른 배열 객체

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

같은 데이터를 참조하지만, 다른 shape을 가지는 객체를 의미한다. 데이터 자체는 처음 뷰를 생성한 객체가 가지고 있다. 예를 들어 a를 통해서 뷰를 생성한 경우에는 shape은 다르게 가질 수 있다. 데이터의 부분집합을 추출할 때, view을 뽑을지, copy로 뽑을지 고민해야한다. copy와 view의 차이점은 copy는 완전히 메모리상에 완전히 새로운 데이터를 갖는다 (주소값이 다르다). 뷰는 메모리상에 같은 데이터를 참조를 하지만, 다만 shape가 다르기 때문에, 읽는 순서가 달라질 뿐이다. (= 깊은 복사 , copy) 

뷰를 통한 shape은 다르게 가질 수 있다.

 

 

파이썬이 [1, 2, 3] 을 저장할 때, 1은 따로 저장, 2도 따로저장, 3도 따로 저장한다음에, 1의 주소 2의 주소 3의주소 이렇게 연결자료구조로 만든다. 그러나 numpy 차원 배열을 저장할 때는 np.array([1,2,3], type = int32)처럼 숫자가 크기를 고려해서 저장하기 때문에, [1][2][3] 연결해서 32비트씩을 가져서 한개의 값을 인덱싱을할 때 바로 알 수 있다. 첫 주소만 알면 나머지는 변수의 자료의 크기만큼만 건너 뛰면되기 때문에, 바로 알 수 있다.

 

인덱싱할 때, 배열로 뽑아올 경우는 copy가 온다.

 

 

 

고급인덱싱를 이용한 인덱싱


 

1
2
3
4
5
6
7
8
# 리스트 배열로 인덱싱
= np.arange(12)**2
ind = np.array([1,1,3,8,5])
a[ind] # array([ 1,  1,  9, 64, 25])
 
# 다차원으로 만들기
= np.array([[3,4], [9,7]])
a[j]
cs

 

다차원 인덱싱


인덱싱 자체가 여라차원인 경우를 의미한다. X[Y, Z] 이러한 인덱싱에,  Y도 다차원, Z도 다차원을 사용하는 경우를 의미한다.

이러한 인덱싱은 X[Y,:]을 우선 계산한다음에, X[Y. :]에 Z인덱싱을 적용한다. 아래의 예시를 보면 이해가 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 다차원 인덱싱
import numpy as np
= np.arange(12).reshape(3,4)
= np.array([[0,1], [1,2]])
= np.array([[2,1], [3,3]])
 
 
a[i,:] 
# array([[[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7]],
 
#        [[ 4,  5,  6,  7],
#         [ 8,  9, 10, 11]]])
# 위의 조건에서 j을 적용한다. 즉 a[i,:]에서 2번째 컬럼을 찾고, 1번쨰 컬럼, 
3번쨰 컬럼, 3번째 컬럼을 찾는다
 
a[i,j]
# array([[ 2,  5],
#        [ 7, 11]])
cs

 

 

최대값 검색

 

 

 

 

 

 


np.argmax : 최대값을 갖는 인덱스를 찾는다.

 

 

 

 

 

 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 배열 인덱스를 이용한 최대값 검색
import numpy as np
data = np.sin(np.arange(20)).reshape(5,4)
# array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
#        [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],
#        [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],
#        [-0.53657292,  0.42016704,  0.99060736,  0.65028784],
#        [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])
 
ind = data.argmax(axis=0)
# array([2, 0, 3, 1])
 
# 이렇게 복잡하게 해야하는데.
data_max = data[ind, range(data.shape[1])]
range(data.shape[1])
 
# 아래의 경우처럼 바로 찾는 것도 가능하다.
data.max(axis=0)
cs

 

 

 

인덱싱을 이용한 값 변경


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# --인덱스를 이용한 값 변경--
import numpy as np
 
= np.arange(5)
a[[1,3,4]] = 0 # 인덱스를 이용한 값 변경
# a[1,2] # 1,2 을 넣으면 a를 2차원으로 인식해서 shape 1,2 인덱스를 찾는다.
a[[1,2]] # [1,2] 을 넣어야한다.
 
= np.arange(5)
# [0 1 2 3 4]
 
 
a[[0,0,2]] = [10,20,30# 0번째 인덱스는 20이 할당
a[[0,0,2]] += 1 # 가장 마지막 값만 변경된다.  #[1,1,3,3,4]
# a[[0,2]] 만 실행이 된다.
cs

 

 

 

논리 배열 인덱스를 이용한 인덱싱


 

1
2
3
4
5
# 부울 배열을 이용한 인덱싱 (True / False을 이용한 인덱싱)
= np.arange(20).reshape((4,5))
= a% 2 ==0 # 나누기 2가 0인 경우만 true가 반환하다. 
a[b] = a[b] **2 # 재할당도 가능하다
a[b] = 0 
cs

 

 

ix_()


1
2
3
4
5
6
7
8
9
10
# ix_() 
= np.array([2,3,4,5])
= np.array([8,5,4])
ax, bx = np.ix_(a,b) # N개의 1차원 시퀀스를 입력 받아 추출해서 ,
각각 N차원인 N 개의 출력을 반환
 
# (array([[2],
#        [3],
#        [4],
#        [5]]), array([[8, 5, 4]]))
 
cs

 

 

 

 

리듀서(Reducer)


집계하는 함수를 모두 리듀서라고 부름(reducer). 매개변수로 함수와 값들을 입력받아 각 요소들에 함수를 적용하고 하나의 결과의 값을 반환하는 함수

1
2
3
4
5
6
7
8
9
10
# 집계하는 함수를 모두 리듀서라고 부름(reducer)
def func_reduce(*vectors, func=np.add):
    vs = np.ix_(*vectors)
    r = func.identity # 항등원을 계산
    print(vs)
    for v in vs:
        r = func(r, v)
    return r
 
func_reduce(a,b)
cs

 

배열 조작


- 행렬 곱: @ 또는 dot

- 역행렬 np.linalg.inv(x)

- 특이값 분해: u, s, vh = np.linalg.svd(A)

- 고유값, 고유벡터 = w, v = np.linalg.eig(x)

 

원본행렬 A(m, n)를 쪼개서 U라는 행렬과 sigma라는 대각행렬 V(t) ㅍ

(m, m) (m, n), (n, n) 이 반환. 원본행렬을 가장 잘 표현할 수 있는 왼쪽상단. 오른쪽 하단으로 갈 수록 원본행렬을 표현하기에는 대표적이지 않은 값일 수 있음. Sigma 행렬을 그래서 다 사용하지 않고, 일부를 잘라서 사용한다.

원본행렬이 null 이 너무 많은 경우, 특이값 분해를 한 다음에, 다시 원본행렬을 만들면 null이 채워지는 경우가 있다.

 

선형 연립방정식


역행렬을 구하려면 정방행렬을 만들어야하는데, 행의수가 열의수가 훨씬 많을 때, left pseudo inverse 을 구한다.

 

히스토그램 

히스토그램 구간내의 값만 알려준다.

 

 

 

dtype


unsigned int8

np.fromstring()

 

 

 


np.power: np.power은 흔히 멱급수를 따른다고하는 식으로 반환한다. 쉽게설명하면 np.power(a, b)은 a**b와 같다.

np.power(10, 2) # 100
np.power(3, 2)  # 9
np.power(9, 0.5) # 3.0

First array elements raised to powers from second array, element-wise.

Raise each base in x1 to the positionally-corresponding power in x2. x1 and x2 must be broadcastable to the same shape. Note that an integer type raised to a negative integer power will raise a ValueError.

 

Parametersx1array_like

The bases.

x2array_like

The exponents. If x1.shape != x2.shape, they must be broadcastable to a common shape (which becomes the shape of the output).

반응형

'Data science > Python' 카테고리의 다른 글

0. Python 이란?: 언어형태, 특징, 메모리관리  (0) 2019.06.16
python 시각화 : Seaborn  (0) 2019.06.10
Python 시각화: 기본  (0) 2019.05.30
2. Python: function  (0) 2019.03.19
1. 기본자료형, Python Built-in Code  (0) 2019.03.05

Python


[]: 대괄호 내 존재하는 문자열 내 하나를 가리킨다.

>>> [] 


R

반응형

'Data science' 카테고리의 다른 글

Network analysis  (0) 2019.11.20
Undersampleing & Oversampling  (0) 2019.07.08
머신러닝 모델 분류  (0) 2019.03.12
Reshape and Pivot table  (0) 2019.03.08
SVM (Support Vector machine)  (0) 2019.02.23

구분하는 3가지 기준

지도/비지도/준지도/강화 학습

온라인 학습 /배치 학습

사례 기반 학습/ 모델 기반 학습



배치학습: 

가용한 데이터를 모두 사용해서 훈련시킨 모델. 더 이상의 훈련이 진행되지 않고, 훈련은 주로 리소스를 많이 필요로 하기 때문에, 오프라인 학습이라고도 한다. 배치학습을 새롭게 업데이트 하려면, 이전에 훈련된 데이터를 포함하여 더 많은 데이터를 이용해서, 새롭게 모델을 학습시킨다음에 모델을 교체(replace)해야한다.

온라인 학습

데이터를 순차적으로 한 개씩 또는 Mini-batch라 불리는 작은 묶음 단위로 주입하여 훈련하는 시스템이다. 작은 단위씩 학습 되기 때문에, 학습에 들어가는 리소스가 적은 편이고, 데이터를 수집하고 모델이 들어가는만큼 바로 학습이 된다. 모델의 학습이 즉각적으로 이용되어야하는 상황에 이용이 가능하다. e.g) 주가 예측


사례 기반 학습과 모델 기반 학습




다중 분류


One-versus-all (one-versus-the rest, OVA) 전략.

SVM과 logistic regression 과 같은 알고리즘은 이진 분류기인데, 이 분류기를 통해, Label이 여러가지인 분류 (다중분류)도 가능하다. 이 전략이 OVA전략이다. 예를 들어서, digit image 10개 중에 0이냐 아니냐를 분류하는 분류기 1, 1이냐 1이 아니냐를 분류하는 분류기 2 등... 총 10개의 숫자에 대해서 분류기를 만들어놓고, 실제 분류할 때 분류기의 결정 점수중에서 가장 높은 클래스의 분류를 선택하면 된다. 이를 OVA라고 한다.


One-vursus-one (OvO)

0과 1의 구별, 0과 2의 구별 등... 각 모든 조합마다 이진분류기를 만들어 놓으면 이를 OvO 전략이라고 한다. 

분류하고자 하는 클래스가 N개이면 , N * (N-1)/2개가 필요하다. (nC2). 장점은 각 분류기으 ㅣ훈련에 전체 훈련 세트중 구별할 두 클래스에 해당하는 샘플만 필요하다는 것이다. 여러 잡다구리한 샘플은 필요없다. SVM과 같은 일부 알고리즘은 큰 데이터세트에는 민감해서, 차라리 작은 훈련세트에서 많은 분류기를 훈련시키는 쪽으로하면 빠르다. 

반응형

'Data science' 카테고리의 다른 글

Undersampleing & Oversampling  (0) 2019.07.08
Regular expression  (0) 2019.03.12
Reshape and Pivot table  (0) 2019.03.08
SVM (Support Vector machine)  (0) 2019.02.23
Decision Tree (의사결정나무)  (2) 2019.02.15


데이터가 아래와 같을 때, 변환하는 과정을 Pivoting이라고 한다. 데이터베이스에 들어가는 로그는 업데이트를 하면 안된다. 그렇기 때문에 아래로 길어야하는  ROW 데이터 형식으로 로그형식을 나타내야한다. 단점은 사원번호가 변경되야할 경우가 있는데, 그럴경우는  row 포맷은 사용할 수 없다. 계속 축적되야하는 경우네는 row포맷으로 넣는다.

------------------

사원번호, 요일, 매출액

2019253322,월,100

2019253322,화,200

2023738232,월,200

2023738232,화,300 


----------------


아래의 wide포맷은 row 포맷으로부터 바꿔 사용할 수 있다. 그렇게 될경우 전체 사원번호를 관리하기도 편하다. 사원정보는 변경되할 필요는 wide포맷으로 넣는다.

------------------

사원번호, 월, 화,수

100,100,200, 0

200,200,300,250

------------------

반응형

'Data science' 카테고리의 다른 글

Regular expression  (0) 2019.03.12
머신러닝 모델 분류  (0) 2019.03.12
SVM (Support Vector machine)  (0) 2019.02.23
Decision Tree (의사결정나무)  (2) 2019.02.15
Pandas Dataframe Manipulation  (0) 2019.02.14

+ Recent posts