1. 새롭게 알게된 내용
✅ 그래프 중 특정 데이터 표시 + 텍스트 추가하기
# 서울시에서 폭염이 가장 심했던 날 best10
df_seoul_hotestday = df_seoul_hotday.nlargest(10, '최고기온(°C)')
df_seoul_hotestday
→ 빨간색 박스처리한 데이터를 특정 그래프로 표현
- 추가로 표시할 부분은 plt.plot()을 추가하면 됨
- 특정 데이터의 위치(x, y)는 iloc로 데이터프레임의 인덱스로 접근
## 1. plot 기본 설정
plt.plot(df_seoul_hotday['일시'], df_seoul_hotday['최고기온(°C)'], 'r.')
# x, y축 라벨 표시
plt.xlabel('일시')
plt.ylabel('최고기온(°C)')
# 제목 표시
plt.title('서울시 폭염일 현황(1911-2020)', size = 20, weight = 'bold')
## 2. 가장 더웠던 날 표시
plt.plot(df_seoul_hotestday.iloc[0, 2].date(), df_seoul_hotestday.iloc[0, 5], 'r^') # 빨간색 삼각형으로 표시
## 3. 가장 더웠던 날짜, 온도 표시
plt.text(df_seoul_hotestday.iloc[0, 2].date(), df_seoul_hotestday.iloc[0, 5] + 0.5 # 텍스트 위치
, str(df_seoul_hotestday.iloc[0, 2].date()) + '(' + str(df_seoul_hotestday.iloc[0, 5]) + '도)' # 텍스트
, ha = 'center', size = 12) # 텍스트 기준 위치, 크기
# y축 범위 설정
plt.yticks(range(33, 42))
plt.show()
✅ 다중 막대그래프로 비교
- 다중 막대그래프로 그리기 위해서는 각 그래프의 width를 음수, 양수로 설정하고 align = 'edge'로 설정해야 함
- 범례를 표시할 때에는 ax.set_legend()가 아닌 ax.legend()를 사용해야 함 (그 외 다른 기능들은 ax.set_~ 사용)
# plt.subplots를 fig, ax 객체에 할당
fig, ax = plt.subplots()
# 빨간 막대 그래프 (폭염일수)
ax.bar(df_seoul_hotday_cnt.index, df_seoul_hotday_cnt['폭염일수'], width = - 0.4, align = 'edge'
, color = 'r', label = '폭염일수')
# 검은 막대 그래프 (열대야 일수)
ax.bar(df_seoul_hotnight_cnt.index, df_seoul_hotnight_cnt['열대야 일수'], width = 0.4, align = 'edge'
, color = 'k', label = '열대야 일수')
# 범례 표시 → ax.set_legend() 사용 x
ax.legend()
# 제목 표시
ax.set_title('서울시 연도별 폭염일수, 열대야일수', size = 20, weight = 'bold')
# x축, y축 레이블 표시
ax.set_xlabel('연도')
ax.set_ylabel('일수')
# x축, y축 구간 설정
ax.set_xticks(range(1910, 2021, 10))
ax.set_yticks(range(0, 51, 5))
plt.show()
✅ 막대그래프와 꺾은선그래프를 한 ax 내에 그리기
- 2중 y축을 사용하기 위해 plt.subplots()를 fig, ax1 객체에 할당하고 ax1와 x축을 공유하는 새로운 axes 객체인 ax2를 만든다.
→ ax1 객체에는 막대 그래프를 그린다.
→ ax2 객체에는 다른 y축을 활용하는 꺾은선 그래프를 그린다.
## 1. 남자, 여자 인구수 막대 그래프
# plt.subplots()를 fig, ax1이라는 객체에 할당 (2중 y축을 사용하기 위해)
fig, ax1 = plt.subplots()
ax1.bar(df_sido['시도명'], df_sido['남자 인구수'], width = - 0.4, align = 'edge', color = 'skyblue', label = '남자 인구수')
ax1.bar(df_sido['시도명'], df_sido['여자 인구수'], width = 0.4, align = 'edge', color = 'pink', label = '여자 인구수')
# 범례 표시 (위치 지정) → set_ 사용 x
ax1.legend(loc = (0.2, 0.8))
# x축 회전 → 객체 사용 x / plt.xticks() 사용
plt.xticks(rotation = 45)
## 2. 남녀 비율 꺾은선 그래프
# x축을 공유하는 새로운 axes 객체 만들기 (ax2)
ax2 = ax1.twinx()
ax2.plot(df_sido['시도명'], df_sido['남여 비율'], 'b^-.'
, mfc = 'r', mec = 'r' # 마커 배경, 테두리 색상
,label = '남여 비율')
ax2.legend(loc = (0.6, 0.85))
## 3. 수평선 그리기
# 1 이상 : 남자 비율이 높음, 1 이하 : 여자 비율이 높음을 뜻함
ax2.axhline(1, color = 'k')
# 제목
ax2.set_title('2021년 10월 남여 인구수, 남여 비율', size = 20)
# plt.suptitle('2021년 10월 시도별 인구수, 세대수, 세대당 인구', size = 20) # plt.suptitle도 사용 가능
plt.show()
✅ 다중플롯과 서브플롯
- 다중플롯은 하나의 ax에 여러 개의 plot을 그린 그래프를 뜻한다.
# 1. 반복문으로 여러 개의 데이터를 plot으로 그림
for i in range(len(df_seoul)):
plt.plot(df_seoul.iloc[i], label = df_seoul.index[i].split(' ')[1])
# 2. 그래프의 범례, 제목 등 표시
plt.legend(ncol = 2)
plt.xticks(range(0, 101, 10))
plt.title('2021년 서울시 구별-연령별 인구 구조', size = 20)
plt.ylabel('인구수')
plt.show()
- 여러 개의 그래프를 for문을 활용해 그리기 → plt.add_subplot(행, 열, 순번)
# 1. ax 사이즈 지정 및 fig 객체에 할당
fig = plt.figure(figsize = (15, 30))
# 2. for문을 반복하여 각 위치에 해당되는 그래프에 각 데이터 별 plot을 그림
for i in range(len(df_seoul)):
ax = fig.add_subplot(9, 3, i+1) # 해당하는 행, 열, 순번에 맞춰 ax 객체 할당
ax.plot(df_seoul.iloc[i])
ax.set_xticks(range(0, 101, 10)) # x축 범위 동일
ax.set_yticks(range(0, 15000, 1000)) # y축 범위 통일
ax.set_title(df_seoul.index[i].split(' ')[1])
fig.tight_layout()
✅ [추가] 그래프 특징 별 종류
- 관계, 분포, 카테고리형에 따라 그래프의 종류를 구분해놓은 이미지
2. 파트너간 상보적 학습
✅ DataFrame 경고 (SettingWithCopyWarning)
어제 팀원과 이야기했을 때, 아래의 상황에서 굳이 copy()를 사용할 필요가 있을까라는 생각을 했다.
df_sido = df[df['행정구역'].str.contains('00000000')].copy()
df_sido
어차피 기존 df에서 새로운 데이터프레임인(df_sido)를 만드는 것이기에 df_sido에서 변경한 작업들이 df에 영향이 가지 않을 것이기 때문이다. 그래서 굳이 copy()를 하지 않고 오늘의 코드를 작성하고 있었는데, 아래의 코드에서 다음과 같은 경고 창이 떴다.
# '시도명'이라는 컬럼 추가
df_sido['시도명'] = df_sido['행정구역'].str.split(' ').str[0]
df_sido.head()
<ipython-input-20-38007618a285>:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_sido['시도명'] = df_sido['행정구역'].str.split(' ').str[0]
SettingWithCopyWarning 경고는 원천이 되는 데이터프레임의 일부로 구성된 파생 데이터프레임에 변경을 가하는 경우 발생한다.
Pandas에서는 원천 데이터프레임을 생성할 때만 메모리를 할당하고, 이로부터 파생되는 데이터프레임은 원천 데이터프레임의 이미 적재된 메모리에 접근케하여 메모리를 절약한다. (원천 데이터프레임의 부분집합에 view를 형성하는 것과 같음)
SettingWithCopyWarning의 발생을 막기 위해서는 파생 데이터프레임에 copy() 메서드를 실행하여 원천 데이터프레임과 별도인 메모리 공간을 파생 데이터프레임에 부여하면 된다.
Pandas의 DataFrame 사용 중 SettingWithCopyWarning 발생할 때
Python, Pandas를 Excel보다 사랑하는 직장인을 위한 블로그
emilkwak.github.io
3. 멘토링
✅ displot을 subplot으로 그릴 수 있는지?
어제 titanic 데이터셋으로 seaborn 그래프를 그릴 때, 오류가 발생하는 부분인데 찾아봐도 정확한 답을 구하지 못해서 이것에 대해 강사님께 질문을 하였다.
[나의 질문]
seaborn의 displot은 subplot으로 그리면 빈 그래프와 마지막 그래프만 출력이 되는데, subplot으로는 그릴 수 없는지 궁금합니다.
(histplot, kdeplot 등 다른 그래프는 subplot이 가능한 것은 확인했습니다!)
▶ [답변]
displot은 figure 레벨에서 그려지는 그래프이다.
subplot에서는 figure라는 하나의 캔버스에 여러 axes가 그려진다.
그래서 보통 axes에 plot이 그려지는데, displot은 figure에 그려지는 그래프이기 때문에 subplot으로 그려지지 않는다.
[+]
displot은 histplot, kdeplot, ecdplot, rugplot 총 4가지의 plot을 모두 그릴 수 있는 함수이다.
→ kind 파라미터를 활용하여 설정 (기본 값은 hist로 히스토그램 그래프가 그려짐)
col 파라미터를 활용하여 특정 컬럼의 카테고리 별로 그래프를 그릴 수 있다.
sns.displot(data = titanic, x = 'age', hue = 'alive', col = 'pclass')
sns.displot(data = titanic, x = 'age', hue = 'alive', col = 'pclass', kind = 'kde')
4. 회고
이제까지 배웠던 시각화 기능을 다양한 데이터셋에 적용하여 그려보는 시간을 가졌다.
시각화 공부를 하면 할수록 새로운 기능과 그래프들이 나와서 조금씩 헷갈리기 시작했다. 특히 서브플롯을 그릴 때, 여러가지 방법으로 구현하는데 이 부분을 다시 공부해야겠다는 생각이 들었다.
또 파트너와 상보적 학습과 멘토링을 하면서 모르는 부분을 서로 공유하고 같이 찾아보고, 또 해답을 들을 수 있어서 헷갈리는 부분을 명확히 잡을 수 있어서 좋았다.
'웅진X유데미 STARTERS > TIL (Today I Learned)' 카테고리의 다른 글
[스타터스 TIL] 8일차.SQL을 통한 데이터활용과 분석 (1) - DDL, DML, WHERE절 (0) | 2023.02.16 |
---|---|
[스타터스 TIL] 8일차.파이썬 데이터 시각화 (5) - 시각화 실습 (0) | 2023.02.16 |
[스타터스 TIL] 6일차.파이썬 데이터 시각화 (3) - seaborn, 실습 (0) | 2023.02.13 |
[스타터스 TIL] 5일차.파이썬 데이터 시각화 (2) - 그래프 종류 (0) | 2023.02.11 |
[스타터스 TIL] 4일차.파이썬 데이터 시각화 (1) - 기본 그래프 (0) | 2023.02.10 |