15wk-2: 기말고사

Author

최규빈

Published

December 18, 2023

기말고사 관련

공지사항

  • 시험일: 12월18일(월)
  • 시험시간: 16:00~17:50
  • 대면/비대면: 전북대 충남대 모두 “대면”시험으로 진행. 줌 필요X.
  • 구글검색 허용, ChatGPT 허용

주의사항

  • 부정행위적발시 기말고사점수 0점 처리함.
  • 본인확인을 위한 학생증 or 신분증을 지참.
  • 모두 대면시험이므로 별도의 준비시간없이 바로 시작함.
  • 질문은 카카오톡 채널을 통해서만 받으며, 대면질문은 받지 않음. (충남대 학생들은 대면질문이 불가능하므로)
  • 지연제출시 5분단위로 감점이 있음. (중간고사때는 조금 늦어도 별도의 감점은 없었지만, 다른 학생들과의 형평성에 어긋난다는 피드백이 있어서 수정함.) 전북대의 경우 JBNU 와이파이를 이용할시 속도이슈가 있으니 개인노트북보다는 실습실의 컴퓨터로 제출하는 것을 권장함.

import numpy as np
import pandas as pd
import plotly.express as px
import plotly.io as pio
import json
import requests
import pickle
pd.options.plotting.backend = "plotly"
pio.templates.default = "plotly_white"

1. NYCTaxi 자료 분석 (dashboard) – 100점

아래는 NYCTaxi자료에서 기본적인 전처리를 수행한 데이터프레임이다.

df = pd.read_csv("https://raw.githubusercontent.com/guebin/DV2023/main/posts/NYCTaxi.csv").assign(
    log_trip_duration = lambda df: np.log(df.trip_duration),
    pickup_datetime = lambda df: df.pickup_datetime.apply(pd.to_datetime),
    dropoff_datetime = lambda df: df.dropoff_datetime.apply(pd.to_datetime),
    dist = lambda df: np.sqrt((df.pickup_latitude-df.dropoff_latitude)**2 + (df.pickup_longitude-df.dropoff_longitude)**2),
    #---#
    vendor_id = lambda df: df.vendor_id.map({1:'A',2:'B'})
).assign(
    speed = lambda df: df.dist / df.trip_duration,
    pickup_hour = lambda df: df.pickup_datetime.dt.hour,
    dropoff_hour = lambda df: df.dropoff_datetime.dt.hour,
    dayofweek = lambda df: df.pickup_datetime.dt.dayofweek
)
df_small = df[::100].reset_index(drop=True)

주어진 자료를 이용하여 (1)-(3)에 해당하는 시각화를 대시보드로 구현하고, 홈페이지를 남겨라. 답안 예시는 아래와 같다.

(답안예시)

주의사항

  • 제출시간 이후에 대시보드 생성을 시도할 경우 부정행위로 간주하여 기말고사 전체를 0점처리함. (git에 기록남아있음)
  • 대시보드 구현이 되어있지 않은 경우 0점 처리함
  • xaxis, yaxis, lengend 등을 조정하는 것이 문제의도임. (구현되어있지 않으면 0점처리함)

힌트

