작성자: admin 작성일시: 2016-07-11 22:30:14 조회수: 4116 다운로드: 185
카테고리: Python 태그목록: Python

데이터프레임의 데이터 조작

Pandas는 NumPy의 2차원 배열에서 가능한 대부분의 데이터 처리가 가능하며 추가로 데이터 처리 및 변환을 위한 다양한 함수와 메서드를 제공한다. 여기에서는 그 중 몇가지를 예로 보인다. 전체 기능은 다음 웹사이트를 참조한다

데이터 갯수 세기

가장 간단한 데이터 분석은 데이터의 갯수를 세는 것이다. count 메서드를 사용한다. NaN 값은 세지 않는다.

In:
s = pd.Series(range(10))
s[3] = np.nan
s
Out:
0    0.0
1    1.0
2    2.0
3    NaN
4    4.0
5    5.0
6    6.0
7    7.0
8    8.0
9    9.0
dtype: float64
In:
s.count()
Out:
9

데이터프레임에서는 각 열마다 별도로 데이터 갯수를 센다. 데이터에서 값이 누락된 부분을 찾을 때 유용하다.

In:
np.random.seed(2)
df = pd.DataFrame(np.random.randint(5, size=(4, 4)), dtype=float)
df.iloc[2,3] = np.nan
df
Out:
0 1 2 3
0 0.0 0.0 3.0 2.0
1 3.0 0.0 2.0 1.0
2 3.0 2.0 4.0 NaN
3 4.0 3.0 4.0 2.0
In:
df.count()
Out:
0    4
1    4
2    4
3    3
dtype: int64

연습 문제 1

다음 명령으로 타이타닉호 승객 데이터를 데이터프레임으로 읽어온다. 이 명령을 실행하려면 seaborn 패키지가 설치되어 있어야 한다.

import seaborn as sns
titanic = sns.load_dataset("titanic")

타이타닉호 승객 데이터의 데이터 값을 각 열마다 구해본다.

카테고리 값 세기

시리즈의 값이 정수, 문자열, 카테고리 값인 경우에는 value_counts 메서드로 각각의 값이 나온 횟수를 셀 수 있다.

In:
np.random.seed(1)
s2 = pd.Series(np.random.randint(6, size=100))
s2.tail()
Out:
95    4
96    5
97    2
98    4
99    3
dtype: int64
In:
s2.value_counts()
Out:
1    22
0    18
4    17
5    16
3    14
2    13
dtype: int64

데이터프레임에는 value_counts 메서드가 없으므로 각 열마다 별도로 적용해야 한다.

In:
df[0].value_counts()
Out:
3.0    2
4.0    1
0.0    1
Name: 0, dtype: int64

정렬

데이터를 정렬하려면 sort_indexsort_values 메서드를 사용한다. sort_index는 인덱스 값을 기준으로, sort_values는 데이터 값을 기준으로 정렬한다.

앞에서 s2 시리즈의 각 데이터 값에 따른 데이터 갯수를 보기좋게 정렬하려면 다음처럼 sort_index를 적용한다.

In:
s2.value_counts().sort_index()
Out:
0    18
1    22
2    13
3    14
4    17
5    16
dtype: int64

NaN값이 있는 경우에는 정렬하면 NaN값이 가장 나중으로 간다.

In:
s.sort_values()
Out:
0    0.0
1    1.0
2    2.0
4    4.0
5    5.0
6    6.0
7    7.0
8    8.0
9    9.0
3    NaN
dtype: float64

큰 수에서 작은 수로 반대 방향 정렬하려면 ascending=False 인수를 지정한다.

In:
s.sort_values(ascending=False)
Out:
9    9.0
8    8.0
7    7.0
6    6.0
5    5.0
4    4.0
2    2.0
1    1.0
0    0.0
3    NaN
dtype: float64

데이터프레임에서 sort_values 메서드를 사용하려면 by 인수로 정렬 기준이 되는 열을 지정해 주어야 한다.

