跳转至

Visualization of Who is who

Who is who 数据可视化,了解 DS&BA 项目的同学情况。

本科毕业院校

心得体会与遇到的困难

Who is who 中的新生介绍信息大部分都是文本数据,并且有很多是非结构化的数据。在对这种文本类型居多、非结构化数据居多的数据进行可视化时,首先需要将它们尽量处理成结构化的数据。

处理过程中遇到了很多细小的但又影响分析结果的困难,例如:

  • 有的同学用英文填写信息,她填的“Capricorn”对应的是其他同学填的“摩羯座”,我们只能手动将数据修正。
  • 有的同学写了错别字,她填的“魔羯座”对应的是其他同学填的“摩羯座”,我们也只能手动将数据修正。
  • 有的同学在填写的时候,在前面后后面多了一个空格,如“双鱼座”和“双鱼座”,肉眼看上去都是双鱼座,但前者多了一个空格,导致在统计词频时出错。这要求我们必须仔细检查数据,否则可能都发现不了,导致后续的数据分析存在误差。

方便进行结构化的数据可视化

本科是否在上海与是否经历过隔离/做过志愿者

SMART 分析过程

•Specific:提出问题:本科是上海高校的同学,经历过隔离和做过志愿者的比例是否高于本科非上海高校的同学?

•Measurable:经历过隔离和做过志愿者的同学比例可通过数据表格中的“是否经历过隔离”和“是否做过志愿者”进行量化。本科是否在上海就读可以根据本科毕业院校判断。

•Attainable:数据表中包含 2022 级同学的本科毕业院校、“是否经历过隔离”和“是否做过志愿者”的信息。

•Relevant:疫情相关的问题,可以验证自己的直觉猜想。

•Time-Bound:需要根据人为判断文本信息,并将其结构化。预计需要花费不到 1 小时。

Python
# =====是否经历过隔离或做过志愿者=====
def isolation_volunteer(blocked, type):
    fig = plt.figure(figsize=(8, 6), dpi=100)
    ax = plt.axes()
    for line in ["right", "top"]:
        ax.spines[line].set_visible(False)
    # 去除横坐标的刻度线
    ax.tick_params(bottom=False)
    # 绘制柱状图
    plt.bar([0, 0.5], blocked.loc[type], color="#084082", width=0.3, edgecolor="white")
    # 在柱子上方显示纵坐标
    plt.text(
        0,
        blocked.loc[type]["本科在上海"] + 0.02,
        "%1.0f" % (100 * blocked.loc[type]["本科在上海"]) + "%",
        ha="center",
        va="bottom",
        fontsize=16,
    )
    plt.text(
        0.5,
        blocked.loc[type]["本科不在上海"] + 0.02,
        "%1.0f" % (100 * blocked.loc[type]["本科不在上海"]) + "%",
        ha="center",
        va="bottom",
        fontsize=16,
    )
    # 添加横刻度
    plt.xticks([0, 0.5], ["本科在上海", "本科不在上海"], fontsize=16)
    # 添加纵刻度
    plt.yticks(np.arange(0, 1.1, 0.5), fontsize=16)

    # 显示百分比
    def to_percent(temp, position):
        return "%1.0f" % (100 * temp) + "%"

    plt.gca().yaxis.set_major_formatter(FuncFormatter(to_percent))
    # 保存为本地文件
    fig.savefig(
        "output/{}.png".format(type),
        format="png",
        facecolor="white",
        bbox_inches="tight",
    )

是否经历过隔离

是否做过志愿者

星座分布(基础柱状图)

SMART 分析过程

•Specific:提出问题:各个星座的同学人数是否分布均匀?

•Measurable:星座数据本身是规范的文本,可以统计词频来获得每个星座的人数。

•Attainable:数据表中包含三个年级同学的星座信息。

•Relevant:可以验证自己的直觉猜想:大家出生的日期是否分布均匀。

•Time-Bound:需要人为检查并修改数据,例如错别字、中英文等。预计花费不到 1 小时。

