
Pandas
대부분의 데이터는 시계열(series)이나 표(table)의 형태로 나타낼 수 있다. 판다스(Pandas) 패키지는 이러한 데이터를 다루기 위한 시리즈(Series) 클래스와 데이터프레임(DataFrame) 클래스를 제공한다.
시리즈 클래스
시리즈 Series 클래스는 넘파이에서 제공하는 1차원 배열과 비슷하지만 각 데이터의 의미를 표시하는 인덱스(index)를 붙일 수 있다. 데이터 자체는 값(value)라고 한다.
시리즈 생성
인덱스 라벨(index label)
데이터를 리스트나 1차원 배열 형식으로 Series 클래스 생성자에 넣어주면 시리즈 클래스 객체를 만들 수 있다. 이 때 인덱스의 길이는 데이터의 길이와 같아야 한다. 다음 예에서 이 “서울”, “부산” 등의 문자열이 인덱스의 값이다. 인덱스의 값을 인덱스 라벨(label)이라고도 한다. 인덱스 라벨은 문자열 뿐 아니라 날짜, 시간, 정수 등도 가능하다.
다음 예제는 각 도시의 2015년 인구 데이터를 시리즈로 만든 것이다.
s = pd.Series([9904312, 3448737, 2890451, 2466052], index=[“서울”, “부산”, “인천”, “대구”]) s
1 | |
만약 인덱스를 지정하지 않고 시리즈를 만들면 시리즈의 인덱스는 0부터 시작하는 정수값이 된다.
pd.Series(range(10, 14))
1
2
3
4
50 10 1 11 2 12 3 13 dtype: int64
시리즈의 인덱스는 index 속성으로 접근할 수 있다. 시리즈의 값은 1차원 배열이며 values 속성으로 접근할 수 있다.
s.index
1 | |
s.values
1 | |
name 속성을 이용하여 시리즈 데이터에 이름을 붙일 수 있다. index.name 속성으로 시리즈의 인덱스에도 이름을 붙일 수 있다.
s.name = “인구” s.index.name = “도시” s
1 | |
시리즈 연산
넘파이 배열처럼 시리즈도 벡터화 연산을 할 수 있다. 다만 연산은 시리즈의 값에만 적용되며 인덱스 값은 변하지 않는다. 예를 들어 인구 숫자를 백만 단위로 만들기 위해 시리즈 객체를 1,000,000 으로 나누어도 인덱스 라벨에는 영향을 미치지 않는 것을 볼 수 있다.
s / 1000000
1
2
3
4
5
6도시 서울 9.904312 부산 3.448737 인천 2.890451 대구 2.466052 Name: 인구, dtype: float64
시리즈 인덱싱
시리즈는 넘파이 배열에서 가능한 인덱스 방법 이외에도 인덱스 라벨을 이용한 인덱싱도 할 수 있다. 배열 인덱싱이나 인덱스 라벨을 이용한 슬라이싱(slicing)도 가능하다.
시리즈 데이터를 인덱싱하면 값이 나온다.
s[1], s[“부산”]
1 | |
s[3], s[“대구”]
1 | |
배열 인덱싱을 하면 부분적인 값을 가지는 시리즈 자료형을 반환한다. 자료의 순서를 바꾸거나 특정한 자료만 선택할 수 있다.
s[[0, 3, 1]]
1 |
|
s[[“서울”, “대구”, “부산”]]
1 |
|
s[1:3]
1 |
|
s[(250e4 < s) & (s < 500e4)] # 인구가 250만 초과, 500만 미만인 경우
1 |
|
만약 라벨 값이 영문 문자열인 경우에는 인덱스 라벨이 속성인것처럼 점(.)을 이용하여 해당 인덱스 값에 접근할 수도 있다.
s0 = pd.Series(range(3), index=[“a”, “b”, “c”]) s0
1
2
3
4a 0 b 1 c 2 dtype: int64
s0.a
1 | |
시리즈와 딕셔너리 자료형
시리즈 객체는 라벨 값에 의해 인덱싱이 가능하므로 실질적으로 인덱스 라벨 값을 키(key)로 가지는 딕셔너리 자료형과 같다고 볼 수 있다. 따라서 딕셔너리 자료형에서 제공하는 in 연산도 가능하고 items 메서드를 사용하면 for 루프를 통해 각 원소의 키(key)와 값(value)을 접근할 수도 있다.
“서울” in s # 인덱스 라벨 중에 서울이 있는가
1 | |
“대전” in s # 인덱스 라벨 중에 대전이 있는가
1 | |
1 | |
딕셔너리의 원소는 순서를 가지지 않으므로 시리즈의 데이터도 순서가 보장되지 않는다. 만약 순서를 정하고 싶다면 인덱스를 리스트로 지정해야 한다.
1 | |
1 | |
인덱스 기반 연산
이번에는 2015년도와 2010년의 인구 증가를 계산해 보자. 두 개의 시리즈의 차이를 구하면 된다. 두 시리즈에 대해 연산을 하는 경우 인덱스가 같은 데이터에 대해서만 차이를 구한다.
ds = s - s2 ds
1 | |
대구와 대전의 경우에는 2010년 자료와 2015년 자료가 모두 존재하지 않기 때문에 계산이 불가능하므로 NaN(Not a Number)이라는 값을 가지게 된다. 또한 NaN 값이 float 자료형에서만 가능하므로 다른 계산 결과도 모두 float 자료형이 되었다는 점에 주의한다. NaN이 아닌 값을 구하려면 notnull 메서드를 사용한다.
ds.notnull()
1
2
3
4
5
6대구 False 대전 False 부산 True 서울 True 인천 True dtype: boolds[ds.notnull()]
1
2
3
4부산 55546.0 서울 272830.0 인천 258416.0 dtype: float64
마찬가지로 인구 증가율(%)은 다음과 같이 구할 수 있다.
rs = (s - s2) / s2 * 100 rs = rs[rs.notnull()] rs
1
2
3
4부산 1.636984 서울 2.832690 인천 9.818107 dtype: float64
데이터의 갱신, 추가, 삭제
인덱싱을 이용하면 딕셔너리처럼 데이터를 갱신(update)하거나 추가(add)할 수 있다.
rs[“부산”] = 1.63 rs
1
2
3
4부산 1.630000 서울 2.832690 인천 9.818107 dtype: float64
rs[“대구”] = 1.41 rs
1
2
3
4
5부산 1.630000 서울 2.832690 인천 9.818107 대구 1.410000 dtype: float64데이터를 삭제할 때도 딕셔너리처럼 del 명령을 사용한다.
del rs[“서울”] rs
1
2
3
4부산 1.630000 인천 9.818107 대구 1.410000 dtype: float64
데이터프레임 클래스
- 행 인덱스(row index, index)
- 열 인덱스(cplumn index, columns)
시리즈가 1차원 벡터 데이터에 행방향 인덱스(row index)를 붙인 것이라면 데이터프레임 DataFrame 클래스는 2차원 행렬 데이터에 인덱스를 붙인 것과 비슷하다. 2차원이므로 각각의 행 데이터의 이름이 되는 행 인덱스(row index) 뿐 아니라 각각의 열 데이터의 이름이 되는 열 인덱스(column index)도 붙일 수 있다.
데이터프레임 생성
-
데이터프레임을 만드는 방법은 다양하다. 가장 간단한 방법은 다음과 같다.
-
우선 하나의 열이 되는 데이터를 리스트나 일차원 배열을 준비한다.
-
이 각각의 열에 대한 이름(라벨)을 키로 가지는 딕셔너리를 만든다.
이 데이터를 DataFrame 클래스 생성자에 넣는다. 동시에 열방향 인덱스는 columns 인수로, 행방향 인덱스는 index 인수로 지정한다.
1 | |
1 | |
앞에서 데이터프레임은 2차원 배열 데이터를 기반으로 한다고 했지만 사실은 공통 인덱스를 가지는 열 시리즈(column series)를 딕셔너리로 묶어놓은 것이라고 보는 것이 더 정확하다. 2차원 배열 데이터는 모든 원소가 같은 자료형을 가져야 하지만 데이터프레임은 각 열(column)마다 자료형이 다를 수 있기 때문이다. 위 예제에서도 지역과 인구와 증가율은 각각 문자열, 정수, 부동소수점 실수이다.
시리즈와 마찬가지로 데이터만 접근하려면 values 속성을 사용한다. 열방향 인덱스와 행방향 인덱스는 각각 columns, index 속성으로 접근한다.
1 | |
열 데이터의 갱신, 추가, 삭제
데이터프레임은 열 시리즈의 딕셔너리으로 볼 수 있으므로 열 단위로 데이터를 갱신하거나 추가, 삭제할 수 있다.
1 | |
1 | |
1 | |
1 | |
1 | |
1 | |
열 인덱싱
데이터프레임은 열 라벨을 키로, 열 시리즈를 값으로 가지는 딕셔너리와 비슷하다고 하였다. 따라서 데이터프레임을 인덱싱을 할 때도 열 라벨(column label)을 키값으로 생각하여 인덱싱을 할 수 있다. 인덱스로 라벨 값을 하나만 넣으면 시리즈 객체가 반환되고 라벨의 배열 또는 리스트를 넣으면 부분적인 데이터프레임이 반환된다.
하나의 열만 인덱싱하면 시리즈가 반환된다.
1 | |
1 | |
데이터프레임의 열 인덱스가 문자열 라벨을 가지고 있는 경우에는 순서를 나타내는 정수 인덱스를 열 인덱싱에 사용할 수 없다. 정수 인덱싱의 슬라이스는 뒤에서 설명하겠지만 행(row)을 인덱싱할 때 사용하므로 열을 인덱싱할 때는 쓸 수 없다. 정수 인덱스를 넣으면 KeyError 오류가 발생하는 것을 볼 수 있다.
1 | |
다만 원래부터 문자열이 아닌 정수형 열 인덱스를 가지는 경우에는 인덱스 값으로 정수를 사용할 수 있다.
1 | |
1 | |
1 | |
1 | |
행 인덱싱
1 | |
1 | |
1 | |
개별 데이터 인덱싱
데이터프레임에서 열 라벨로 시리즈를 인덱싱하면 시리즈가 된다. 이 시리즈를 다시 행 라벨로 인덱싱하면 개별 데이터가 나온다.
1 | |
| 인덱싱 값 | 가능 | 결과 | 자료형 | 추가사항 |
|---|---|---|---|---|
| 라벨 | O | 열 | 시리즈 | |
| 라벨 리스트 | O | 열 | 데이터프레임 | |
| 인덱스데이터(정수) | X | 열 라벨이 정수인 경우에는 라벨 인덱싱으로 인정 | ||
| 인덱스데이터(정수) 슬라이스 | O | 행 | 데이터프레임 |
예제
1 | |
(1) 모든 학생의 수학 점수를 시리즈로 나타낸다.
1 | |
1 | |
(2) 모든 학생의 국어와 영어 점수를 데이터 프레임으로 나타낸다.
1 | |
1 | |
(3) 모든 학생의 각 과목 평균 점수를 새로운 열로 추가한다.
1 | |
1 | |
(4) 방자의 영어 점수를 80점으로 수정하고 평균 점수도 다시 계산한다.
1 | |
1 | |
(5) 춘향의 점수를 데이터프레임으로 나타낸다.
1 | |
1 | |
(6) 향단의 점수를 시리즈로 나타낸다.
1 | |
1 | |
1 | |
1 | |
출처 : 데이터사이언스 스쿨