Series를 데이터 그룹화(groupby)하기

df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
                    'key2' : ['one', 'two', 'one', 'two', 'one'],
                    'data1': np.random.randn(5),
                    'data2': np.random.randn(5)})
image
위 DataFrame에 key1과 key2에는 중복된 값이 있는 것을 확인할 수 있다.

이 때, key1열이 a인 행들에 대해, data1의 평균을 구하고 싶다고 가정하자.
(이전까지는 key1의 유니크한 값으로 마스크 –> 반복문 (df.loc( 마스크, data1열)) 을 통해 평균을 계산했었다. 하지만, 데이터 그룹화를 통해 더 쉽게 할 수 있다)

데이터 그룹화를 하기 위해서는, Series나 DataFramegroupby()함수를 실행할 수 있다.

  • 통계량을 계산할 열(Series) . groupby(  기준이 될 열(Series)  ) 형식으로 실행하게 되는데,
    grouped = df["data1"].groupby( df["key1"])를 통해
    key1열을 데이터그룹화를 한 다음,  data1열의 통계량을 계산할 준비를 한다.
    image
    값을 확인할 수 없는 이유는 , key1열을 기준으로 data1열을 그룹화만 했을 뿐이며, 통계함수는 사용하지 않았기 때문이다.
    grouped에는 ket1의 값인 a를 포함하는 행과 b를 포함하는 행을 각각 그룹화하여  동시에  가지고 있다.
  • 이렇게 그룹화까지만 된 것인 grouped 를 이용해서, 통계함수로 통계량을 계산한다.
    grouped.mean()
    image

이러한 groupby()함수의 절차를 [  splitapplycombine ] 이라고 한다.
기준열을 지정하여 특정열을 그룹별로 나누고 – 각 그룹에 통계함수를 적용하고 – 최종적인 통계량이 산출된 것은 통합해서 표시해주기 때문이다.
(my :  groupby로 데이터를 그룹화 했으면, 반드시 통계함수를 적용시켜야하는구나. 통계량 구할라고 하는 거구나!)


이제 그룹화의 기준이 될 열을 2개 이상 지정할 수도 있다. 2개 열의 성분이 모두 같은 것만 하나의 그룹이 된다.
이 때, 그룹화의 기준열이 2개이면, 계층적 인덱스로 적용된 Series가 나온다.

  • means = df["data1"].groupby( [ df["key1"], df["key2"]]).mean() 를 통해, 기준열2개로 data1열을 그룹화 후 평균까지 구하자.
    image
    나온 결과에서, 기준열이 2개면, 계층적 인덱스가 적용된 Series가 나온다.
    이 때,  unstactk()함수를 적용해서 최하위 인덱스를 칼럼으로 올린 뒤, 데이터를 분석해도 된다.
    image

DataFrame을 데이터그룹화(groupby)하기