Python
# =====星座柱状图=====
def draw_constellations(df):
    # 统计各星座的频率
    constellations = df["星座"].value_counts().reset_index()
    # 修改列名
    constellations.rename(columns={"星座": "人数"}, inplace=True)
    # 将星座名映射为带有日期的星座名,并为每一个星座按时间指定顺序。同时,为每一个星座指定颜色
    constellations_order = {
        "水瓶座": ["水瓶座 (1.20-2.18)", 1, "#1e3482"],
        "双鱼座": ["双鱼座 (2.19-3.2)", 2, "pink"],
        "白羊座": ["白羊座 (3.21-4.19)", 3, "red"],
        "金牛座": ["金牛座 (4.20-5.20)", 4, "yellow"],
        "双子座": ["双子座 (5.21-6.20)", 5, "#6ac8cf"],
        "巨蟹座": ["巨蟹座 (6.21-7.21)", 6, "#dddbde"],
        "狮子座": ["狮子座 (7.22-8.22)", 7, "gold"],
        "处女座": ["处女座 (8.23-9.22)", 8, "#b7e1fb"],
        "天秤座": ["天秤座 (9.23-10.22)", 9, "#e5e2f4"],
        "天蝎座": ["天蝎座 (10.23-11.21)", 10, "#6766bc"],
        "射手座": ["射手座 (11.22-12.21)", 11, "#f67524"],
        "摩羯座": ["摩羯座 (12.22-1.19)", 12, "#5c5c5c"],
    }
    constellations["星座"] = constellations["index"].apply(
        lambda constellations: constellations_order[constellations][0]
    )
    constellations["顺序"] = constellations["index"].apply(
        lambda constellations: constellations_order[constellations][1]
    )
    # 升序排列所有星座,即 1 月的星座在最上方
    constellations.sort_values(by=["顺序"], inplace=True)
    # 挑选出需要的列
    constellations = constellations[["星座", "人数"]]
    # 设置画布的尺寸
    fig = plt.figure(figsize=(10, 7), dpi=300)
    ax = plt.axes()
    # 隐藏上侧和右侧的框线
    for line in ["right", "top"]:
        ax.spines[line].set_visible(False)
    # 去除横坐标的刻度线
    ax.tick_params(bottom=False)
    # 绘制柱状图
    plt.bar(
        x=constellations["星座"],
        height=constellations["人数"],
        color=[value[2] for value in list(constellations_order.values())],
    )
    # 添加平均线
    plt.axhline(constellations["人数"].mean(), color="gray", ls="--", label="平均人数")
    # 设置 y 轴坐标标签
    plt.ylabel("人数", fontsize=12)
    # 添加横刻度
    plt.xticks(constellations["星座"], rotation=90)
    # 添加纵刻度
    plt.yticks(np.arange(0, 19, 2))
    plt.legend(loc="upper left")
    # 保存为本地文件
    fig.savefig("output/星座.png", format="png", facecolor="white", bbox_inches="tight")

星座

本科毕业院校(多组柱状图)

SMART 分析过程

•Specific:提出问题:DS&BA 项目从哪些本科院校、哪些本科专业招生?各年度之间是否有变化?

•Measurable:本科毕业院校数据本身是规范的文本,可以统计词频来获得每个学校的人数。本科专业的名字可能存在差异,例如“经济统计”和“经济统计学”,其实是一个专业,只是同学们填的不同,因此适合用词云图来展现关键词。

•Attainable:数据表中包含三个年级同学的本科毕业院校信息和本科专业信息。

•Relevant:可以为关注 DS&BA 项目的同学提供参考:哪些院校、哪些专业的同学进入过 DS&BA 项目。

•Time-Bound:需要人为检查并修改数据,例如错别字、院校缩写等。预计花费不到 2 小时。

