Lecture Survey Summary (Google Forms)

  • 2주 전 학회에서 머신러닝 기초 강의를 했습니다.
  • Google Forms를 통해서 참석자들에게 피드백을 받았습니다.
  • 답변 정리에 Matplotlib 함수를 적극적으로 사용했습니다.


1. Google Forms

  • Google Forms는 간단하게 설문조사를 할 수 있는 플랫폼입니다.

  • 회의나 회식 일정을 잡는데 사용하기도 편하고 피드백을 받기 좋습니다.


  • 결과를 자체적으로 취합해서 보여주기 때문에 사실상 추가 처리가 필요치 않습니다.

  • 스크린샷만 찍어서 보고서에 붙여넣어도 무방한 퀄리티입니다.


  • 그런데 가끔 문제가 발생합니다.

  • 강의평가 중 강의 속도강의 난이도는 5점 만점 중 3점에 몰려있습니다.

  • 강의 속도와 난이도 조절을 실패한 것 처럼 보입니다.


  • 그러나 실제 문항을 보면 너무 느림너무 빠름의 딱 중간입니다.

  • 속도와 난이도가 적절했음을 알 수 있습니다.

  • 그림을 기계적으로 갖다붙이면 강의를 진행한 입장에서 몹시 억울할 것입니다.


  • Google Forms에서는 원본 데이터 다운로드를 제공합니다.

  • 그림을 다운받아 새로 그리면 됩니다.

  • 파이썬에서 진행합니다.

2. Python Visualization

2.1. 데이터 다운로드

  • 설문조사 결과지의 오른쪽 위를 클릭해 데이터를 받습니다.


  • 설문조사명이 파일명이 됩니다.

  • 적절히 짧게 바꿔 노트북에서 읽어옵니다.

  • 데이터 중 한글이 있으므로 한글 사용 설정도 함께 합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    %matplotlib inline

    # 필요 라이브러리 읽어오기
    import seaborn as sns
    import numpy as pd
    import pandas as pd
    import matplotlib.pyplot as plt

    sns.set_context("talk")
    sns.set_style("white")

    # 한글 사용 설정
    plt.rcParams['font.family']='NanumGothic'
    plt.rcParams['axes.unicode_minus'] = False

    # 데이터 파일 읽기
    df = pd.read_csv("googlesurvey.csv")
    df.head(3)


2.2. 문항 추출

  • 컬럼명이 문항입니다.
    1
    2
    Qs = df.columns
    Qs
    • 실행 결과
      1
      2
      3
      4
      5
      6
      7
      Index(['Timestamp', '1-1. 강의 전까지 본인의 파이썬 경험'', '1-2. 강의 전까지 본인의 머신러닝 경험',
      '1-3. 강의 전까지 본인 연구에 머신러닝 활용 계획', '1-4. 본인의 연차',
      '2-1. 강의 커리큘럼 - 슬라이드 & 예제 코드', '2-2. 강의 속도', '2-3. 강의 난이도',
      '2-4. 강의 전달력', '2-5. 동료에게 추천 의사', '3-1. 강의 후 파이썬 학습 의사',
      '3-2. 강의 후 머신러닝 학습 의사', '3-3. 강의 후 본인 연구에 머신러닝 활용 의사',
      '4. 건의사항 등 강사에게 하고싶은 말 (optional)'],
      dtype='object')