아래와 같은 양식으로 qmd를 만들면 그림이 중복되어 출력되는 문제1가 발생하지 않음.

  • 1 현재 quarto dashboard가 불완전(정식버전이 아니라 prereleased version임)하여 생기는 버그인듯합니다

  • NYCTaxi.qmd
    ---
    title: "NYCTaxi"
    author: "최규빈"
    format: dashboard
    execute: 
      enabled: true
      cache: false
      freeze: false
    ---
    
    ```{python}
    #| output: false
    # 여기에 온갖코드를 넣음.
    # 1-(1),(2),(3) 에 대응하는 plotly figure를 아래와 같은 이름으로 저장
    # fig1 = ...
    # fig2 = ...
    # fig3 = ...
    ```
    
    # 기말고사1-(1),(2)
    
    ```{python}
    #| title: 요일,시간에 따른 평균속력 시각화        
    fig1.show()
    ```
    
    ```{python}
    #| title: 요일,시간에 따른 평균이동거리 시각화        
    fig2.show()
    ```
    
    # 기말고사1-(3)
    
    ```{python}
    #| title: 속력별 경로 시각화
    fig3.show()
    ```

    (1) 요일,시간에 따른 평균속력 시각화 – 25점

    자료 df에서 시간에 따른 평균속력을 구하고 이를 대시보드에 시각화하라.

    README

    • 요일은 {0:'월',1:'화',2:'수',3:'목',4:'금',5:'토',6:'일'}의 규칙에 따라 변환할 것

    (2) 요일,시간에 따른 평균이동거리 시각화 – 25점

    자료 df에서 시간에 따른 평균이동거리를 구하고 이를 대시보드에 시각화하라.

    README

    • 요일은 {0:'월',1:'화',2:'수',3:'목',4:'금',5:'토',6:'일'}의 규칙에 따라 변환할 것

    (3) 속력별 경로시각화 – 50점

    자료 df_small에서 속력을 quatile에 따라 4개의 구간으로 나누고, 구간별 이동경로를 대시보드에 시각화하라.

    README

    • Zoom = 11 로 설정할것. Figure의 width, height는 설정하지 말것
    • 기타 설정값에 대해서는 궁금한것이 있다면 질문할 것

    힌트:

    힌트1: 아래의 코드를 관찰하세요.

    speed = pd.Series([1,1,2,2,3,3,4,4])
    print(pd.qcut(speed,4))
    print(pd.qcut(speed,4,labels=['매우느림','조금느림','조금빠름','매우빠름']))
    0    (0.999, 1.75]
    1    (0.999, 1.75]
    2      (1.75, 2.5]
    3      (1.75, 2.5]
    4      (2.5, 3.25]
    5      (2.5, 3.25]
    6      (3.25, 4.0]
    7      (3.25, 4.0]
    dtype: category
    Categories (4, interval[float64, right]): [(0.999, 1.75] < (1.75, 2.5] < (2.5, 3.25] < (3.25, 4.0]]
    0    매우느림
    1    매우느림
    2    조금느림
    3    조금느림
    4    조금빠름
    5    조금빠름
    6    매우빠름
    7    매우빠름
    dtype: category
    Categories (4, object): ['매우느림' < '조금느림' < '조금빠름' < '매우빠름']

    힌트2: 1-(3)에 해당하는 그림을 fig3로 저장한후 아래의 코드를 관찰하세요

    for i in range(150):
        print(fig3.data[i].mode)

    이를 이용하여 legend를 수정하는 방법을 생각해보세요.

    2. 에너지사용량 (지리정보시각화) – 50점

    아래는 대한민국의 행정구역을 나타내는 json 파일과 2018-2021 기간동안의 에너지사용량이 저장된 url들이다.

    # Json
    https://raw.githubusercontent.com/southkorea/southkorea-maps/master/kostat/2018/json/skorea-provinces-2018-geo.json
    https://raw.githubusercontent.com/southkorea/southkorea-maps/master/kostat/2018/json/skorea-municipalities-2018-geo.json
    # DataFrame
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2018.csv
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2019.csv
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2020.csv
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Seoul2021.csv
    ...
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Busan2018.csv
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Busan2019.csv
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Busan2020.csv
    https://raw.githubusercontent.com/guebin/DV2022/main/posts/Energy/Busan2021.csv

    주어진 자료를 활용하여 아래의 물음에 답하라.

    주의사항

    • ‘전주시완산구’,’완산구’와 같은 지역명은 ’전주시-완산구’와 같은 양식으로 정리하라.
    • 인천광역시 남구는 새로운 이름인 미추홀구로 변경하라.

    힌트

    문제가 되는 지역명을 정리하면 아래와 같다.

    s = pd.Series(['인천광역시-미추홀구',
                   '경기도-고양시-덕양구','경기도-고양시-일산동구','경기도-고양시-일산서구',
                   '경기도-성남시-분당구','경기도-성남시-수정구','경기도-성남시-중원구',
                   '경기도-수원시-권선구','경기도-수원시-영통구', '경기도-수원시-장안구', '경기도-수원시-팔달구',
                   '경기도-안산시-단원구', '경기도-안산시-상록구',
                   '경기도-안양시-동안구', '경기도-안양시-만안구',
                   '경기도-용인시-기흥구', '경기도-용인시-수지구', '경기도-용인시-처인구',
                   '경상남도-창원시-마산합포구', '경상남도-창원시-마산회원구', '경상남도-창원시-성산구', '경상남도-창원시-의창구', '경상남도-창원시-진해구',
                   '경상북도-포항시-남구', '경상북도-포항시-북구',
                   '전라북도-전주시-덕진구', '전라북도-전주시-완산구',
                   '충청남도-천안시-동남구', '충청남도-천안시-서북구',
                   '충청북도-청주시-상당구', '충청북도-청주시-서원구', '충청북도-청주시-청원구', '충청북도-청주시-흥덕구'])

    (1) 에너지사용량차이(전기-도시가스) 시각화 – 25점

    에너지사용량(TOE)/전기에너지사용량(TOE)/도시가스의 차이를 계산하여 에너지사용량차이(전기-도시가스)라는 새로운 열로 추가하라. 수도권지역에 한정하여 에너지사용량차이(전기-도시가스)를 시각화하라. 시각화를 위해 plotlychoropleth_mapbox를 사용하고, 다음 요구사항을 충족시켜라.

    • 색상은 에너지사용량차이(전기-도시가스) 값에 따라 달라져야 하며, 색상 범위(range_color)는 해당 열의 최소값과 최대값으로 설정하라.
    • 애니메이션 프레임은 년도를 기준으로 하라.
    • 호버 데이터는 시도지역을 포함해야 한다.
    • 투명도는 0.5로 설정하라.
    • 지도 스타일은 ’carto-positron’을 사용하며, 중심 좌표는 위도 37.5642135, 경도 127.0016985로 설정하라.
    • 지도의 줌 레벨은 7.5로, 높이는 800, 너비는 750으로 설정하라.
    • 스크롤 줌 기능은 비활성화하라.

    시각화예시는 아래와 같다.

    fig = pio.from_json(requests.get('https://raw.githubusercontent.com/guebin/DV2023/main/posts/figure_21.json').text)
    pio.show(fig,config={'scrollZoom':False})

    주의사항

    • 수도권지역은 서울,경기,인천을 의미한다.
    • 호버데이터시 ‘고양시-덕양구’와 같은 양식이 아니라 ’고양시덕양구’ 혹은 ’덕양구’와 같은 방식으로 호버될 경우 0점 처리함. (인천광역시의 미추홀구 역시 구지명(인천광역시 남구)로 호버될경우 0점처리함)
    에너지사용량 정답오류 수정 2023-12-16 9:30 AM

    기존의 정답이 에너지사용량을 올바르게 계산하지 않고 있어 수정하였습니다. 오류는 한혜지 학생의 도움으로 찾을 수 있었습니다. 현재는 해당오류내용이 수정되었습니다.

    (2) (서울+김포)특별시? – 25점

    김포시의 서울편입이슈에 대한 아래의 제시문을 읽으라.

    김포시의 서울편입 이슈

    김포시를 서울특별시로 편입하자는 주장에 대한 논의가 활발해졌다. 2023년 10월 23일, 국민의힘 소속 김포 지역 정치인들이 2026년 신설 예정인 경기북부특별자치도에 김포시가 포함되는 것에 반대하며 서울특별시 편입을 제안했다. 이 제안은 국민의힘 지도부의 호응을 받았고, 이로 인해 10월 30일에는 이 문제가 국민의힘 내에서 중요한 논의 주제로 부상했다. 이후, 이 주제는 제22대 국회의원 선거의 중요한 정치적 이슈로 자리 잡으며, 많은 논쟁과 대중의 관심을 불러일으켰다. 이러한 정치적 변화는 한국 정치 무대에서 논쟁의 새로운 중심점이 되었으며, 김포시의 행정적 미래에 대한 광범위한 토론을 촉발하고 있다.

    김포시가 서울시에 편입되었다고 가정하고, (서울+김포)특별시 내 각 구별 에너지사용비율을 아래의 수식을 참고하여 연도별로 계산하라.

    Note

    2018년 김포시의 에너지사용비율, 2018년 서울시 서초구의 에너지사용비율은 각각 아래와 같이 계산한다.

    • \(\text{에너지사용비율}_{\text{김포시,2018}} = \frac{\text{에너지사용량}_\text{김포시,2018}}{\text{에너지사용량}_\text{김포시,2018}+\text{에너지사용량}_\text{서울시강남구,2018}+...+\text{에너지사용량}_\text{서울시중랑구,2018}}\)
    • \(\text{에너지사용비율}_{\text{서울시서초구,2018}} = \frac{\text{에너지사용량}_\text{서울시서초구,2018}}{\text{에너지사용량}_\text{김포시,2018}+\text{에너지사용량}_\text{서울시강남구,2018}+...+\text{에너지사용량}_\text{서울시중랑구,2018}}\)

    이때 에너지사용량은 전기,도시가스,지역난방의 합을 의미한다. 계산된 데이터를 바탕으로, 구별 에너시사용비율을 시각화 하라. 시각화를 위해 plotlychoropleth_mapbox를 사용하고, 다음 요구사항을 충족시켜라.

    • 색상은 ’에너지사용비율’에 따라 달라져야 하며, range_color에너시사용비율 열의 최소값과 최대값으로 설정하라.
    • 애니메이션 프레임은 ’년도’를 기준으로 설정하라.
    • 호버 데이터에는 ’시도’와 ’지역’을 포함시켜라.
    • 지도의 투명도는 0.5로 설정하라.
    • 지도 스타일은 ’carto-positron’을 사용하고, 중심 좌표는 위도 37.5612, 경도 126.8228로 설정하라.
    • 지도의 줌 레벨은 9로, 높이는 800, 너비는 750으로 설정하라.
    • 스크롤 줌 기능은 비활성화라.

    시각화 예시는 아래와 같다.

    fig = pio.from_json(requests.get('https://raw.githubusercontent.com/guebin/DV2023/main/posts/figure_22.json').text)
    pio.show(fig,config={'scrollZoom':False})

    3. FIFA – 50점

    아래는 FIFA 자료를 불러오는 코드이다.

    df = pd.read_csv('https://raw.githubusercontent.com/guebin/DV2021/master/_notebooks/2021-10-25-FIFA22_official_data.csv').drop(['Loaned From','Marking'],axis=1).dropna()
    df.head()
    ID Name Age Photo Nationality Flag Overall Potential Club Club Logo ... SlidingTackle GKDiving GKHandling GKKicking GKPositioning GKReflexes Best Position Best Overall Rating Release Clause DefensiveAwareness
    0 212198 Bruno Fernandes 26 https://cdn.sofifa.com/players/212/198/22_60.png Portugal https://cdn.sofifa.com/flags/pt.png 88 89 Manchester United https://cdn.sofifa.com/teams/11/30.png ... 65.0 12.0 14.0 15.0 8.0 14.0 CAM 88.0 €206.9M 72.0
    1 209658 L. Goretzka 26 https://cdn.sofifa.com/players/209/658/22_60.png Germany https://cdn.sofifa.com/flags/de.png 87 88 FC Bayern München https://cdn.sofifa.com/teams/21/30.png ... 77.0 13.0 8.0 15.0 11.0 9.0 CM 87.0 €160.4M 74.0
    2 176580 L. Suárez 34 https://cdn.sofifa.com/players/176/580/22_60.png Uruguay https://cdn.sofifa.com/flags/uy.png 88 88 Atlético de Madrid https://cdn.sofifa.com/teams/240/30.png ... 38.0 27.0 25.0 31.0 33.0 37.0 ST 88.0 €91.2M 42.0
    3 192985 K. De Bruyne 30 https://cdn.sofifa.com/players/192/985/22_60.png Belgium https://cdn.sofifa.com/flags/be.png 91 91 Manchester City https://cdn.sofifa.com/teams/10/30.png ... 53.0 15.0 13.0 5.0 10.0 13.0 CM 91.0 €232.2M 68.0
    4 224334 M. Acuña 29 https://cdn.sofifa.com/players/224/334/22_60.png Argentina https://cdn.sofifa.com/flags/ar.png 84 84 Sevilla FC https://cdn.sofifa.com/teams/481/30.png ... 82.0 8.0 14.0 13.0 13.0 14.0 LB 84.0 €77.7M 80.0

    5 rows × 63 columns

    아래는 {소속대륙:국가} 및 {포지션:세부포지션}에 정보를 담은 딕셔너리이다.

    continent_dict = {
        'Asia': ['Afghanistan', 'Japan', 'Macau', 'Chinese Taipei', 'Indonesia', 'Korea Republic', 'Kazakhstan', 'Kyrgyzstan', 'Bhutan', 'Philippines', 'Syria', 'China PR', 'Oman', 'Guam', 'Vietnam', 'Jordan', 'Palestine', 'Malaysia', 'Hong Kong', 'Korea DPR', 'Lebanon', 'Uzbekistan', 'India','Iraq', 'Iran', 'Saudi Arabia', 'United Arab Emirates','Australia'],
        'Europe': ['Portugal', 'Germany', 'Belgium', 'Netherlands', 'Croatia', 'Spain', 'Austria', 'Italy', 'France', 'Serbia', 'England', 'Poland', 'Ukraine', 'Wales', 'Scotland', 'Czech Republic', 'Slovakia', 'Romania', 'Bosnia and Herzegovina', 'Republic of Ireland', 'Norway', 'Sweden', 'Bulgaria', 'Lithuania', 'Estonia', 'Latvia', 'Liechtenstein','Albania','Denmark','Finland','Greece','Hungary','Iceland','Luxembourg','Northern Ireland','Slovenia','Switzerland','Andorra','Azerbaijan','Belarus','Cyprus','Faroe Islands','Georgia','Kosovo','Malta','Moldova','Montenegro','North Macedonia','Armenia','Gibraltar','Russia','Turkey','Israel'],
        'South America': ['Uruguay', 'Argentina', 'Brazil', 'Chile', 'Colombia', 'Ecuador', 'Paraguay', 'Venezuela', 'Suriname', 'Bolivia','Peru','Guyana'],
        'Africa': ['Egypt', "Côte d'Ivoire", 'Senegal', 'Morocco', 'Ghana', 'Algeria', 'Guinea', 'Mali', 'Congo DR', 'Liberia', 'Cameroon', 'Tunisia', 'Comoros', 'Kenya', 'South Africa', 'Zimbabwe', 'Madagascar', 'Mozambique', 'Equatorial Guinea', 'Congo', 'Burundi', 'Grenada', 'Thailand', 'Togo', 'Sudan', 'Mauritania','Guinea Bissau','Libya','Nigeria','Zambia','Angola','Benin','Burkina Faso','Cape Verde Islands','Central African Republic','Chad','Eritrea','Gabon','Gambia','Mauritius','Namibia','Rwanda','Sierra Leone','South Sudan','São Tomé e Príncipe','Uganda','Niger'],
        'North and Central America': ['Antigua and Barbuda', 'Barbados', 'Belize', 'Bermuda', 'Canada', 'Costa Rica', 'Cuba', 'Curacao', 'Dominican Republic', 'El Salvador', 'Guatemala', 'Haiti', 'Honduras', 'Jamaica', 'Mexico', 'Montserrat', 'Panama', 'Puerto Rico', 'Saint Kitts and Nevis', 'Saint Lucia', 'Trinidad and Tobago', 'United States'],
        'Oceania': ['New Zealand', 'Fiji', 'Papua New Guinea','New Caledonia'],
    }
    position_dict = {
        'GOALKEEPER':{'GK'},
        'DEFENDER':{'CB','RCB','LCB','RB','LB','RWB','LWB'},
        'MIDFIELDER':{'CM','RCM','LCM','CDM','RDM','LDM','CAM','RAM','LAM','RM','LM'},
        'FORWARD':{'ST','CF','RF','LF','RW','LW','RS','LS'},
        'SUB':{'SUB'},
        'RES':{'RES'}
    }

    주어진 자료를 활용하여 아래를 잘 읽고 물음에 답하라.

    (1) 대륙별 인적자원 – 20점

    각 대륙 및 국가별 인적 자원 현황을 시각화하고자 한다. 이를 위해 아래와 같은 두 가지 형태의 시각화를 구현했다.

    fig = pio.from_json(requests.get('https://raw.githubusercontent.com/guebin/DV2023/main/posts/figure_31.json').text)
    pio.show(fig,config={'scrollZoom':False})
    fig = pio.from_json(requests.get('https://raw.githubusercontent.com/guebin/DV2023/main/posts/figure_32.json').text)
    pio.show(fig,config={'scrollZoom':False})

    첫 번째 시각화(Figure 1)를 통해, 각 대륙별로 선수들의 평균 능력치, 평균 급여, 그리고 선수층의 깊이를 비교할 수 있었다. 이를 바탕으로, 남미 대륙이 평균 능력치에서, 아프리카가 평균 급여에서 높은 값을 보였으며, 유럽은 가장 깊은 선수층을 가지고 있는 것으로 나타났다. 두 번째 시각화(Figure 2)는 나라별로 세분화된 인적 자원을 조사하는 데 중점을 두었다. 이 그림에서 브라질은 선수 수, 평균 능력치, 평균 급여 등 여러 면에서 우수함을 확인할 수 있었다. 반면, 우크라이나는 선수들의 평균 능력치는 높지만 선수 수와 평균 급여는 상대적으로 낮은 값을 보었다. 두 번째 시각화를 이용해 국가별 특색을 좀 더 면밀히 파악할 수 있었다.

    Figure 1과 Figure 2를 재현하라.

    (2) 아시안컵은 누가 차지할까 – 30점(+\(\alpha\))

    곧 시작될 아시안컵의 우승 국가를 예측하기 위해, 아시아 국가들의 축구 선수들을 기준으로 한 새로운 강함 지표를 개발했다. 이 지표는 선수들의 평균 능력치와 선수 수를 결합한 것이다. 예를 들어, 한국과 일본의 Strength 지표는 각각 다음과 같이 계산된다:

    • 한국의 Strength = 한국 선수들의 평균 능력치 + 한국 선수들의 수 / 5
    • 일본의 Strength = 일본 선수들의 평균 능력치 + 일본 선수들의 수 / 5

    이를 바탕으로 아래와 같은 두가지 형태의 시각화를 구현했다.

    fig = pio.from_json(requests.get('https://raw.githubusercontent.com/guebin/DV2023/main/posts/figure_33.json').text)
    pio.show(fig,config={'scrollZoom':False})
    fig = pio.from_json(requests.get('https://raw.githubusercontent.com/guebin/DV2023/main/posts/figure_34.json').text)
    pio.show(fig,config={'scrollZoom':False})

    이 첫 번째 시각화(Figure 1)를 통해, 각 국가의 Strength를 기반으로 8강 진출 국가를 예상했다. 그 결과 일본,한국,호주,사우디아라비아,이란,중국,시리아,우즈베키스탄 순으로 8강진출국이 예상되었다. 또한 두 번째 시각화 (Figure22)에서는 Strength가 높은 상위 6개 국가를 선별하여, 국가별 포지션에 따른 평균 능력치(Overall)를 비교함으로써 각 국가의 강점과 약점을 분석했다. 이 분석에 따르면, 일본은 모든 포지션에서 뛰어난 능력치를 보였고, 이란은 특히 골키퍼와 공격수 포지션에서 매우 우수한 것으로 나타났다.

    Figure1,2를 재현하라.

    주의사항

    • Figure1에서 투명도는 구현하지 않아도 무방하며 투명도 구현시 10점의 가산점이 있음. (Figure1에서 8강 진출이 예상되는 국가에 대한 투명도는 0.9로, 그렇지 않는 국가에 대한 투명도는 0.5로 설정)
    • Figure2에서 카테고리들의 정렬은 구현하지 않아도 무방함. (즉 국가가 일본,한국,…,중국 순서로 정렬될 필요는 없으며 포지션도 골키퍼,수비수,미드필더,공격수 순으로 정렬될 필요없음) 구현시 10점 가산점 있음.
    • 이외의 사항은 모두 구현되어야 하며 올바르게 구현되지 않은 경우 0점 처리함.