Python
# =====本科毕业院校柱状图=====
def draw_undergraduate_university(df):
    # 提取出各年份的本科毕业院校
    undergraduate_university = df.groupby("入学年份")["本科毕业院校"].value_counts().to_frame()
    # 修改列名
    undergraduate_university.columns = ["人数"]
    # 重设索引,避免处理多重索引
    undergraduate_university.reset_index(inplace=True)
    # 将长型数据转换为宽型数据
    undergraduate_university = undergraduate_university.pivot(
        index="本科毕业院校", columns="入学年份", values="人数"
    )
    # 将空值填充为 0
    undergraduate_university.fillna(0, inplace=True)
    # 将数据降序排列
    undergraduate_university.sort_values(
        by=["2022", "2021", "2020"], ascending=False, na_position="last", inplace=True
    )
    # 创建年份与颜色的字典
    color_year = {
        "2020": "#4E9ACB",
        "2021": "#1E6DB2",
        "2022": "#084082",
    }
    # 创建画布
    fig = plt.figure(figsize=(18, 8), dpi=300)
    ax = plt.axes()
    # 隐藏上侧和右侧的框线
    for line in ["right", "top"]:
        ax.spines[line].set_visible(False)
    # 去除横坐标的刻度线
    ax.tick_params(bottom=False)
    # 设定每一个柱子的宽度
    bar_width = 0.2
    # 画图
    for year in undergraduate_university.columns:
        # 指定各年的所有柱子的横坐标。乘以 0.8 是因为一个柱子群一共只有 3 个柱子,0.8 就代表 4 个柱子,剩下一个柱子的距离用来分割每个柱子群。
        globals()["x_" + year] = (
            np.arange(undergraduate_university.shape[0]) * 0.8
            + (int(year) - 2020) * bar_width
        )
        # 获取各年的所有柱子的纵坐标
        globals()["data_" + year] = undergraduate_university[year]
        plt.bar(
            globals()["x_" + year],
            globals()["data_" + year],
            width=bar_width,
            color=color_year[year],
            edgecolor="None",
            label=year,
        )
        # 在柱子上方显示纵坐标
        for x, y in zip(globals()["x_" + year], globals()["data_" + year]):
            plt.text(x, y + 0.05, "%.0f" % y, ha="center", va="bottom")
    # 添加横坐标
    plt.xticks(
        globals()[
            "x_"
            + undergraduate_university.columns[
                int(undergraduate_university.shape[1] / 2)
            ]
        ],
        undergraduate_university.index,
        rotation=90,
    )
    # 添加图例
    plt.legend()
    # 保存为本地文件
    fig.savefig(
        "output/本科毕业院校.png", format="png", facecolor="white", bbox_inches="tight"
    )

本科毕业院校

本科专业(词云图)

Python
# =====绘制词云图=====
def draw_word_cloud(
    text_path, output_path, outline_image_path=imread(r".\data\黑圆点.png")
):
    # 字体路径
    font_path = r"C:\Windows\Fonts\simhei.ttf"
    # 读取文本
    text = open(text_path, encoding="UTF-8").read()
    # 配置词云图
    wc = WordCloud(
        font_path=font_path,
        background_color="white",
        max_words=2000,
        mask=outline_image_path,
        max_font_size=100,
        random_state=42,
        width=1000,
        height=860,
        margin=2,
    )
    # 生成词云图
    wc.generate(text)
    plt.figure(dpi=300)
    plt.imshow(wc, interpolation="bilinear")
    plt.axis("off")
    # 保存为本地文件
    wc.to_file(output_path)

本科专业词云图

各年度入学的本科专业

Python
# =====绘制各年度年本科专业词云图=====
for year in ["2020", "2021", "2022"]:
    df[df["入学年份"] == year]["本科专业"].to_csv(
        r".\data\undergraduate_major_{}.txt".format(year), index=False, header=False
    )
    draw_word_cloud(
        text_path=r".\data\undergraduate_major_{}.txt".format(year),
        output_path=r".\output\{}年本科专业词云图.png".format(year),
    )

2020 年:

2020 年本科专业词云图

2021 年:

2021 年本科专业词云图

2022 年:

2022 年本科专业词云图

不方便进行结构化的数据可视化

SMART 分析过程