2.3. 시각화 함수 작성

  • 모든 문항은 본인의 연차항목을 제외하고 5점 척도로 되어 있습니다.
  • 형식은 histogram, 또는 bar plot이 적절합니다.
  • 데이터의 전반적인 분포가 중요하고, 데이터간 변화량은 중요치 않기 때문입니다.
  • 시각화 함수는 다음과 같이 작성되었습니다.

  • 부분별 설명은 주석으로 달았습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    from matplotlib import cm

    def plot_count(x, data, color="C0", cmap=None, ticks=range(1, 6), ticklabels=None,
    orient="v", ax=None, ec="none", figsize=(10, 5), filename=None):

    # 지정된 Axes가 없으면 새로 만들기. 크기는 figuresize에서 입력받음.
    if not ax:
    fig, ax = plt.subplots(figsize=figsize, constrained_layout=True)

    # value별로 갯수 세기. 데이터가 존재하지 않으면 0을 채움.
    val_cnt = data[x].value_counts().to_dict()
    cnt_list = [val_cnt[k] if k in val_cnt.keys() else 0 for k in ticks]

    # bar의 방향. v(ertical) 또는 h(orizontal).
    if orient == "v":
    ax.bar(x=range(1, 6), height=cnt_list, fc=color, ec=ec)
    elif orient == "h":
    ax.barh(y=range(1, 6), width=cnt_list, fc=color, ec=ec)

    # 변수 이름은 xlabel이지만 실제로는 title. 시각화 코드 수정이 남긴 흔적.
    # Google Forms에서 받은 데이터에 홑따옴표(')가 있어 제거 필요.
    # font 색상, 크기, 두께를 fontdict로 설정
    xlabel = x.replace("'","")
    font_label = {"color":"gray", "fontsize":"large", "fontweight":"bold"}

    # title 지정
    ax.set_title(xlabel, fontdict=font_label, pad=12)

    # bar 방향에 따라 ticklabels를 xticks 또는 yticks로 설정
    # ticklabels 입력과 무관하게 데이터값이 보이는 위치에 정수만 출력하고 grid 설정
    # ticklabels를 입력받으면 입력받은 값 출력
    if orient == "v":
    yticks = [int(y) for y in ax.get_yticks() if not (y*10)%10]
    ax.set_yticks(yticks)
    ax.set_yticklabels(yticks)
    ax.grid(axis="y")
    ax.set_ylabel("count", fontdict=font_label, labelpad=8)

    if ticklabels:
    ax.set_xticks(range(1, 6))
    ax.set_xticklabels(ticklabels, fontweight="bold")
    ax.set_xlabel("")

    if orient == "h":
    xticks = [int(x) for x in ax.get_xticks() if not (x*10)%10]
    ax.set_xticks(xticks)
    ax.set_xticklabels(xticks)
    ax.grid(axis="x")
    ax.set_xlabel("count", fontdict=font_label, labelpad=8)

    if ticklabels:
    ax.set_yticks(range(1, 6))
    ax.set_yticklabels(ticklabels, fontweight="bold")
    ax.set_ylabel("")

    # 입력받은 컬러맵 사용
    # 데이터의 범위보다 2개 더 많은 컬러맵 색상을 지정하고 첫 색상과 끝 색상은 사용하지 않음
    if cmap:
    ncmaps = 7
    if ticklabels:
    ncmaps = len(ticklabels) + 2
    # 컬러맵 불러오기
    cmap_ = plt.get_cmap(cmap, ncmaps)
    for i, p in enumerate(ax.patches, 1):
    p.set_facecolor(cmap_(i))

    # 파일명 입력시 입력받은 이름으로 저장.
    if filename:
    fig.savefig(filename, dpi=200)

    return ax
  • 시각화 결과물이 출력될 Axes를 입력받을 수도 있고 그렇지 않을 수도 있습니다.

  • bar plot을 가로 방향 또는 세로 방향으로 출력할 수 있습니다.

  • bar 색상은 특정 색상을 지정할 수도 있지만 컬러맵을 사용할 수 있습니다.

  • 컬러맵 사용시 맨 처음과 끝 색은 사용하지 않도록 설정했습니다. 지나치게 극단적인 색상 차를 방지하기 위해서입니다.

  • 코드가 잘 작동하는지 테스트합니다.
    1
    plot_count(Qs[1], df)

  • 다른 axes에 삽입도 해보고 가로 방향도 돌려봅니다.
  • 색상도 지정해보고, 너무 밝은 색에는 테두리도 둘러봅니다.
    1
    2
    3
    4
    5
    fig, axs = plt.subplots(ncols=3, figsize=(20, 6))
    plot_count(Qs[1], df, orient="h", color="C1", ax=axs[0])
    plot_count(Qs[2], df, orient="h", color="C2", ax=axs[1])
    plot_count(Qs[3], df, orient="h", color="C3", ec="gray", ax=axs[2])
    fig.tight_layout()

3. 설문결과 정리

  • 크게 4개 항목에 대하여 설문조사를 수행했습니다.
  • 보고서에 삽입될 그림이라 가로로 긴 모양을 택했습니다.

1. 강의 전 본인의 상태: 교육 참여자들의 파이썬, 머신러닝 친밀도와 학습 의지 조사
2. 강의 품질: 강의 속도, 난이도 등 조사. 차기 강의에 반영하기 위한 데이터
3. 강의 후 본인의 상태: 강의 효과 확인
4. 건의사항 등 강사에게 하고 싶은 말 (optional): 설문에 담기지 않은 내용 조사

3.1. 강의 전 본인의 상태

  • 교육 참여자

  • 첫 질문은 강의 전까지 파이썬 사용 경험입니다.

    1
    2
    plot_count(Qs[1], df, filename="Q1.png", cmap="magma", 
    ticklabels=["1\n한번도 안 써봤다", "2\n", "3\n", "4\n", "5\n주3회 이상 사용한다"])


  • 두 번째 질문은 기존 머신러닝 경험입니다.

    1
    2
    plot_count(Qs[2], df, filename="Q2.png", cmap="magma",
    ticklabels=["1\n한번도 안 해봤다", "2\n", "3\n", "4\n", "5\n필요한 기술을\n능숙하게 사용한다"])


  • 강의 전까지 본인 연구에 머신러닝을 활용할 계획이 있었는지 궁금했습니다.

    1
    2
    plot_count(Qs[3], df, filename="Q3.png", cmap="magma",
    ticklabels=["1\n전혀 없었다", "2\n", "3\n", "4\n", "5\n매우 구체적이었다"])


  • 본인의 연차

  • ticklabels가 길어서 가로로 그렸습니다.

1
2
3
4
plot_count(Qs[4], df, filename="Q4.png", cmap="Blues", orient="h",
ticks=["학부 졸업 후 현업 근무", "석사과정 학생", "석사 졸업 후 현업 근무", "박사과정 학생", "박사학위 소지자"],
ticklabels=["학부 졸업 후 현업 근무", "석사과정 학생", "석사 졸업 후 현업 근무",
"박사과정 학생", "박사학위 소지자"])