지금까지는 데이터 그룹화(groupby)를 적용시키는 것에  특정열 1개를 Series로 주었는데,
DataFrame에 대해서도 groupby()를 적용시킬 수 있다.
Series에서 했던 것과는 방식이 조금 달라진다.
- Series 의 데이터 그룹화 :  특정열인덱싱.groupby ( 기준열인덱싱
- DataFrame의 데이터 그룹화 :  df . groupby ( “기준이 될 컬럼명”) 를 통해 특정열이 아닌, df의 모든 열에 대해서 통계량이 계산된다.

  • df.groupby("key1").mean() 를 적용시켜보자.
    image
  • df.groupby("key1").count() 를 통해, 각 key1열의 값을 가지는 행들의 갯수를 세서 산출해줄 수 있다.
    image
  • 2개의 열을 기준으로 할 수도 있다. 마찬가지로 인자에, 리스트형식으로 칼럼명을 넣어준다.
    image


DataFrame을 데이터 그룹화 해서, 특정열x 전체 열을 그룹화 하더라도,  특정열에 대한 통계량만 산출할 수 도 있다.
그룹화결과물에, 통계함수를 적용하기 에 [ “컬럼명”]으로 뽑아내면된다.

  • df.groupby( ["key1","key2"])["data2"].mean()
    image



반복문을 이용하여, 그룹화 직후의 결과물 확인해보기(통계함수 적용하기전에)

그룹화를 수행한 직후의 결과물을 확인할 수 없었으나, 반복문을 통해 그룹화에 대한 결과물 확인이 가능하다.

key1 이라는 열에 대해, name, group이라 2변수로 매 반복문마다 값을 받아서, 각각의 print해보자.

  • for name, group in df.groupby("key1") :
         print(name)
         print(group)
    key1이라는 열의 각 성분 별로 그룹화를 시켰는데,
    name이라는 변수에는 각 그룹으로 나뉘는 기준열의 성분이 들어가서 출력되며, group에서는 기준성분을 포함하는 행들을, 모든 열별로 출력이 된다.
    image

만약 기준열이 2개라면, name변수 자리에 소괄호()를 이용해서 2개의 변수에 각 기준열의 성분을 받아야한다.

  • for (k1, k2), group in df.groupby( ["key1", "key2"]) :
         print(k1, k2)
         print(group)
    image



딕셔너리를 이용해서 그룹화 직후의 결과물 보기

df.groupby( “key1”)의 결과물은 2개의 변수로 받을 수 있었다.

이것을 list()함수를 씌워서, 순서대로 짤라서 넣게 되고, dict()함수를 이용해서 딕셔너리 형태로 담는다.
이 때,  그룹화된 결과물에 list()함수를 입히면, list의 형태가  [ ( 성분1, group1) , (성분2, group2) , … ]형태로 담길 것이다.
이것을 dict()함수를 이용하면 { 성분1 : group1,  성분2 : group2 }의 딕셔너리 형태로 넣을 수 있는 것이다.
(my : 아! name , group을 한번에 딕셔너리에 담을 수 없어서  그룹화결과물 –> list로 쪼개어 담기 – >dictionary에 한꺼번에 담아주기 )

  • pieces = dict ( list( df.groupby("key1") ) ) 를 통해, 그룹화결과물딕셔너리의 형태로 살펴보자.
    { a라는 키값 : 그룹화된 결과물  } 형태로  나타난다.
    image
  • 이것을 딕셔너리 열인덱싱(키 인덱싱) 하여 b에 대한 그룹화 결과물만 볼 수 있다.
    pieces["b"]
    image



기준열 대신 별로도 정의된 Series나 딕셔너리를 이용하여,  매핑 & 데이터 그룹화

df2 = pd.DataFrame(np.random.randn(5, 5),
                    columns=['a', 'b', 'c', 'd', 'e'],
                    index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'])

image

5 x 5 DataFrame이 있는 상태에서, df2의 컬럼(a,b,c,d,e)를 다른 값으로 매핑하기 위한 딕셔너리를 생성할 것이다.
딕셔너리의 {키값 = 매핑시킬 칼럼들  :  밸류값 = 매핑할 더 작은 종류의 값들} 형태로 만들어야한다.
(21강에서는 특정열의 성분들을 매핑해서, 더 적은 수의 성분들로 치환했었다. 이 때, m to n 딕셔너러+ apply()함수가 이용됬었음
키값 : 특정열의성분들 –> 밸류값 : 매핑할 더 작은 종류의 값들)

map_dict = {'a': 'red', 'b': 'red', 'c': 'blue',
             'd': 'blue', 'e': 'red', 'f' : 'orange'}
image

이제 groupby를 통화 그룹화를 할 때, 기준이 되는 인자에 딕셔너리를 넣고, axis를 1로 주어, 열 방향(→)으로 지정하여
(위에서 특정열에 대한 성분을 기준으로,  그 값을 포함하는 <index(행들)>를 그룹화 했던 것과는 다르게,)
 컬럼들을 그룹화한다. 이 때, 딕셔너리의 키값을 가진 컬럼들이,  밸류값들로 더 작게 매핑되서 컬럼들을 그룹화 한다.
(axis 인자를 안 주었을 때는, 기준열의 성분을 포함하는 행들을, 그룹화하였고
딕셔너리로 매핑 +  aixs =1을 준 경우에는, 해당 매핑값을 기준으로 해당 값에 속하는 칼럼들을 모아놓는다.

  • dict( list( df2.groupby(map_dict, axis=1) ) ) 를 통해, 
    axis=1으로 컬럼들을 그룹화 할 것이고, 딕셔너리를 통해 매핑하면서 그룹화한다.
    그룹화된 결과물을 보기 위해서, list로 쪼개고, 딕셔너리에 담았다.
    image
  • 그룹화결과물을 바로 보지 말고, 통계함수를 적용해서 합계를 보자.
    df2.groupby(map_dict, axis=1).sum()
    image
    a부터 e의 열을 red, blue로 매핑한 뒤, 각 red, blue에 해당하는 칼럼들을 그룹화하고 나서,  합을 구한 것이다.


Series를 가지고 매핑 한뒤, 그룹화 할 수 있다. 위에서 사용한 딕셔너리를 이용해서, Series를 만들어서 해보자.
map_s = pd.Series(map_dict)

  • df2.groupby(map_s, axis=1).count() 를 통해, 딕셔너리와 마찬가지로, 첫번째 인자에 Series를 넣고 axis=1로 준다.
    .count()를 통해 그룹화된 열의 갯수를 확인할 수 있다.
    image


이렇게 그룹화된 데이터에 적용할 수 있는 통계함수는 아래와 같다.
image



데이터 그룹화 결과물에 통계함수가 아닌, 사용자 정의 함수 적용하기

데이터 그룹화를 통해 얻어진 결과물에, 통계함수 외 사용자 정의함수를 적용할 수 도 있다.

먼저, df의 key1열을 기준으로 데이터그룹화 시켜놓고 변수에 저장한 뒤, 함수를 새로 정의할 것이다.
peak_to_peak()함수를 정의하는데, 받은 array의 < 각 열>마다 최대값 – 최소값을 반환하는 함수다.

grouped = df.groupby("key1")
def peak_to_peak(arr):
     return arr.max() - arr.min()

그룹화된 결과물에  agg()함수를 적용하게 되면,  그룹화된 각 그룹마다 사용자 정의함수(각 열의 최소-최대)를 적용할 수 있게 해준다.

  • grouped.agg( peak_to_peak )
    image

데이터 그룹화의 결과물에 .agg()를 이용해서, 일반적인 통계함수도 적용시킬 수 있다.
이 때, 인자에 “문자열”로 해당 함수를 호출하게 된다.

  • grouped.agg( "std" )  를 통해,  문자열에 std로 입력하면, 각 그룹들에 표준편차를 구할 수 있다.
    image



그룹화된 결과물에 대한 전체 통계량 보기

그룹화된 결과물에 .describe()를 통해 전체 통계량을 확인할 수 있다.

  • grouped.describe()
    image

+ Recent posts