본문 바로가기
Python/Data Visualization

[Kaggle 데이터 활용] 여러 개의 그래프 한번에 그리기(2) 심화

by ISLA! 2023. 8. 10.

Kaggle 2021년 survey 데이터 시각화

4개 국가 별, 가장 많이 쓰이는 클라우드 서비스 시각화하여 비교하기

 

라이브러리 import

import plotly.graph_objects as go
import plotly.figure_factory as ff		#대화형 시각화 라이브러리

 

데이터 불러오고, 간단히 가공하기

df21 = pd.read_csv("./data/kaggle/kaggle_survey_2021/kaggle_survey_2021_responses.csv")
questions = df21.iloc[0, :].T
df21 = df21.iloc[1:, :]

 

간단히 데이터 확인

print(questions['Q28'])
print(questions['Q29_A_Part_1'])
Of the cloud platforms that you are familiar with, which has the best developer experience (most enjoyable to use)? - Selected Choice
Do you use any of the following cloud computing products on a regular basis? (Select all that apply) - Selected Choice -  Amazon Elastic Compute Cloud (EC2) 

위 질문에 대한 답으로 들어온 데이터가 이렇게 자유분방(?)한걸 확인할 수 있다. >> 유사한 질문, 답변 데이터 중복 문제

다양한 클라우드 서비스를 사용한다는 여러 응답들인데 이러한 두 질문(28, 29의 파트1 ~ 파트4)에 대한 답변 데이터를 정리해보자.

먼저, 유사한 질문인 Q29_A_part1~4 의 네 개 문항 답변을 정리해서 보도록 하자. 함수를 쓸 것이다.

 

 

 

sub_questions_count 함수

 

👉 주어진 질문 번호(question_num)와 파트 개수(part_num)를 기반으로 질문 목록을 생성

  • 매개변수 : 질문 번호(question_num), 파트 번호(part_num), text 매개변수는 기본값이 False
  • part_questions 라는 빈리스트 생성
  • 만약 text가 "A" 또는 "B" 중 하나인 경우, 조건문 실행
    • 조건이 참일 경우 :
      • 문자열을 part_questions 라는 빈 리스트에 추가
      • 예를 들어, question_num이 1이고 part_num이 4이며, text가 "A"인 경우: 'Q1_A_Part_1', 'Q1_A_Part_2', 'Q1_A_Part_3'이 part_questions에 추가됨
      • 그 다음, Q1_A_OTHER'와 같은 형식의 추가적인 문자열을 part_questions에 추가
    • 조건이 거짓일 경우 : "A" 또는 "B"가 아닌 다른 텍스트 경우 
      • 이 경우도 위와 동일하게 part_questions 리스트에 지정된 형식에 따라 문자열들을 추가
def sub_questions_count(question_num, part_num, text = False):
  part_questions = []

  if text in ["A", "B"]:
    part_questions = ['Q' + str(question_num) + "_" + text + '_Part_' + str(j) for j in range(1, part_num)]
    part_questions.append('Q' + str(question_num) + "_" + text + '_OTHER')
  else:
    part_questions = ['Q' + str(question_num) + '_Part_' + str(j) for j in range(1, part_num)]
    part_questions.append('Q' + str(question_num) + '_OTHER')

 

위의 sub_questions_count 함수와 이어집니다

 

  • categories와 counts 라는 빈 리스트를 생성 : 질문 카테고리와 각 카테고리에 속하는 질문 수를 저장할 용도
  • part_questions 리스트의 각 요소에 대해 반복문 실행 : 
    • category = 데이터프레임 df의 i 열에서 가장 높은 빈도수를 가진
    • val = df의 i 열에서 가장 높은 빈도수를 가진 값의 빈도
    • category와 val 값을 각각 리스트에 저장
  • 빈 데이터프레임 combined_df 생성
  • combined_df에 Category와 Count 열 추가, 각 열에 categories와 counts 리스트 내용 넣기
  • Count 열을 기준으로, combined_df 를 내림차순 정렬
  • 정렬된 combined_df를 Return
  # category count
  categories = []
  counts = []
  for i in part_questions:
    category = df[i].value_counts().index[0]
    val = df[i].value_counts()[0]
    categories.append(category)
    counts.append(val)

  combined_df = pd.DataFrame()
  combined_df['Category'] = categories
  combined_df['Count'] = counts

  combined_df = combined_df.sort_values(['Count'], ascending = False)
  return combined_df

 

  • 앞서 정의한 sub_questions_count 함수 호출 : sub_questions_count(29, 4, "A")
    • 29번 질문의 A파트에 대한 카테고리별 질문수를 계산하여 반환할 것
    • 29번 하위의 4개 질문 각각에서 가장 많이 나온 답변과 그 수를 categories와 counts 리스트에 담는 것
    • 결과 : combined_df

 