3.2. 강의 품질

  • 강의 커리큘럼은 적절했는지 궁금했습니다.
    1
    2
    plot_count(Qs[5], df, filename="Q5.png", cmap="magma",
    ticklabels=["1\n매우 불만족", "2\n", "3\n", "4\n", "5\n매우 만족"])

  • 강의 속도와 난이도가 가장 신경쓰였습니다.
  • 강의 속도 항목입니다. 딱 중간이 가장 좋고 양 끝으로 갈수록 좋지 않습니다.
  • 내용 전달을 위해 컬러맵을 좌우 대칭의 diverging 타입인 RdBu_r로 바꾸었습니다.
  • 가운데가 매우 밝은 회색이라 배경의 흰색과 잘 구분이 안되기에 테두리를 둘렀습니다.
    1
    2
    plot_count(Qs[6], df, filename="Q6.png", cmap="RdBu_r", ec="gray",
    ticklabels=["1\n너무 느림", "2\n", "3\n적절함", "4\n", "5\n너무 빠름"])

  • 강의 난이도입니다.
    1
    2
    plot_count(Qs[7], df, filename="Q7.png", cmap="RdBu_r", ec="gray",
    ticklabels=["1\n너무 쉬움", "2\n", "3\n적절함", "4\n", "5\n너무 어려움"])

  • 제가 제대로 했는지 강의 전달력도 많이 궁금했습니다.
    1
    2
    plot_count(Qs[8], df, filename="Q8.png", cmap="magma",
    ticklabels=["1\n매우 불만족", "2\n", "3\n", "4\n", "5\n매우 만족"])

  • 주최측에서 앞으로 계속 키워가고자 하는 행사입니다.
  • 앞으로의 흥행이 중요합니다.
    1
    2
    plot_count(Qs[9], df, filename="Q9.png", cmap="magma",
    ticklabels=["1\n매우 부정", "2\n", "3\n", "4\n", "5\n매우 긍정"])

  • 피드백을 통해 감을 잡을 수 있었습니다.
  • 다음 강의가 열린다면, 준비를 더 잘 할 수 있을 것 같습니다.

3.3. 강의 후 본인의 상태

  • 강의 전과 비교하여 조금 적극적이 되기를 바랬습니다.
  • 파이썬, 머신러닝, 본인 연구에 대한 변화가 있기를 바랬습니다.
  • 강의 시작부분에서 한시간 반으로는 맛배기도 안된다. 스스로 공부하시라는 말을 했기에 마음가짐 변화가 가장 중요합니다.
  • 함수로 그린 그림을 변수로 받아 수정합니다.
  • 설문조사 결과도 강의 전 결과를 그림으로 삽입하여 비교했습니다.
  • 함수로 만들어 사용할까 했지만 몇 개 안되어 코드를 복사해서 활용했습니다.
  • 먼저, 강의 전 후 파이썬 학습 의사를 조사했습니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 함수로 그림을 그립니다.
    ax = plot_count(Qs[10], df, filename="Q10.png", cmap="magma",
    ticklabels=["1\n매우 부정", "2\n", "3\n", "4\n", "5\n매우 긍정"])

    # Axes를 담고 있는 Figure를 호출합니다.
    fig = ax.figure

    # Figure에 비교할 그림을 붙일 공간을 확보합니다.
    ax_prev = fig.add_axes([0.05, 0.4, 0.6, 0.5])

    # 강의 전 상태를 불러와서 붙입니다.
    im_prev = plt.imread("Q1.png")
    ax_prev.imshow(im_prev)
    ax_prev.axis(False)

    # 결과를 정리합니다.
    fig.savefig("Q10.png", dpi=200)

  • 강의 후 머신러닝 학습 의사입니다.
  • 코드는 거의 동일합니다.

  • 강의 후 본인 연구에 머신러닝을 활용할 의사입니다.
  • 코드는 거의 동일합니다.

  • 전반적으로 강의 전보다 후에 파이썬, 머신러닝, 본인 연구 적용 의사가 높아졌습니다.
  • 감사하게도 응답을 잘 해주셨다는 생각도 듭니다만 실제로 이런 영향이 있으면 좋겠습니다. :)

3.4. 건의사항 등 강사에게 하고 싶은 말 (optional)

  • 9분 중 6분으로부터 감사한 글들을 받았습니다.
  • 세미나 형식의 발표는 다수 경험했고 온라인으로 단발적인 강의를 한 적은 있었습니다.
  • 그러나 대면수업으로 진도를 나가는 경험이 처음이었고, 90분으로 커버가 되기 어려운 내용이라 범위와 형식 선정에 신경을 썼습니다.
  • 다행히 반응이 호의적이어서 기운이 많이 납니다.
  • 다시 한번 감사드리며, 다음 기회에는 더 좋은 발표를 할 수 있으면 좋겠습니다..



도움이 되셨나요? 카페인을 투입하시면 다음 포스팅으로 변환됩니다

Share