In:
df.sort_values(by=1)
Out:
0 1 2 3
0 0.0 0.0 3.0 2.0
1 3.0 0.0 2.0 1.0
2 3.0 2.0 4.0 NaN
3 4.0 3.0 4.0 2.0

by 인수에 리스트 값을 넣으면 이 순서대로 정렬 기준의 우선 순위가 된다. 즉, 리스트의 첫번째 열을 기준으로 정렬한 후 동일한 값이 나오면 그 다음 열로 순서를 따지게 된다.

In:
df.sort_values(by=[1, 2])
Out:
0 1 2 3
1 3.0 0.0 2.0 1.0
0 0.0 0.0 3.0 2.0
2 3.0 2.0 4.0 NaN
3 4.0 3.0 4.0 2.0

연습 문제 2

타이타닉호 승객중 성별(sex) 인원수, 나이별(age) 인원수, 선실별(class) 인원수, 사망/생존(alive) 인원수를 구하라.

행/열 합계

행과 열의 합계를 구할 때는 sum(axis) 메서드를 사용한다.

In:
np.random.seed(1)
df2 = pd.DataFrame(np.random.randint(10, size=(4, 8)))
df2
Out:
0 1 2 3 4 5 6 7
0 5 8 9 5 0 0 1 7
1 6 9 2 4 5 2 4 2
2 4 7 7 9 1 7 0 6
3 9 9 7 6 9 1 0 1

행 합계를 구할 때는 sum(axis=1) 메서드를 사용한다.

In:
df2.sum(axis=1)
Out:
0    35
1    34
2    41
3    42
dtype: int64
In:
df2["RowSum"] = df2.sum(axis=1)
df2
Out:
0 1 2 3 4 5 6 7 RowSum
0 5 8 9 5 0 0 1 7 35
1 6 9 2 4 5 2 4 2 34
2 4 7 7 9 1 7 0 6 41
3 9 9 7 6 9 1 0 1 42

열 합계를 구할 때는 sum(axis=0) 메서드를 사용하는데 axis인수의 디폴트 값이 0이므로 axis인수를 생략할 수 있다.

In:
df2.sum()
Out:
0          24
1          33
2          25
3          24
4          15
5          10
6           5
7          16
RowSum    152
dtype: int64
In:
df2.loc["ColTotal", :] = df2.sum()
df2
Out:
0 1 2 3 4 5 6 7 RowSum
0 5.0 8.0 9.0 5.0 0.0 0.0 1.0 7.0 35.0
1 6.0 9.0 2.0 4.0 5.0 2.0 4.0 2.0 34.0
2 4.0 7.0 7.0 9.0 1.0 7.0 0.0 6.0 41.0
3 9.0 9.0 7.0 6.0 9.0 1.0 0.0 1.0 42.0
ColTotal 24.0 33.0 25.0 24.0 15.0 10.0 5.0 16.0 152.0

apply 변환

행이나 열 단위로 더 복잡한 처리를 하고 싶을 때는 apply 메서드를 사용한다. 인수로 행 또는 열을 받는 함수를 apply 메서드의 인수로 넣으면 각 열(또는 행)을 반복하여 그 함수에 적용시킨다.

In:
df3 = pd.DataFrame({
        'A': [1, 3, 4, 3, 4],
        'B': [2, 3, 1, 2, 3],
        'C': [1, 5, 2, 4, 4]
    })
df3
Out:
A B C
0 1 2 1
1 3 3 5
2 4 1 2
3 3 2 4
4 4 3 4

예를 들어 각 열의 최대값과 최소값의 차이를 구하고 싶으면 다음과 같은 람다 함수를 넣는다.

In:
df3.apply(lambda x: x.max() - x.min())
Out:
A    3
B    2
C    4
dtype: int64

만약 행에 대해 적용하고 싶으면 axis=1 인수를 쓴다.

In:
df3.apply(lambda x: x.max() - x.min(), axis=1)
Out:
0    1
1    2
2    3
3    2
4    1
dtype: int64