👀 이를 통해 29번의 A 문항과 연결된 1, 2, 3, 4 네 개 질문에서 핵심(각 문항별 가장 많이 응답된 클라우드 서비스와 그 수)만 뽑아 볼 수 있었다.

👉 이제 28번 문항의 결과를 4개 나라별로 시각화해서 살펴보자.

 

  • df21['Q28'].value_counts()
    • df21 데이터프레임의 Q28 컬럼에 있는 값들의 빈도를 반환 => 28번 질문에 대한 응답분포를 확인
sub_questions_count(29, 4, "A")
df21['Q28'].value_counts()

 

 

  • Q5 컬럼에 있는 값들(직업) 중에서, 주어진 직업에 해당하는 데이터만 선택하여 df21 데이터프레임을 필터링
  • Q3 컬럼에 있는 값들(나라) 중에서 일부 국가명을 변경(간결하게!)
  • country_list 에 분석할 국가들을 나타내는 리스트 정의
  • countries_df : country_list에 포함된 국가들에 해당하는 데이터만 선택한 데이터프레임 (4개 국가 데이터만 보고싶으니까)
  • q3_q8 :
    • 위에서 생성한 4개 국가 데이터를 국가와 28번 질문 열을 기준으로 그룹화
    • 각 그룹 내 데이터 개수를 세어 count 열로 나타냄
df21 = df21[df21['Q5'].isin(['Student','Data Scientist','Software Engineer', 'Data Analyst', 'Machine Learning Engineer','Research Scientist'])]
df21['Q3'] = df21['Q3'].replace(['United States of America', 'South Korea'], ['USA', 'Korea']) # Change Name
country_list = ["USA", "China", "Japan", "Korea"]
countries_df = df21[df21['Q3'].isin(country_list)]
q3_q28 = countries_df.groupby(['Q3', 'Q28']).size().reset_index().rename(columns = {0:"Count"})

 

 

 

get_pnt 함수 : 데이터와 국가를 입력 받아, 해당 국가의 데이터를 가공하는 역할

  • 입력한 데이터프레임에서 입력 국가에 해당하는 데이터만 추출하여 data_country 라는 데이터프레임 생성
  • 방금 생성한 데이터프레임에 28번 질문 응답 분포 비율을 나타내는 컬럼 추가 => percentage 컬럼
  • percentage 컬럼 값을 numpy 메서드를 써서 소수점 첫째자리까지 반올림하여 % 비율로 나타냄 => % 컬럼
  • 이렇게 정리한 data_country 데이터프레임을 Return

+ 마지막으로 get_pnt 함수를 써서 4개 국가에 대한 data_country 데이터 프레임 만들기

def get_pnt(data, country):
    data_country = data[data['Q3'] == country].reset_index(drop = True)
    data_country['percentage'] = data_country["Count"] / data_country["Count"].sum()
    data_country['%'] = np.round(data_country['percentage'] * 100, 1)
    
    return data_country

usa_df = get_pnt(q3_q28, "USA")
china_df = get_pnt(q3_q28, "China")
japan_df = get_pnt(q3_q28, "Japan")
korea_df = get_pnt(q3_q28, "Korea")

 

🚩 최종 데이터 시각화

  • 네 개 국가별로 사용하는 클라우드 서비스 비교하는 막대그래프 만들기
fig = make_subplots(rows = 2, cols = 2, 
                    shared_xaxes=True, # Shared X Axes
                    shared_yaxes=True, # Shared Y Axes
                    vertical_spacing = 0.05,
                    subplot_titles=("USA with Q28", "China with Q28", "Japan with Q28", "Korea with Q28"), # title of each graph area
                    column_widths = [0.5, 0.5]) # size control  

fig.add_trace(go.Bar(x = usa_df['Q28'], 
                     y = usa_df['%'], 
                     text = usa_df['%'].astype(str) + "%", 
                     textposition='auto'), 
              row = 1, col = 1)

fig.add_trace(go.Bar(x = china_df['Q28'], 
                     y = china_df['%'], 
                     text = china_df['%'].astype(str) + "%", 
                     textposition='auto'), 
              row = 1, col = 2)

fig.add_trace(go.Bar(x = japan_df['Q28'], 
                     y = japan_df['%'], 
                     text = japan_df['%'].astype(str) + "%", 
                     textposition='auto'), 
              row = 2, col = 1)

fig.add_trace(go.Bar(x = korea_df['Q28'], 
                     y = korea_df['%'], 
                     text = korea_df['%'].astype(str) + "%", 
                     textposition='auto'), 
              row = 2, col = 2)

fig.update_layout(height = 1000,
                  showlegend=False)

fig.show()

728x90