python의 hashable object은 hash함수에 인자로 들어갈 수 있는 객체들을 의미한다. hashable에 대한 정의로 또 hash라는 단어가 들어갔다. 그럼 이번에 hash라는 것이 무엇인지 알아보면 될 것이다.
hash(object): object의 저장된 내용을 기준으로 한 개의 정수를 생성하여 반환하는 함수
- 이 함수는 hasher라고도 부른다. hash 함수안에 인자로 들어가는 object은 하나의 값일 수도 있고, 여러 개의 값을 갖고 있는 컨테이너 일 수도 있다. 즉, 내용이 뭐든지간에(사실, 조건이 없진 않다..), 이에 해당하는 숫자 하나를 무조건 생성한다고 생각하면 된다. 아래의 예시처럼, string이 무엇이든 간에 hash function을 통과하고나면 무조건 하나의 숫자로 반환되는 함수를 의미한다. 이는 튜플일 수도 있는데 (1, 2, 3) 을 hash function에 넣어, 2366528764324이 나왔다고 하면, 이 튜플은 hashable object 라고 부른다.
비교를 위해 사용된다. 즉, hash을 하고나면, 각 객체가 숫자로 나오기 때문에, 같은 객체인지 다른객체인지 비교가 가능하다. 같은 숫자면 같은 객체로 인식한다. 또한, 컨테이너인 객체들도, hash을 이용하면 한번에 비교가 가능하다. 가령 (a, b, c)인 객체와 (d, b, c)인 객체를 비교할 대도, 각각의 원소들이 같은지 여러번 비교를 하는 것이 아니라, hash 값만 있으면 비교가 가능하므로, 한 번의 비교 연산만이 필요하다. 즉, 1) Computationally robust함을 유지하기 하기위해 사용된다 (쉽게 말하면, 다른 객체는 다른 해시함수를 갖어야한다). 다른 객체들이 같은 해시를 가지면 충돌이 일어날 수 있다. 2) 같은 오브젝트가 일관성 있게, 같은 값을 가질 수 있도록 표식한다.
모든 오브젝트는 hashable할까?
리스트라든가 셋, 딕셔너리와 같이 데이터 변경이 가능한 컨테이너은 hashable하지 않다. 이유는 데이터가 변경가능한(immutable)한 객체들은 해시를 만들어놓고도, 중간에 데이터가 변경되면 해쉬값도 매번 변경되어야되기 때문에, 이런경우 type error가 발생한다. 즉, Numeric, immutable container은 hashable이다.
생각해보면, 숫자(int, bool, float)은 그 자체로 숫자이기 때문에, 숫자 중간을 바꿀 수 없고, 변경불가능한 컨테이너(immutable container)은 tuple, string, bytes, forzenset도 변경이 불가능하기 때문에 hashable하다. 또한, numeric 들은 int이든 bool이든 float은 타입이 다르더라도 비교해서 동등을 알 수 있다. 아래의 예시를보면 1이든 True (bool type) 이든 hash값이 동일해서, 동등비교를해도 True인 것을 알 수 있다.
이를 이용하는 경우, 중복여부를 빠르게 판단할 수 있는데, 중복이 없어야하는 dict, set의 item을 비교할 때 사용될 수 있다. 따라서, set과 dict의 key값들은 중복이 되면 안되기에, hashable해야한다.
TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
아래와 같이 numpy 배열의 데이터타입이 object 인 경우. numpy 내에 object로 스트링으로 숫자나 글자들이 들어가있을 수도 있다. 추출한 행,열의 dtype을 확인하여라.
np.isnan(np.array([np.nan,0], dtype=object))TypeError: ufunc 'isnan'not supported for the input types,and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
컴퍼일 언어는 원시코드를 컴파일이라는 과정을 통해 기계여로 번역한 파일을 만들고, 만든 파일만을 가지고 파일을 통해 실행시킨다. 즉실행파일만 미리 만들어두는 것이다. 그러나, 컴파일 과정이 오래걸리고, 실행시키는 컴퓨팅 환경에 많이 영향을 받지만, 컴파일 파일(실행파일)만 있으면 되니까, 매우 빠른 속도로 실행될 수 있다.
예) C, C++
인터프리터 언어
- 인터프리터(해석기)에 의해서 원시 소스코드(진짜 코드)를 한 줄씩 읽어 실행하는 언어이다. 즉 Line by Line으로 읽을 수 있다.
- 컴파일 언어보다 더 느리게 실행된다. 이는 미리 컴파일 시켜놓아, 바로 실행되는 형태가 아니기 때문이다.
- 장점으로는, 코드를 빠르게 실행시켜볼 수 있고, 대화식(내가 입력하면서, 컴퓨터가 바로 출력하는 형태)로 코드를 개발 할 수 있기에, 교육용으로 사용되는 경우가 많다.
- 예, Python, JavaScript, PHP
파이썬 개요 및 특징
파이썬은 1989년 귀도 반 로섬에 의해 개발되었다.
특징으로는 다음과 같다
플랫폼 독립적: 이는 어느 운영체제 관계없이, 또는 PC, 모바일등과 같이 다른 환경에서 사용 가능하다는 의미이다.
인터프리터식: Line by line + 대화식으로 사용가능
객체지향적: 자료형을 숫자, 문자, 자료구조들을 파이썬 객체라고하는 어떤 상자안에 저장된 형태로 만들어 사용
동적 타이핑 대화형언어(dynamically typed): 예를 들어, 변수 A를 문자형으로 지정했다고 하고, 이를 숫자형으로 마음대로 바꿀 수 있다. 다른 언어들은 미리 메모리 공간을 잡아 놓기 때문에, 변수의 형태를 마음대로 변경하는것을 지원하지 않는다. (=This implies that dynamic typed languages do not require the explicit declaration of the variables before they’re used) [1]
기본 제공하는 함수(기능)은 거의 없고, 대부분 많은 기능이 라이브러리로 구성됨
요약하자면, 가독성(문법 간결), 확장성(라이브러리), 접착성(C로 구현된것도 쉽게 만들어 붙일 수 있음, 반대도 가능), 유니코드, 동적타이핑(동적언어 + 인터프리터 언어)
파이썬의 메모리관리: 저수준컴퓨팅 ~ 가비지 컬렉션 & 레퍼런스 카운팅
파이썬의 뒷단에는 내가 지정한 변수들을 어떻게 관리하고, 메모리를 어떻게 할당/관리하는지에 대하 설명이다. [2]저수준(Low-level computing) 컴퓨팅과, 파이썬에서의 저수준 컴퓨팅, 내부 메모리 관리 알고리즘에 대해 추가적인 이해를 하고 싶다면, 본 섹션을 참고하길 바란다.
우선, 우리가 A4용지내에 수학문제를 풀고자한다면, 변수와 공식들을 써내려가면서 문제를 풀고자 할것이다. 이처럼 메모리 자체를 어떤 공책이라고 생각하면 편하다. 메모리(A4노트, 또는 책)에 변수를 지우개로 지워서 다시쓸수도있고, 더 추가적으로 쓸수도 있고, 내가 갖고있는 공책(메모리)가 부족할 수도있다. 그러나, 우리는 노트 장 수가 한정적이기 때문에 메모리 관리에 대해 배울 필요도 있다. 또한, 여백의 A4공간을 어떻게 공식을 써내려갈지도 고민해야한다. 다행히 히는 파이썬에서 알아서 해준다.
CPython?
우선, 파이썬 기본 실행(Default Python Implementation)는 CPython이라는 C로 써진 것인데, pyc파일 이나 pycache 폴더를 본적 이 있다면, 이는 bytoecode로 가상환경에서 인터프리팅된것이다. CPython도 있고, IronPython(MS에서 다운)도 있고, Jypthon도 있고.. 여러가지가 있다. 우선 여기서는 CPython에서도만 이야기하자면, Cpython은 위에서 언급했듯이 C로 쓰여진것이고, 파이썬 bytecode을 인터프리팅 하는 실행계획 같은거다. 이 CPython에 메모리 관리에 필요한 구조와 알고리즘 코드가 들어있다. 따라서, 파이썬의 메모리 관리를 알고자한다면, 우리는 CPython에 대해 좀더 이해를 한다.
CPython도 역시 객체로 구성되어있는데, (예를 들어, 파이썬에 string type)같은 것이다. PyObject라고 불린다. 이 PyObejct는 모든 파이썬 객체의 조부모에 해당하는 객체인데 Ob_refcnt, ob_type을 포함하는데 이에 해당하는 설명은 다음과 같다.
ob_refcnt: 레퍼런스 수(Reference count)
ob_type: 포인터(다른 타입을 지정하는 포인터)
레퍼런스 카운터는 가비지 콜렉터(Garbage collection)에 사용되고, pointer는 실제 오브젝트의 타입을 가리키는데 사용된다. 오브젝트 타입은 파이썬 오브젝트에서 사전형(dict)s나 숫자(int)형과 같은 것을 설명하기위한 구조이다.
Carbage collection(가비지 콜렉터)
다시 A4 용지에 수학문제를 풀고자한다고 생각해보자. 임의로 변수 X에 대해서 식을 풀어쓰다가 Z가 필요해서 써내려갔다. 그런데 사실 Z는 안쓰게되서 A4 한구석에 Z라고만 써놓기만했다면, 수식에서는 전혀 쓸모가 없기때문에, Z를 지워도 무관할 것이다. 이와 같이, 파이썬 코드내에서 언급이 되지 않는(Unreferenced) 객체들은 지워야하는데, 이럴 때 Reference count가 0인 경우에 그 파이썬 객체를 삭제하게 된다. 레퍼런스 카운트에 대해서 조금 더 자세한 예를 들면, 아래와 같다.
1
2
3
4
5
6
7
ref = [5,6,7]
# ref 객체가 5,6,7을 가르키고 있기 때문에, 레퍼런스 카운트가 1이다
my_ref = ref
# 또한, my_ref가 ref의 주소를 가리키지만, 이는 사실 [5,6,7]을 가르키기 때문에 레퍼런스 카운트가 2이다.
객체 ref가 [5,6,7]을 직접 저장하고 있는것이 아니라, 주소값만 가지고 [5,6,7]을 가르키고 있는 것이다. 그렇기 때문에 이에 대한 레퍼런스카운드가 1이다. 3번라인은 my_ref객체가 ref객체를 가르키는 것처럼보이지만, 사실은 ref가 가지고있는 [5,6,7]에 대한 주소를 가르키기 때문에 my_ref 도 [5,6,7]을 가르키는 주소값만 가지고 있다. 즉 1번과 3번라인의 주소값이 동일하게 가르키고 있기 때문에 레퍼런스 카운트가 2이다. 이는 id(ref) 와 id(my_ref)을 출력해보면 동일한 주소값을 가지고 있음을 알 수 있다. 또한 6번라인처럼, 이전에 주소값에다가 연산을 또 하면 레퍼런스 카운트가 증가한다. 이처럼 레퍼런스 카운트가 증가하는 반면, 필요가 없는 경우 삭제되는데, 레퍼런스 카운트가 0이 되는 경우 변수를 삭제한다.
Seaborn(발음: 시본)은 파이썬 데이터시각화 라이브러리이며, matplotlib라는 파이썬 시각화툴을 기반으로하고있다. Seaborn은 고수준(high-level) 인터페이스로, 통계적인 그레픽이나 디자인측면에서 손쉽게 구현이 가능하다(여기서 "고수준"은 사용자가 디테일한 수준까지 설정할필요없이, 몇가지 설정으로만 사용할 수 있다는 것이다. 반대어는 저수준으로 디테일한 수준까지 고려할 수 있음을 의미한다). 쉽게얘기하면, 그레프를 조금 더 쉽게 그려주는 페키지이다. 그레프를 통상 관계형, 범주형, 분포, 회귀, 행렬로 나누어서 설명을 한다. Seaborn은 스스로 그래프를 그리는 기능이 있어서 간편하게 사용해볼 수 있다.
그레프 크기 설정
matplotlib.pyplot.subplots()을 이용하여 서브플롯을 그릴 때, 너무 작은 서브플롯이 그려져서 보이지 않을 수 있다. 이 때는 matplotlib.pyplot.subplots()함수 내에, figsize라는 인자를 전달하면 된다. figsize은 tuple도 가능하고, list도 가능하다. 순서만 맞춰서 전달하면 된다. 가로가 12, 세로가 8인 크기로 만드록 싶으면, [12, 8], 또는 (12, 8) 둘 다 상관없다. 단위는 인치이다.
seaborn에서는 set_style, set, set_theme이라는 함수를 제공한다. 각각의 기능은 다음과 같다.
1. set(context, style, palette, font, font_scale, color_code, rc): set_theme과 동일한 함수이다. 스타일, 팔레트, 글꼴, 글꼴 크기 등을 설정. 이는 앞으로 그리게 되는 모든 플롯의 그림에 영향을 준다. 즉, 환경변수 설정이다. (추후 버전에서 삭제될 얘정이다)
2. set_theme(context, style, palette, font, font_scale, color_code, rc): 이 함수를 사용하면 앞으로 그려지는 plot들의 테마들이 일괄적으로 세팅된다. 이 함수를 사용하면 python.matploblib 내의 rcParams system을 변경하게되는데, 이렇게되면 전체적인 플롯들의 테마(글꼴, 팔레트 등)이 일률적으로 변경된다. 파라미터는 다음과 같다.
Parameter
- context: string. or dict. 배율조정. 그림 사이즈의 크기가 아니라 그레프의 배율이 커진다.
- style: string. or dict. {None, 'darkgrid', 'white grid', 'dark', 'white', 'ticks'} 중 하나 가 들어간다.
- set(style='darkgrid')라고 해도되지만, 다음에 소개할 set_style('whitegrid')함수를 사용해도 된다. set하나 가지고, 축을 변경할 수도 있지만, set_axis을 이용해도 된다.
3. set_style(style, rc):은 set_theme과 동일하나 일부 특성만 조작을 할 수 있는 함수이다. "배경색", "배경 내 격자무늬(=그리드)"의 사용여부를 기본으로 사용할 것인지 말것인지에 대한 설정을 할 수 있다.
- 예제, TimesNewRoman으로 폰트 변경
1
sns.set_style({'font.family':'serif', 'font.serif':['Times New Roman']})
vmin, vmax는 최대 최소값을 지정할수 있는 값 인자이다. cmap은 컬러맵을 의미하며, 아래의 예시와 같이 컬러맵에 대한 내용을 string 또는 리스트로 지정해주면된다. 변수들간의 상관계수를 색으로 인코딩하여 행렬로 표시한다. vmin, vmax=은 최대 최소를 의미한다. 상관계수는 1 annot =True이면 값 안에 숫자를 입력함
Line 1: JointGrid 객체를 만들 것인데, 이에 필요한 데이터를 인자로 넣어 생성, x에 sepal_length , y에 sepal_width을 대입할 것임
Line 2: plot(joint_function, marginal_function) 을 할 때, 이변량 그레프는 어떤 것을 그리고, 일변량 그레프는 어떤 것을 그릴것인지 정함. joint_function은 이변량 그레프를 어떤것을 그릴것인지 의미. marginal function은 이변량 그레프 외의 가장자리에 어떤 그레프를 그릴 것인지를 의미
파이썬에서 시각화 할 수 있는 여러 패키지들이 있다. 여러가지가 있지만 대표적으로 사용되는 것들은 다음과 같다.
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'고해상도를 그리기 위한 코드
[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 객체가 리턴이 된다. Figure 객체는 도화지이기 때문에, 우리는 그림을 그릴 때, 어느 구역에서 그릴지만 지정해주면 된다. 바로 axis[0,0], axis[0,1] 처럼 몇 번째 구역에 그릴 것인지, 바로 직관적으로 그릴 수 있다.
히스토그램이 bin의 개수에 따라서, 표현이 많이 달라지는데, 커널밀도함수(kernel density funciton)를 표현해서, 데이터의 분포를 분포를 이용하여 완만하게 그려줄 수 있다. 유사하게 바이올린플롯도 kernel density function으로 이용해서, 각 자료의 구간을 완만하게 표현해주는 그레프이다.