•Specific:提出问题:DS&BA 项目的同学有何兴趣爱好?去过的以及想去的地方有哪些?

•Measurable:兴趣爱好等数据都是同学们自定义的文本数据,本身并不规范,因此难以进行结构化。可以通过词云图展现关键词的出现频率。

•Attainable:数据表中包含三个年级同学的兴趣爱好等信息。2022 级同学还包含去过的和想去的地方等信息。

•Relevant:可以帮助了解 DS&BA 项目的同学的生活,找到相同爱好的同学们、组织大家都喜欢的聚会活动等。

•Time-Bound:需要处理数据、生成词云图,预计花费不到 2 小时。

兴趣爱好

Python
# =====绘制兴趣爱好词云图=====
df["兴趣爱好"].to_csv(r".\data\hobby.txt", index=False, header=False)
draw_word_cloud(
    text_path=r".\data\hobby.txt",
    output_path=r".\output\兴趣爱好词云图.png",
    outline_image_path=imread(r".\data\篮球.png"),
)

兴趣爱好词云图

最喜欢的书

Python
# =====绘制最喜欢的书词云图=====
df["最喜欢的书"].to_csv(r".\data\favorite_book.txt", index=False, header=False)
draw_word_cloud(
    text_path=r".\data\favorite_book.txt",
    output_path=r".\output\最喜欢的书.png",
    outline_image_path=imread(r".\data\书本.png"),
)

最喜欢的书

最喜欢的电影

Python
# =====绘制最喜欢的电影词云图=====
df["最喜欢的电影"].to_csv(r".\data\favorite_movie.txt", index=False, header=False)
draw_word_cloud(
    text_path=r".\data\favorite_movie.txt",
    output_path=r".\output\最喜欢的电影.png",
    outline_image_path=imread(r".\data\电影.png"),
)

最喜欢的电影

最喜欢的食物

Python
# =====绘制最喜欢的食物词云图=====
df["最喜欢的食物"].to_csv(r".\data\favorite_food.txt", index=False, header=False)
draw_word_cloud(
    text_path=r".\data\favorite_food.txt",
    output_path=r".\output\最喜欢的食物.png",
    outline_image_path=imread(r".\data\食物.jpg"),
)

最喜欢的食物

去过令你印象最深刻的地方

Python
# =====绘制去过令你印象最深刻的地方词云图=====
df["去过令你印象最深刻的地方"].to_csv(
    r".\data\most_impressing_place.txt", index=False, header=False
)
draw_word_cloud(
    text_path=r".\data\most_impressing_place.txt",
    output_path=r".\output\去过令你印象最深刻的地方.png",
    outline_image_path=imread(r".\data\山脉.jpg"),
)

去过令你印象最深刻的地方

疫情结束后最想去的地方

Python
# =====绘制疫情结束后最想去的地方词云图=====
df["疫情结束后最想去的地方"].to_csv(r".\data\most_attractive_place.txt", index=False, header=False)
draw_word_cloud(
    text_path=r".\data\most_attractive_place.txt",
    output_path=r".\output\疫情结束后最想去的地方.png",
    outline_image_path=imread(r".\data\山脉.jpg"),
)

疫情结束后最想去的地方

最喜欢的明星或艺术家

Python
# =====绘制最喜欢的明星或艺术家词云图=====
df["最喜欢的明星或艺术家"].to_csv(r".\data\favorite_artist.txt", index=False, header=False)
draw_word_cloud(
    text_path=r".\data\favorite_artist.txt",
    output_path=r".\output\最喜欢的明星或艺术家.png",
    outline_image_path=imread(r".\data\明星.jpg"),
)

最喜欢的明星或艺术家

最喜欢的歌

Python
# =====绘制最喜欢的歌词云图=====
df["最喜欢的歌"].to_csv(r".\data\favorite_song.txt", index=False, header=False)
draw_word_cloud(
    text_path=r".\data\favorite_song.txt",
    output_path=r".\output\最喜欢的歌.png",
    outline_image_path=imread(r".\data\音乐.jpg"),
)

最喜欢的歌

评论