마케터의 데이터 분석 공부#2 : NumPy
2.2 ndarray의 dtype
dtype은 ndarray가 메모리에 있는 특정 데이터를 해석하기 위해 필요한 정보를 담고 있는 특수한 객체다.
IN
GD_arr1 = np.array([1,2,3],dtype=np.float64)
GD_arr1.dtype
OUT
dtype('float64')
IN
GD_arr2 = np.array([1,2,3],dtype=np.int32)
GD_arr2.dtype
OUT
dtype('int32')
위 코드처럼 각 배열의 dtype이 확인 가능하다. 산술 데이터의 dtype은 float나 int 같은 자료형의 이름과 하나의 원소가 차지하는 비트 수로 이루어진다. 그리고 dtype이 있기에 Numpy가 강력하면서도 유연한 도구가 될 수 있었는데, 천천히 알아보도록 하자.
Numpy의 자료형
EX) 자료형(자료형 코드): 설명
int8, uint8(i1, u1)
부호가 있는 8비트 정수형과 부호가 없는 8비트 정수형
int16, uint16(i2, u2)
부호가 있는 16비트 정수형과 부호가 없는 16비트 정수형
int32, uint32(i4, u4)
부호가 있는 32비트 정수형과 부호가 없는 32비트 정수형
int64, uint64(i8, u8)
부호가 있는 64비트 정수형과 부호가 없는 64비트 정수형
float16(f2)
반정밀도 부동소수점
float32(f4 or f)
단정밀도 부동소수점, C언어의 float형과 호환
float64(f8 or d)
배정밀도 부동소수점, C언어의 double형과 파이썬의 float 객체와 호환
float128(f16 or g)
확장정밀도 부동소수점
complex64, complex128, complex256(c8, c16, c32)
각각 2개의 32,64,128비트 부동소수점형을 가지는 복소수
bool(?)
True와 False 값을 저장하는 불리언형
object(0)
파이썬 객체형
string_(S)
고정 길이 아스키 문자열형. 길이가 10인 문자열 dtype은 S10이 된다.
unicode_(U)
고정 길이 유니코드형. string_형과 같은 형식을 쓴다.
Numpy의 모든 dtype을 외울 필요는 없다. 부동소수점, 복소수, 정수, 불리언, 문자열, 일반 파이썬 객체 같은 일반적인 종류의 자료형만 신경 쓰면 된다. 주로 대용량 데이터가 메모리나 디스크에 저장되는 방식을 제어해야 할 필요가 있을 때 알아두면 좋다.
이제 ndarray의 astype 메서드를 알아보자.
IN
GD_arr = np.array([1,2,3,4,5])
GD_arr.dtype
OUT
dtype('int32')
IN
GD_float_arr = sw_arr.astype(np.float64)
GD_float_arr.dtype
OUT
dtype('float64')
ndarray의 astype 메서드를 사용해서 배열의 dtpye을 다른 형으로 변환 가능하다. 위 코드는 정수형인 GD_arr배열에 astype을 사용해서 부동소수점 형식의 GD_float_arr 배열을 새롭게 만든 것이다.
IN
GD_arr = np.array([1.8, -3.2, 0.5, -3.4, 3.3, 2.2])
GD_arr
OUT
array([ 1.8, -3.2, 0.5, -3.4, 3.3, 2.2])
IN
GD_arr.astype(np.int32)
OUT
array([ 1, -3, 0, -3, 3, 2])
위 코드는 부동소수점 형식의 GD_arr 배열을 astype을 사용해서 정수형으로 변환한 것이다. GD_arr 배열의 값이 변한 것을 확인할 수 있는데, 만약 부동소수점수를 정수형 dtype으로 변환하면 소수점 아래 자리는 버려진다.
IN
GD_numeric_strings = np.array(['1.20','-8.4', '23'], dtype=np.string_)
GD_numeric_strings.astype(float)
OUT
array([ 1.2, -8.4, 23. ])
숫자 형식의 문자열을 담고 있는 배열이 있다면 astype을 사용하여 숫자로 변환할 수 있다. GD_numeric_strings 이름의 문자열 배열을 생성하고, astype을 활용해서 숫자형으로 변경했다. Numpy에서 문자열 데이터는 고정 크기를 가지며 별다른 경고를 출력하지 않고 입력을 임의로 잘라낼 수 있으므로 위 코드처럼 numpy.string_형을 이용할 때는 주의하는 것이 좋다.
IN
GD_int_array = np.arange(15)
GD_int_array
OUT
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
IN
GD_another = np.array([.11, .390, .222, .434, .555, .786], dtype=np.float64)
GD_int_array.astype(GD_another.dtype)
OUT
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.,
13., 14.])
이렇게 다른 배열의 dtype 속성을 활용한 형 변환도 가능하다.
IN
GD_empty_uint32 = np.empty(8, dtype='u4')
GD_empty_uint32
OUT
array([1768053869, 977484654, 1702057308, 1499231090, 1548176961,
1148219457, 1549890657, 1633906508], dtype=uint32)
위 코드처럼 자료형 코드를 사용하여 dtype에 적용할 수도 있다.
2.3 Numpy 배열의 산술 연산
배열의 중요한 특징은 for 문을 작성하지 않고 데이터를 일괄 처리할 수 있다는 것이다. 이를 벡터화라고 하는데, 같은 크기의 배열 간의 산술 연산은 배열의 각 원소 단위로 적용된다.
IN
GD_arr = np.array([[1., 2., 3.], [4., 5., 6.]])
GD_arr
OUT
array([[1., 2., 3.],
[4., 5., 6.]])
IN
GD_arr * GD_arr
OUT
array([[ 1., 4., 9.],
[16., 25., 36.]])
IN
GD_arr - GD_arr
OUT
array([[0., 0., 0.],
[0., 0., 0.]])
산술 연산이 원소 단위로 적용되기 때문에 위 코드처럼 for문을 사용하지 않고 GD_arr 배열의 곱셈과 뺄셈 연산을 수행할 수 있다.
IN
1 / GD_arr
OUT
array([[1. , 0.5 , 0.33333333],
[0.25 , 0.2 , 0.16666667]])
IN
GD_arr ** 0.5
OUT
array([[1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974]])
스칼라 인자가 포함된 산술 연산의 경우에는 배열 내의 모든 원소에 스칼라 인자가 적용된다.
IN
GD_arr2 = np.array([[2., 4., 0.],[6., 2., 11.]])
GD_arr2
OUT
array([[ 2., 4., 0.],
[ 6., 2., 11.]])
IN
GD_arr2 > GD_arr
OUT
array([[ True, True, False],
[ True, False, True]])
GD_arr2 이름의 배열을 만들고 같은 크기의 GD_arr과 비교 연산을 입력해 보았다. 같은 크기를 가지는 배열 간의 비교 연산은 불리언 배열을 반환한다.
배열의 간단한 연산들을 살펴보았다. 이번 글은 여기서 마치고, 다음 글에서 ndarray 이론을 이어서 공부해보도록 하자.