본문 바로가기
Machine Learning

판다스(Pandas)의 자료구조

by rubyda 2020. 4. 6.
728x90
파이썬 머신러닝 완벽 가이드: 다양한 캐글 예제와 함께 기초 알고리즘부터 최신 기법까지 배우는/권철민 지음을 참고하여 공부하고 정리하는 스터디 포스팅입니다.

 

pandas

판다스(Pandas)의 자료구조

판다스(Pandas)란?

  • 행과 열로 이루어진 2차원 데이터를 효율적으로 가공/처리할 수 있는 다양한 기능을 제공해 줍니다.
  • 넘파이보다 훨씬 유연하고 편리하게 데이터 핸들링을 가능하게 해줍니다.
  • 판다스는 csv등의 파일을 쉽게 DataFrame으로 변경해 데이터의 가공/분석을 편리하게 수행할 수 있게 만들어줍니다.

판다스의 자료구조에는 Series와 DataFrame이 있습니다. 지금부터 두 자료구조에 대해 알아보도록 하겠습니다.

1. 시리즈(Series)

1-1 시리즈(Series)란?

  • 컬럼이 하나뿐인 즉 1차원 배열과 같은 구조입니다. Series는 index를 Key 값으로 가지고 있습니다.

1-2 시리즈(Series) 나타내기

In [92]:
import numpy as np
import pandas as pd

Series 클래스를 사용하면 객체를 만들 수 있습니다. 결과값을 보면 Key값이 index로, value값이 값으로 표현되는 것을 알 수 있습니다.

In [93]:
ex_series=pd.Series([-1,2,5,8])
ex_series
Out[93]:
0   -1
1    2
2    5
3    8
dtype: int64

Series 객체는 index값을 따로 지정해주지 않으면 0부터 시작해서 인덱싱이 됩니다.

  • index를 지정해 주기
In [94]:
ex_series2=pd.Series([-1,2,5,8],index=['a','b','c','d'])
ex_series2
Out[94]:
a   -1
b    2
c    5
d    8
dtype: int64

위와 같이 index 값을 따로 지정해 줄 수도 있습니다.

1-3 시리즈(Series)값 확인하기

In [95]:
# 값 확인하기 #
ex_series.values
Out[95]:
array([-1,  2,  5,  8], dtype=int64)
In [96]:
# 인덱스 확인하기 #
ex_series.index
Out[96]:
RangeIndex(start=0, stop=4, step=1)

1-4 딕셔너리를 시리즈로 만들기

In [97]:
disc={'a':1,'b':2,'c':3,'d':4}
seri=pd.Series(disc)
seri
Out[97]:
a    1
b    2
c    3
d    4
dtype: int64

딕셔너리의 키값이 시리즈의 인덱스가 되는 것을 알 수 있습니다.

1-5 인덱싱

  • 시리즈에서 인덱싱은 위치와 인덱스명 두가지 방법이 존재합니다.
In [98]:
# 위치로 인덱싱하기
seri[0]
Out[98]:
1
In [99]:
# 인덱스명으로 인덱싱하기
seri['a']
Out[99]:
1
In [100]:
# 여러개 인덱싱하기
seri['a','b']
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in get_value(self, series, key)
   4380             try:
-> 4381                 return libindex.get_value_box(s, key)
   4382             except IndexError:

pandas/_libs/index.pyx in pandas._libs.index.get_value_box()

pandas/_libs/index.pyx in pandas._libs.index.get_value_at()

pandas/_libs/util.pxd in pandas._libs.util.get_value_at()

pandas/_libs/util.pxd in pandas._libs.util.validate_indexer()

TypeError: 'tuple' object cannot be interpreted as an integer

During handling of the above exception, another exception occurred:

KeyError                                  Traceback (most recent call last)
<ipython-input-100-9f041034a5fd> in <module>
      1 # 여러개 인덱싱하기
----> 2 seri['a','b']

