Wireframe

Pandas 기초 사용법 – Series

파이썬에서 통계 및 데이터 분석을 위해 사용하는 대표적인 패키지로 pandas를 꼽을 수 있다. 사실 pandas말고 다른 통계용 패키지는 뭐가 있나 잘 모르겠… 통계 분석을 위해서 pandas를 사용하기 위해 파이썬을 배우는 입장이 아니라면 기존의 파이썬 자료 구조와는 사용법이 살짝 다르기 때문에 약간 위화감이 들 수 있다. 이 글에서는 기존 파이썬 자료 구조에 익숙한 사용자가 pandas를 익히기 위해 필요한 내용과 그 사용법을 정리하고자 한다.

Pandas에서는 Series와 DataFrame이라는 두 가지 형식의 데이터 타입이 존재한다. Series는 특정한 기준에 따른 계열 데이터로 파이썬의 리스트와 비슷하다. DataFrame은 Series를 합친 형태로 2차원의 표 형식의 데이터를 다룰 때 사용한다.

Series

Series는 배열과 유사한 1차원 데이터를 위한 자료 구조이다. 파이썬의 리스트와 여러 모로 유사하다고 생각할 수 있지만 몇 가지 차이점이 존재한다. 파이썬 리스트가 그 원소의 타입에 제한을 두지 않는 것과 달리, pd.Series는 단일한 타입의 연속적인 데이터를 사용한다. 또 파이썬 리스트는 0부터 시작하는 정수 인덱스를 사용하여 원소를 참조하지만, pd.Series는 기본적으로 0부터 시작하는 정수 인덱스를 사용할 수 있는 것 외에 datetime 같은 별도의 인덱스를 사용할 수 있다. (이때, datetime은 numpy 에서 정의된 np.datetime64 타입의 값이다.)

또 파이썬 리스트가 xs[i], xs[i:j] 와 같은 subscription 방식을 사용하는 것과 달리, pandas의 데이터 타입들은 인덱서라는 슬라이스를 확장한 문법을 사용하여 특정 값 및 부분 집합을 액세스한다. 인덱서의 사용 방법에 대해서는 뒤에서 다시 자세히 다뤄보도록 하겠다.

https://pandas.pydata.org/docs/reference/api/pandas.Series.html

Series 생성

Series 타입은 pd.Series 로 정의되어 있다. 클래스 생성자의 모양은 아래와 같이 생겼다.

class pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)
> pd.Series([1,2,3, 4])
> pd.Series([1,2,3,4], index=list('ABCD')

파이썬의 정수 리스트를 데이터로 주면 이는 int64 타입으로 변환되어 저장된다. index= 옵션을 주면 해당 리스트/배열을 인덱스로 사용할 수 있다. pd.date_range()를 사용하면 시계열 인덱스를 생성할 수 있어서 다음과 같은 식으로 시계열 난수 데이터를 생성해볼 수 있다.

> pd.Series(np.random.randn(100),
            index=pd.date_range('2020-01-01 00:00:00', freq='1S', periods=100))

원소 액세스

Series 내의 특정 원소나 부분집합을 참조하는 방식은 파이썬 리스트와 비슷하다. 기본적으로 sr[0] 과 같이 정수 인덱스를 사용해서 특정한 원소를 액세스하거나, sr[2:8] 과 같이 슬라이스를 사용해서 부분열을 만드는 것이 가능하다. 만약 Series를 생성할 때, 인덱스를 별도로 정의해서 생성했다면 sr['a'] 와 같이 특정 값에 대한 인덱스를 사용해서 액세스하게 된다. (이렇게 별도의 인덱스를 지정했더라도, 인덱스가 정수가 아니라면 sr[0] 과 같이 정수 인덱스로도 여전히 액세스 가능하다.)

pandas의 데이터들은 여기에 추가로 .loc,.at 이라는 두 개의 인덱서를 지원한다. 이들은 미리 약속된 인덱스를 받아서 그에 해당하는 원소 혹은 부분열을 액세스할 수 있도록 해준다. .at 의 경우 단일 원소값을 참조하는데 사용하며, .loc[index] 은 단일 원소 및 부분열을 액세스할 수 있다. 이 인덱서들은 2차원 데이터인 데이터프레임에서도 같은 방식으로 사용할 수 있다. 참고로 .loc, .at 이 레이블(인덱스)를 사용하는데 비해 파이썬 내장 타입처럼 정수를 사용하여 위치를 기준으로 액세스하는데에는 앞에 i 를 붙인 .iloc, .iat 을 사용할 수 있다.

먼저 i가 붙는 인덱서를 사용하는 방법이다.

s.loc[]s.iloc[] 과 유사하지만 순번이 아닌 인덱스/레이블에만 의존하여 값을 찾는다. 문자나 다른 타입의 값으로 인덱를 지정했다면 s.loc[9]s.at[0] 은 에러를 일으킨다. 사용법은 거의 같다.

# 난수를 사용하여 Series 생성하고 알파벳으로 인덱스를 부여함
xr = pd.Series(np.random.randn(12), index=list('abcdefghijkl'))

# 리스트처럼 액세스하기
xr[0]
xr[1:3]

xr['a']
# 인덱스가 정수가 아닌 경우에는 인덱스를 속성처럼 사용할 수 있다.
xr.a
# 인덱스가 문자이지만, 연속되는 경우에는 슬라이스 문법을 사용할 수 있다.
# 이 경우에는 end 위치의 값도 포함된다.
xr['a':'d'] 

# .loc[] 로케이터를 사용하기
xr.loc['a']
xr.loc['a':'d']
xr.loc[['a','e','i']]
xr.loc[xr >= 0]

연결, 합치기

2개 이상의 계열 객체는 하나의 계열로 합치는 것이 가능하다. 여기서 합친다는 말의 의미는 ‘연결한다’라고 볼 수 있다. 예를 들어 길이가 각각 10인 두 개의 계열을 합치면 길이가 20인 계열을 하나 만들거나, 혹은 2 * 10 짜리 테이블(데이터프레임)을 만들 수 있다. 이 두 경우는 연결하는 방향에 따라 결정된다.

데이터프레임과 달리 계열 객체에는 join(), merge(), concat() 과 같이 연결을 의미하는 이름의 메소드가 없다. 따라서 pd.concat() 이라는 함수를 사용하여 두 개의 계열을 연결할 수 있다. axis= 파라미터는 연결할 방향을 결정한다. 0이면 종방향(길이방향), 1이면 횡방향이다.

두 개의 계열을 길이 방향으로 연결했을 때, 인덱스가 같은 항목이 여러 개 있더라도 상관없이 연결된다. 심지어 인덱스가 정수값이라 하더라도 재정렬은 일어나지 않는다. 인덱스 구성이 다른 두 계열을 횡방향으로 연결한 경우에는 새로운 데이터프레임이 생성되며, 이 때 인덱스를 별도로 명시적으로 지정하지 않았다면 정수 인덱스가 새롭게 매겨진다. (만약 인덱스 구성이 일치한다면 원래의 인덱스가 유지된다.)

인덱스가 중복된 원소들이 존재한다면 .loc[] 인덱서를 사용하여 특정한 인덱스에 대한 값을 참조하면 2개 이상의 값이 있을 때에는 계열 데이터가 리턴된다.

그룹바이

인덱스가 중복된 원소들이 존재할 때, 인덱스가 같은 값끼리 묶어서, 묶은 그룹에 대한 연산 결과를 알아 볼 수 있다. s.groupby()가 그 방법인데, 호출하는 방법은 두 가지이다.

.groupby() 메소드는 by=level= 인자를 반드시 전달해야 한다. by= 인자에는 일반적으로 함수를 줄 수 있는데, 그룹핑을 할 키를 생성하는 함수이다. level= 은 레벨값이나 레벨 이름을 주는데, 계열 객체는 항상 1차원 데이터이므로 level=0 으로 전달하면 된다.

s = pd.Series(np.random.randn(10))
t = pd.Series(np.arange(10), index=(x*2+3 for x in range(10)))
w = pd.concat([s, t], axis=0)
w.groupby(level=0).sum()  # 같은 인덱스값들의 합

그룹바이의 결과는 GroupBy 객체를 생성하며, 그룹바이 객체는 REPL 상에서 출력했을 때 그 내용을 보여주지 않는다. 그래서 .sum(), .mean() 등의 집합 함수 메소드를 사용하여 그룹별 데이터의 모양을 얻어서 사용한다.

간단한 통계 기능

pandas는 numpy와 긴밀하게 연동되어 있어서 numpy의 기능을 잘 활용하고 있다. (실제로 내부에 저장되는 데이터는 numpy 타입의 배열로 데이터를 저장한다.) 따라서 Series는 numpy 배열의 계산 동작과 비슷한 기능(벡터화 같은) 기능을 제공하며, 여기에 더해 간단한 통계도 즉시 계산할 수 있게 해준다.

통계와 관련하여 numpy 와 차이가 있는데, 분산 및 표준편차에 대해 numpy 배열은 디폴트로 모분산, 모표준편차를 계산하는데, pandas Series와 DataFrame은 통계적 추정등에 사용되는 경우가 더 많다보니, 표본분산, 표본표준편차를 계산해준다.

그래프 기능

pandas는 제공하는 데이터 타입의 하부구조의 상당부분을 numpy의 의존하고 있기에 pandas를 설치하기 위해서는 시스템에 numpy가 먼저 설치되는 것을 필요로 한다. pandas에는 필수적인 의존성은 아니지만, 시스템에 함께 설치되어 있다면 활용할 수 있는 기능들도 제공하고 있다. 파이썬에서 그래프를 그리는데 사용하는 대표적인 시각화 라이브러리인 matplotlib 이 있다면, 데이터 프레임이나 시리즈의 값을 사용해서 간단한 차트를 그려볼 수 있다. s.plot() 를 호출해주면 matplotlib의 현재 컨텍스트(pyplot)에 플롯 차트가 그려지므로, plt.show() 함수를 사용해서 그려진 그래프를 표시해서 볼 수 있다.

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
sr = pd.Series(np.random.randn(100),
        index=pd.date_range('2020-08-01', freq='D', periods=100))
plt.figure()
sr.plot()
plt.show()

정리

원래는 데이터프레임까지 다뤄보려고 했는데, 분량 조절에 실패해서 데이터프레임은 다음 기회를 기약하도록 하겠다.

Exit mobile version