본문 바로가기
재미로 하는 코딩

시각화 뽀개기8

by 헬푸밍 2023. 3. 2.

The seaborn.objects interface(seaborn객체 인터페이스)

 

Transforming data before plotting(플로팅 전 데이터 변환)

Statistical transformation(통계 변환)

많은 seaborn함수들과 같이 객체 인터페이스는 통계 변환을 지원한다. Agg같은 것을 Stat 객체를 통해 수행된다!
 
펭귄 데이터를 이용해서 그래프를 그려볼건데...
x는 종, y는 몸무게...
.add(so.Bar(), so.Agg())로 막대그래프, 몸무게 계산을 해서 그려보자!

import seaborn as sns
import seaborn.objects as so
penguins = sns.load_dataset("penguins")
(
    so.Plot(penguins, x="species", y="body_mass_g")
    .add(so.Bar(), so.Agg())
)

Shift + Tab으로 확인해보면 평균이 기본값인 것을 알 수 있고 실제로 종별 평균 막대그래프가 그려졌다!
 
함수 인터페이스에서, barplot과 같은 몇몇 시각화는 통계 변환이 가능했지만 scatterplot과 같은 다른 것들은 통계 변환을 하지 못했다. 객체 인터페이스에서는 더 깔끔하게 시각화와 변환을 분리해서 Mark와 Stat 객체를 구성할수 있게 한다!
 
위 그래프에서 Line만 Dot으로 바꾸고 pointsize=10으로 지정해주면...

(
    so.Plot(penguins, x="species", y="body_mass_g")
    .add(so.Dot(pointsize=10), so.Agg())
)

이렇게 그려진다!(산점도도 통계 변환을 할 수 있다!)

속성을 매핑하여 그룹을 형성할 때 Stat 변환(so.Agg())은 각 그룹에 개별적으로 적용된다!
그래프를 그려 확인해보자!
위 그래프에서 color='sex'만 추가해서 그래프를 그려보면...

(
    so.Plot(penguins, x="species", y="body_mass_g", color="sex")
    .add(so.Dot(pointsize=10), so.Agg())
)

이렇게 암수 따로 통계가 적용된다!
 

Resolving overplotting(오버플로팅 (그래프가 겹치는 것)해결)

일부 seaborn함수는 자동적으로 오버플롯팅을 해결하는 메커니즘을 갖고 있다. barplot의 경우 hue가 할당되면 막대를 회피한다. 객체 인터페이스는 덜 복잡한 기본 동작이 있는다. 여러개 그룹을 표현하는 막대는 기본적으로 겹친다!

(
    so.Plot(penguins, x="species", y="body_mass_g", color="sex")
    .add(so.Bar(), so.Agg())
)

바로 위에서 그렸던 시각화 코드에서 Dot만 Bar로 바꾸면...

이렇게 그래프가 겹쳐 그려진다!
 
겹치는 것을 해결하려면...
Agg stat과 두번째 변환(Dodge클래스로 변환하는 것)으로 Bar mark를 구성하면 된다!
 
이렇게 앞의 그래프 코드에서 so.Dodge()를 add안에 추가해 주면...

(
    so.Plot(penguins, x="species", y="body_mass_g", color="sex")
    .add(so.Bar(), so.Agg(), so.Dodge())
)

그래프를 겹치지 않게 그려준다!
 
Dodge클래스는 Move(이동) 변환의 예인데, Stat이랑 비슷하지만 단지 x, y좌표만 조정한다. Move 클래스는 어느 마크에도 적용될 수 있고 Stat클래스가 먼저 안와도 상관없다!
이렇게 so.Dot()에 바로 Dodge클래스를 적용하면...

(
    so.Plot(penguins, x="species", y="body_mass_g", color="sex")
    .add(so.Dot(), so.Dodge())
)

이렇게 성별별로 나눠서 점이 찍힌다!
 
여러개의 Move 기능을 연속으로 적용할 수도 있는데...
바로 뒤에 so.Jitter(.3)을 써보면...

(
    so.Plot(penguins, x="species", y="body_mass_g", color="sex")
    .add(so.Dot(), so.Dodge(), so.Jitter(.3))
)

이렇게 점이 덜겹치게 그려진다!
Jitter(0)이면 일직선이고 숫자가 커질수록 퍼지게 된다!
 

Creating variables through transformation(변환을 통한 변수생성)

Agg stat은 x, y 모두 정의가 되어야 하지만, 통계변환을 통해 변수를 생성할 수도 있다! 예를 들면, Hist stat은 단지 x, y 둘중 하나만 정의된 상태를 필요로하고... 다른 변수는 관찰값을 세어서 생성한다!
 
