데이터 핸들링 판다스 (p.39)
판다스는 파이썬에서 데이터 처리를 위해 사용되는 라이브러리.
핵심객체는 DataFrame으로, 여러개의 행과 열로 이뤄진 2차원 데이터를 담는 데이터 구조체이다.
판다스 시작- 파일을 DataFrame으로 로딩, 기본 API
import pandas as pd
판다스는 다양한 포맷으로 된 파일을 DataFrame으로 로딩할 수 있는 편리한 api를 제공한다.(read_csv, read_table, read_fwf 등)
이 때 read_csv()와 read_table의 차이는 필드 구문 문자(Delimeter)을 csv에서는 ,를 기준으로 하고 table에서는 tab을 기준으로 한다는 것이다.
이 때 read_csv()의 경우 사실 sep라는 인자를 추가해주면 어떠한 형식의 필드 구문 문자 기반의 파일 포맷도 읽을 수 있다. (한마디로 table처럼 읽기위해서는 sep=’\t’를 추가하면 된다.)
따라서 read_csv가 더 범용적으로 사용된다. read_csv의 경우 아래와 같이 인자에 파일경로를 넣어줌으로써 파일을 불러올 수 있다.
이번 예제에서는 캐글의 titanic 데이터를 사용해보겠다.
우선 read_csv로 데이터를 불러올 때, 절대경로와 상대경로의 개념이 있는데
절대경로는 파일의 경로 전체를 적어주는 것이고, 상대경로는 현재 내가 작성하고 있는 ipynb,py파일의 경로를 기준으로 하는 경로이다.
한마디로 만약 "C:\Users\DESKTOP\Downloads\train.csv” 이 경로에 data파일이 저장되어 있고, ipynb파일도 동일한 경로에 있을 때
아래 두 코드는 같은 경로로 인식한다.
df=pd.read_csv("C:/Users/DESKTOP/Downloads/train.csv")
df=pd.read_csv("train.csv")
이후 데이터를 확인해보면 다음과 같이 좌측의 csv형태의 데이터가 데이터프레임 형식으로 잘 불러와진 것을 볼 수 있다 .
데이터프레임 객체를 확인해보면 실제 데이터의 첫번째 줄에 있던 문자열들이 dataframe의 열(column)으로 할당되었다.
이처럼 read_csv()는 별다른 인자를 지정해주지 않으면 파일의 맨 처음 row를 column으로 인식하여 변환한다.
또한 제일 좌측 column을 보면, 컬럼명이 지정되어 있지 않은 0~890까지의 숫자가 있는데, 이것을 바로 pandas의 index 객체를 의미한다.
이 index값이 rdbms등의 pk와 유사하게 데이터를 식별하는 역할을 한다.
이러한 데이터 프레임을 간단하게 확인해볼 때 중간이 생략되어 나오긴하지만, 불필요한 메모리를 낭비하기 때문에 .head() 혹은 .tail()을 써서 앞부분/ 뒷부분만 간단하게 나타낼 수 있다
head와 tail 기본 파라미터는 5로, ()안에 아무것도 적어주지 않으면 자동으로 맨앞 5개 혹은 맨뒤 5개가 출력되고 n을 입력하면 n개만큼 나오게 된다.
df.head(3)
데이터 프레임의 행과 열 크기를 알아보기 위해서는 보통 그냥 데이터프레임을 찍으면 제일 좌측아래에 나오긴하지만, 더 간단하게 확인하는 방법은 shape를 이용하는 것이다.
아래와 같이 데이터프레임 객체에 .shape를 써주면 891개의 row와 12개의 column shape을 나타내준다.
df.shape
>> (891,12)
데이터프레임으로는 다양한 것들을 할 수 있는데, column의 타입, null 데이터 개수, 데이터 분포도 등 다양한 것들도 쉽게 확인 가능하다.
이를 위한 대표적인 메서드로 info()와 describe()가 있다.
info()
우선 info()메서드의 경우 데이터의 전체적 정보를 보여준다.
df.info()
info()를 사용하게 되면 좌측과 같이 나오게 되는데,
우선 맨처음 0 to 890에서 row의 행번호 및 개수를 파악할 수 있으며,
total 12 columns에서 12개의 column이 존재한다는 것을 확인하고,
각 column의 이름과 데이터 타입 null의 개수가 한번에 나오게 된다.
보면 age, cabin, embarked column에 null이 존재하는 것을 확인할 수 있다.
describe()
다음으로 describe 메서드는 칼럼별 숫자형 데이터값의 다양한 통계값들을 확인할 수 있다. ( 이 때 자동으로 int, float 형의 column에만 적용되고, object 타입은 무시된다.)
df.describe()
좌측처럼 int형과 float형 column들에 대한 개수, 평균, 표준편차, 최소값,사분위수, 최대값등을 쉽게 파악 가능하다.
이렇게 전체적인 분포를 파악할 수도 있으며, 각 column들을 따로따로 확인해볼 수도 있는데 예를 들어 column중 pclass라는 값에 대하여 확인해본다고 하자.
우선 데이터프레임의 []연산자안에 column명을 입력하면 해당 column이 series형태로 나오게된다.
여기서 series란 인덱스와 단 하나의 칼럼으로 구성된 데이터 셋이라고 보면 될 것 같다(즉 series 여러개가 붙어있는 것이 Dataframe)
우선 pclass에 어떤 값들이 있는지와 각각의 개수등을 세보기 위해 value_counts라는 메서드를 사용해보자.
df['Pclass'].value_counts()
>> Pclass
3 491
1 216
2 184
Name: count, dtype: int64
이때 value_counts로 반환된 값도 series형태인데, 인덱스가 이번에는 의미없는 단순 순서를 나타내는 값이 아니라, pclass column에 포함되어 있는 데이터 종류들을 나타낸다.
이렇듯 데이터프레임, 시리즈에서의 index는 단순 무의미한 숫자가 아니라, 데이터를 식별할 수 있는 식별자의 역할을 하며 매우중요하고, 반드시 고유성이 보장되어야 한다.
value_counts에 위처럼 ()안에 아무것도 써주지 않으면 default값으로 dropna=True가 반영되어 null값은 데이터로 간주하지 않고 세게된다. 반대로 dropna=Flase를지정해주면
null값의 개수 또한 나오게 된다. 아래와 같이 이전에 info에서 확인했던 null 값이 포함된 column인 embarked column의 value_counts를 확인해봄으로써 볼 수 있다.
df['Embarked'].value_counts()
>> Embarked
S 644
C 168
Q 77
Name: count, dtype: int64
df['Embarked'].value_counts(dropna=False)
>> Embarked
S 644
C 168
Q 77
NaN 2
Name: count, dtype: int64
DataFrame과 리스트, 딕셔너리, 넘파이 ndarray 상호 변환(p.49)
위에서는 타이타닉 데이터를 csv형태로 다운받아서, 데이터프레임으로 불러오는 작업을 했었는데, 데이터프레임을 리스트, 딕셔너리, 넘파이 등 다양한 데이터로 직접 생성할 수 있다.
scikit learn의 경우 데이터프레임을 인자로 입력받을 수 있지만, 다른 모델들 등의 경우 일반적으로 넘파이의 ndarray를 인자로 받기 때문에
변환과정을 잘 알아야 한다.
넘파이 ndarray, 리스트, 딕셔너리를 DataFrame으로 변환하기 (p.50)
데이터프레임은 리스트나 ndarray와는 다르게 column명이 존재한다. 이러한 column 명 때문에 데이터프레임이 핸들링하기에 용이한 것이다.
데이터프레임을 생성할 때나 불러올 때 따로 지정을 해주지 않으면 가장 첫번째 row가 column명으로 지정이 되는데, 이러한 것을 직접 지정할 수 있다.
우선 dataframe은 기본적으로 행과 열로 이루어진 2차원의 데이터이기 떄문에 2차원 이하의 데이터들만 Dataframe으로 변환될 수 있다.
import numpy as np
col_name1=['col1']
list1 = [1, 2, 3]
array1 = np.array(list1)
print('array1 shape:', array1.shape)
>> array1 shape: (3,)
df_list1 = pd.DataFrame(list1, columns=col_name1)
print(df_list1)
>> col1
0 1
1 2
2 3
df_array1 = pd.DataFrame(array1, columns=col_name1)
print(df_array1)
>> col1
0 1
1 2
2 3
위와 같이 column명을 col1이라고 지정해주고, pd.DataFrame()안에 변환하고자 하는 ndarray혹은 list를 넣어주고, col명을 넣어주면 데이터프레임이 생성된다.
2차원의 데이터 또한 방법은 동일하다. 아래와 같이 2개의 row와 3개의 column을 가진 데이터프레임이 생성되게 된다.
col_name2=['col1', 'col2', 'col3']
list2 = [[1, 2, 3],
[11, 12, 13]]
array2 = np.array(list2)
print('array2 shape:', array2.shape )
>> array2 shape: (2, 3)
df_list2 = pd.DataFrame(list2, columns=col_name2)
print(df_list2)
>> col1 col2 col3
0 1 2 3
1 11 12 13
df_array2 = pd.DataFrame(array2, columns=col_name2)
print(df_array2)
>> col1 col2 col3
0 1 2 3
1 11 12 13
ndarray와 list와 다르게 딕녀너리는 key와 value로 이루어져있는데, 이 때 key가 자동으로 column값, value가 각 칼럼의 데이터
dict = {'col1':[1, 11], 'col2':[2, 22], 'col3':[3, 33]}
df_dict = pd.DataFrame(dict)
print(df_dict)
>> col1 col2 col3
0 1 2 3
1 11 22 33
DataFrame을 넘파이 ndarray, 리스트, 딕셔너리로 변환하기 (p.52)
방금 전 딕녀너리를 이용해서 만든 데이터프레임을 각각 ndarray, list, 딕셔너리로 변환해보자.
ndarray의 경우 .values를 이용하면되고, list의 경우는 .tolist(), 딕셔너리의 경우 to_dict(’list’)를 적어주면 된다.
array3 = df_dict.values
print(array3)
>> [[ 1 2 3]
[11 22 33]]
list3 = df_dict.values.tolist()
print(list3)
>> [[1, 2, 3], [11, 22, 33]]
dict3 = df_dict.to_dict('list')
print(dict3)
>> {'col1': [1, 11], 'col2': [2, 22], 'col3': [3, 33]}rg_array = np.array([ 3, 1, 9, 5])
DataFrame의 컬럼 데이터 생성과 수정 (p.53)
DataFrame의 데이터 생성과 수정 또한 []연산자를 이용하여 할 수 있다.
우선 아래와 같이 새로운 컬럼을 추가하고 해당 컬럼의 모든 값에 데이터를 임의로 채워넣을 수도 있다.
df['New_col']=a
df.head(3)
이렇게 column series에 상수값을 할당하면, series의 모든 데이터셋(위에서 new_col이라는 series에 0을 할당)에 일괄적으로 적용이 된다.
또한 이미 존재하는 컬럼에도 비슷한 방식으로 데이터를 업데이트할 수도 있다.
df['New_col']=df['New_col']+100
df.head(3)
DataFrame 데이터 삭제(p.55)
위와 같은 방식을 이용하여 데이터프레임에 새로운 데이터를 추가할 수 있으며, 반대로 데이터를 삭제하기 위해서는 drop() 메서드를 이용한다.
drop()메서드에서는 다양한 인자를 이용할 수 있다.
DataFrame.drop(labels=None,axis=0,index=None,columns=None,level=None,inplace=False,errors='raise')
여기서 중요한 몇가지 인자는 labels, axiso, inplace인데, 하나씩 설명해보겠다.
우선 axis는 축을 의미하는데, 2차원의 ndarray, 데이터프레임은 2차원 데이터이기 때문에 axis 0과 axis 1이 존재한다.
2차원에서의 axis 0은 column(세로)축, axis 1은 row(가로)축을 의미한다.
drop메서드에 axis=0을 입력하면 row를 드랍하게되고, axis=1을 입력하면 column이 drop되게 된다.
다음으로, inplace의 같은경우 default값은 False이다. 이는 실제 데이터프레임을 수정할 것인가를 의미한다.
예를 들어 단순히 한 컬럼을 drop한 결과를 임시로 보고 싶으면 inplace=False로 하고 만약 실제로 앞으로는 drop한채로 쓰고 싶다하면 inplace=True로 하면된다.
# df에서 반영되지 않음
df.drop('New_col',axis=1)
# df에 반영됨
df=df.drop('New_col',axis=1)
# df에 반영됨
df.drop('New_col',axis=1,inplace=True)
# 오류
df=df.drop('New_col',axis=1,inplace=True)
index 객체(p.58)
Pandas의 index는 데이터프레임, 시리즈의 저장된 값을 유일하게 식별하는 객체이다.
이러한 인덱스는 .index 속성을 통해 볼 수 있다.
df.index
>> RangeIndex(start=0, stop=891, step=1)
print(df.index.values)
>> [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
... 882 883 884 885 886 887 888 889 890]
이러한 index객체도 1차원 ndarray로 이루어져 있어서 값 반환 및 슬라이싱도 가능하다.
그러나 데이터를 식별하는 고유값이기 때문에 함부로 변경할수 없다.
예를 들어 아래와 같은 코드는 에러가 난다.
df.index[5]=0
>> ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Untitled-1.ipynb Cell 19 line 1
----> 1 df.index[5]=0
File c:\Users\DESKTOP\miniconda3\envs\eda_project\lib\site-packages\pandas\core\indexes\base.py:5347, in Index.__setitem__(self, key, value)
5345 @final
5346 def __setitem__(self, key, value) -> None:
-> 5347 raise TypeError("Index does not support mutable operations")
TypeError: Index does not support mutable operations
그리고 reset_index()라는 메서드는 인덱스를 새롭게 연속된 숫자형으로 나열하며, 기존의 인덱스는 index라는 이름을 가진 column으로 이동하게 된다.
즉 이는 중간의 데이터를 삭제하여 인덱스가 불연속적 등이 되었을 때 사용하면 된다.
이 reset_index()안의 인자로 drop=True인자를 추가하면 기존의 index가 추가되지 않게 하는 방법도 있다.
이어지는 데이터프레임 관련 내용은 다음글에 이어서 작성해보도록 하겠습니다~
'ML & DL > 파이썬 머신러닝 완벽 가이드' 카테고리의 다른 글
파이썬 머신러닝 완벽 가이드 Day 3 (데이터 핸들링 판다스) (0) | 2023.11.16 |
---|---|
파이썬 머신러닝 완벽 가이드 Day 1 (넘파이) (0) | 2023.11.10 |