~\Anaconda3\lib\site-packages\pandas\core\series.py in __getitem__(self, key)
    866         key = com.apply_if_callable(key, self)
    867         try:
--> 868             result = self.index.get_value(self, key)
    869 
    870             if not is_scalar(result):

~\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in get_value(self, series, key)
   4387                     raise InvalidIndexError(key)
   4388                 else:
-> 4389                     raise e1
   4390             except Exception:  # pragma: no cover
   4391                 raise e1

~\Anaconda3\lib\site-packages\pandas\core\indexes\base.py in get_value(self, series, key)
   4373         try:
   4374             return self._engine.get_value(s, k,
-> 4375                                           tz=getattr(series.dtype, 'tz', None))
   4376         except KeyError as e1:
   4377             if len(self) > 0 and (self.holds_integer() or self.is_boolean()):

pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_value()

pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_value()

pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()

pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()

pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()

KeyError: ('a', 'b')

주의! 여러개를 인덱싱할때는 괄호를 두개 씌워주어야 합니다.

In [101]:
# 여러개 인덱싱하기
seri[['a','b']]
Out[101]:
a    1
b    2
dtype: int64
  • 슬라이싱으로 인덱싱하기
In [102]:
seri[1:3]
Out[102]:
b    2
c    3
dtype: int64

슬라이싱을 사용해서도 인덱싱을 할 수 있습니다.

2. 데이터 프레임(DataFrame)

  • 2차원 데이터로 행과 열이 존재한다. 쉽게 말해 Series를 여러개 이어 붙인 것으로 표현할 수 있습니다.

2-1 데이터프레임(DataFrame)나타내기

In [103]:
data = {
    "국어": [90, 60, 75, 20,70],
    "영어": [80, 20, 95, 60,55],
    "수학": [30, 60, 90, 80,75],
}
columns = ["국어", "영어", "수학"]
index = ["민지", "종원", "시연", "춘석","윤주"]
df = pd.DataFrame(data, index=index, columns=columns)
In [104]:
df
Out[104]:
국어 영어 수학
민지 90 80 30
종원 60 20 60
시연 75 95 90
춘석 20 60 80
윤주 70 55 75

입력해준 값의 맞게 행과 열이 존재하는 데이터프레임이 만들어진 것을 확인할 수 있다.

2-2 데이터프레임(DataFrame)값 확인하기

In [105]:
# 값 확인하기 #
df.values
Out[105]:
array([[90, 80, 30],
       [60, 20, 60],
       [75, 95, 90],
       [20, 60, 80],
       [70, 55, 75]], dtype=int64)
In [106]:
# 컬럼 확인하기
df.columns
Out[106]:
Index(['국어', '영어', '수학'], dtype='object')
In [107]:
# 인덱스 확인하기
df.index
Out[107]:
Index(['민지', '종원', '시연', '춘석', '윤주'], dtype='object')

데이터프레임의 인덱싱과 또다른 특징들을 다른 포스팅을 통해서 따로 다루도록 하겠습니다.

2-3 파일을 DataFrame으로 불러오기

  • 판다스는 다양한 포맷으로 된 파일을 DataFrame으로 불러 올수 있는 편리한 API를 제공합니다. 대표적인 예시로는 read_csv(), read_tale(), read_fwf()가 있습니다.

    - read_csv(): csv(컬럼을 ','로 구반하는 파일 포맷)파일을 불러오는 API
    - read_table(): 구분자가 탭('\t')인 파일을 불러오는 API
    - read_fwf(): Fixed Width 즉 곶ㅇ 길이 기반의 컬럼 포맷을 로딩하기 위한 API

  • read_csv()는 csv뿐만이 아닌 어떤 필드 구분 문자 기반의 파일 포맷도 DateFrame으로 변환이 가능합니다. read_csv()의 인자인 sep에 해당 구분 문자를 입력하면 됩니다. 예를들어 탭으로 필드가 구분 돼어 있는 파일을 불러오고 싶으면 read_csv('파일명', sep='\t')와 같이 쓰면 됩니다.