Plot에는 x에 종만 정의하고...
.add(so.Bar(), so.Hist())를 추가해주면...

(
    so.Plot(penguins, x="species")
    .add(so.Bar(), so.Hist())
)

이렇게 y를 정의하지 않더라도... 자동으로 세어서 변수를 만들어준다!
 
Hist stat은 수치데이터가 주어지면 비닝을 통해 새로운 x값을 만들어준다!
이렇게 x에 수치형변수인 날개길이? 를 넣어주면...

(
    so.Plot(penguins, x="flipper_length_mm")
    .add(so.Bars(), so.Hist())
)

이렇게 비닝을 통해 x축이 자동으로 생성!
 
주의할 점은 연속적 x축을 plot을 그리려면 Bar대신 Bars를 쓴 것이다!
이렇게 Bar로 하면...

(
    so.Plot(penguins, x="flipper_length_mm")
    .add(so.Bar(), so.Hist())
)

뚝 끊긴다!
 
Bars mark와 Bar mark는 관련이 있지만, Bars mark는 다른 기본값을 가지고 있고 연속적 히스토그램에 더 잘 작동한다. 또한 다른, 더 효율적인 matplotlib 작업을 할 수 있게 해준다. 이렇게 Bar/Bars와 같이 단수/복수 marks는 다른 곳에도 있고... 복수 mark는 보통 더 큰 수의 marks에 최적화 되어 있다!
 
몇몇 변환은 x, y를 둘 다 받지만, 각 좌표에 간격 데이터를 추가한다!. 특히 집계 후에 error bar를 그리는 것에 적절할 수 있다!
Plot에 데이터, x에 몸무게, y에종, color에 성별을 넣은 뒤...
.add(so.Dot(), so.Agg(), so.Doge()를 넣으면...

(
    so.Plot(penguins, x="body_mass_g", y="species", color="sex")
    .add(so.Dot(), so.Agg(), so.Dodge())
)

종별 암수별 몸무게가 집계가 된다!
 
여기에 errorbar을 추가할 수 있는데...
.add(so.Range(), so.Est(errorbar="sd"), so.Dodge())이렇게 해주면...

(
    so.Plot(penguins, x="body_mass_g", y="species", color="sex")
    .add(so.Dot(), so.Agg(), so.Dodge())
    .add(so.Range(), so.Est(errorbar="sd"), so.Dodge())
)

점의 연장선상에서 몸무게에 대한 에러바가 추가된다!
 

Orienting marks and transforms(방향 표시와 변환)

막대그래프를 집계하고, 안겹치게 그림을 그릴 때, x, y변수는 각각 다르게 처리된다. 각 연산은 orientation(방향)이라는 개념이 있다! Plot은 변수의 데이터 형식에 따라 방향을 자동으로 결정하려고 한다. 예를 들면 앞에서 그렸던 막대그래프(https://blog.kakaocdn.net/dn/csrL4B/btr1vsnmu6k/tLzzty7DeH6fHKaTIiEaxk/img.png) 코드에서 종과 몸무게(x와 y)를 바꿔버리면, 같은 플롯이지만 가로방향으로 그려진다!

(
    so.Plot(penguins, x="body_mass_g", y="species", color="sex")
    .add(so.Bar(), so.Agg(), so.Dodge())
)

이렇게 수평 막대그래프가 그려진다!
 
x, y가 둘다 수치형 변수일때와 같이 올바른 방향이 모호할 때가 있다. 이 경우에는 .add()에 명시적으로 orient 파라미터를 추가해주면 된다!
이번예시에는 tips데이터를 사용해볼 건데...
x는 총 계산한 금액, y는 사이즈, color는 시간대로 해서...
총 계산한 금액의 평균을 겹치지 않는 수평 막대그래프로 그려보면...

(
    so.Plot(tips, x="total_bill", y="size", color="time")
    .add(so.Bar(), so.Agg(), so.Dodge(), orient="y")
)

이렇게 수평 막대그래프로 그려진다...
 
만약 명시적으로 orient='y'를 넣어주지 않는다면...

tips = sns.load_dataset("tips")
(
    so.Plot(tips, x="total_bill", y="size", color="time")
    .add(so.Bar(), so.Agg(), so.Dodge())
)

seaborn이 헷갈려해서 x축 방향으로 집계를 해 알아보기 힘든 그래프가 그려진다...


참고사이트
https://seaborn.pydata.org/tutorial/objects_interface.html#transforming-data-before-plotting

The seaborn.objects interface — seaborn 0.12.2 documentation

The seaborn.objects interface The seaborn.objects namespace was introduced in version 0.12 as a completely new interface for making seaborn plots. It offers a more consistent and flexible API, comprising a collection of composable classes for transforming

seaborn.pydata.org

 

댓글