각 열에 대해 어떤 값이 얼마나 사용되었는지 알고 싶다면 value_counts 함수를 넣을 수도 있다.

In:
df3.apply(pd.value_counts)
Out:
A B C
1 1.0 1.0 1.0
2 NaN 2.0 1.0
3 2.0 2.0 NaN
4 2.0 NaN 2.0
5 NaN NaN 1.0

NaN 값은 fillna 메서드를 사용하여 원하는 값으로 바꿀 수 있다. astype 메서드로 전체 데이터의 자료형을 바꾸는 것도 가능하다.

In:
df3.apply(pd.value_counts).fillna(0).astype(int)
Out:
A B C
1 1 1 1
2 0 2 1
3 2 2 0
4 2 0 2
5 0 0 1

실수 값을 카테고리 값으로 변환

실수 값을 크기 기준으로 하여 카테고리 값으로 변환하고 싶을 때는 다음과 같은 명령을 사용한다.

  • cut: 실수 값의 경계선을 지정하는 경우
  • qcut: 갯수가 똑같은 구간으로 나누는 경우

예를 들어 다음과 같은 나이 데이터가 있다고 하자.

In:
ages = [0, 2, 10, 21, 23, 37, 31, 61, 20, 41, 32, 100]

cut 명령을 사용하면 실수값을 다음처럼 카테고리 값으로 바꿀 수 있다. bins 인수는 카테고리를 나누는 기준값이 된다. 영역을 넘는 값은 NaN으로 처리된다.

In:
bins = [1, 15, 25, 35, 60, 99]
labels = ["미성년자", "청년", "중년", "장년", "노년"]
cats = pd.cut(ages, bins, labels=labels)
cats
Out:
[NaN, 미성년자, 미성년자, 청년, 청년, ..., 노년, 청년, 장년, 중년, NaN]
Length: 12
Categories (5, object): [미성년자 < 청년 < 중년 < 장년 < 노년]

cut 명령이 반환하는 값은 Categorical 클래스 객체이다. 이 객체는 categories 속성으로 라벨 문자열을, codes 속성으로 정수로 인코딩한 카테고리 값을 가진다.

In:
type(cats)
Out:
pandas.core.categorical.Categorical
In:
cats.categories
Out:
Index(['미성년자', '청년', '중년', '장년', '노년'], dtype='object')
In:
cats.codes
Out:
array([-1,  0,  0,  1,  1,  3,  2,  4,  1,  3,  2, -1], dtype=int8)
In:
df4 = pd.DataFrame(ages, columns=["ages"])
df4["age_cat"] = pd.cut(df4.ages, bins, labels=labels)
df4
Out:
ages age_cat
0 0 NaN
1 2 미성년자
2 10 미성년자
3 21 청년
4 23 청년
5 37 장년
6 31 중년
7 61 노년
8 20 청년
9 41 장년
10 32 중년
11 100 NaN

qcut 명령은 구간 경계선을 지정하지 않고 데이터 갯수가 같도록 지정한 수의 구간으로 나눈다. 예를 들어 다음 코드는 1000개의 데이터를 4개의 구간으로 나누는데 각 구간은 250개씩의 데이터를 가진다.

In:
data = np.random.randn(1000)
cats = pd.qcut(data, 4, labels=["Q1", "Q2", "Q3", "Q4"])
cats
Out:
[Q2, Q1, Q2, Q3, Q1, ..., Q1, Q1, Q4, Q4, Q2]
Length: 1000
Categories (4, object): [Q1 < Q2 < Q3 < Q4]
In:
pd.value_counts(cats)
Out:
Q4    250
Q3    250
Q2    250
Q1    250
dtype: int64

연습 문제 3

타이타닉호 승객을 사망자와 생존자 그룹으로 나누고 각 그룹에 대해 '미성년자', '청년', '중년', '장년', '노년' 승객의 비율을 구한다. 각 그룹 별로 비율의 전체 합은 1이 되어야 한다.

질문/덧글

아직 질문이나 덧글이 없습니다. 첫번째 글을 남겨주세요!