예시에서는 read_csv()를 사용하여 데이터를 불러오도록 하겠습니다. 사용할 데이터는 캐글(Kaggle)에서 제공하는 타이타닉 탑승자 파일입니다. 데이터 파일은 https://www.kaggle.com/c/titanic 에서 다운받을 수 있습니다.

image.png

다운 받은 데이터 파일을 열어보면 맨 위에 줄에는 컬럼명이 있고 각각의 필드는 콤마로 분리되어 있음을 확인할 수 있습니다.
read_csv('filepath_or_buffer, sep=',' ',...)함수에서 가장 중요한 인자는 filepath입니다. filepath는 불러오는 데이터 파일의 경로를 포함한 파일명을 입력하면 됩니다.

In [108]:
import pandas as pd
titanic_df=pd.read_csv("./train.csv")
In [19]:
titanic_df.head(3)
Out[19]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S

일부 데이터만 확인해 보기 위해서 head()함수를 사용하여 맨 앞 3개의 로우를 확인해본 결과 데이터가 잘 불러온것을 확인해 볼 수 있습니다.

info(): 총 데이터 건수와 데이터 타입, NULL 건수를 알려주는 함수

In [21]:
titanic_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB

위 결과를 통해서 알수 있는 점을 정리하면 다음과 같습니다.

1) 전체 데이터는 891개의 row와 12개의 column을 가집니다.
2) 컬럼별 데이터 타입을 알수 있습니다. ex) Pclass의 데이터 타입은 int입니다.
3) 데이터의 non-null 개수를 알려줍니다. ex) Age의 경우 714가 Null이 아니라는 뜻입니다.
4) 전체 컬럼을 요약하자면 2개 컬럼이 float64, 5개의 컬럼이 int64, 5개의 컬럼이 object입니다.

describe(): 컬럼별 숫자형 데이터값의 n-percentile분포도, 평균값, 최댓값, 최솟값을 나타내주는 함수

In [22]:
titanic_df.describe()
Out[22]:
PassengerId Survived Pclass Age SibSp Parch Fare
count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200

위 결과를 통해서 알수 있는 점을 정리하면 다음과 같습니다.

1) count는 Not Null인 데이터 건수, mean은 전체 데이터의 평균값, std는 표준편차, min은 최솟값, max는 최댓값을 의미합니다.
2) 25%는 25 percentile값, 50%sms 50 percentile값, 75는 75 percentile값을 의미합니다.
3) Survived의 경우 min, max의 값이 0과1이고 25~75%의 값이 0인것을 보아 0과 1로 이루어진 숫자형 카테고리 컬럼임을 예상해 볼 수 있습니다. 마찬가지로 Pclass의 경우도 1,2,3으로 이루어진 숫자형 카테고리임을 예상해 볼 수 있습니다.

다음은 Pclass 컬럼의 값이 어떠한 분포로 이루어져 있는지 살펴보겠습니다.
value_counts(): 해당 컬럼값의 유형과 건수를 알려주는 함수

DataFrame의 [] 연산자 내부에 컬럼명을 입력하게 되면 Series 형태로 컬럼 데이터가 반환이 됩니다. value_counts()함수를 사용해서 확인을 해보겠습니다.

In [25]:
value_counts=titanic_df['Pclass'].value_counts()
print(value_counts)
3    491
1    216
2    184
Name: Pclass, dtype: int64

결과 3이 491개, 1이 216개, 2가 184개임을 알 수 있습니다.

데이터의 분포도를 아는 것은 머신러닝 알고리즘의 성능을 향상시키는데 중요한 요소입니다. 예를 들어 회귀에서 결정 값이 정규 분포를 이루지 않고 왜곡되어 있는 경우, 데이터 값에 이상치가 많은 경우 예측 성능이 떨어지게 됩니다. 그래서 이렇게 개략적으로 분포도를 확인할 수 있는 함수들을 알아두면 유용하게 사용할 수 있습니다.