用 Pandas 对抓取的电影数据进行分析

基于上一步搭建 网络机器人 抓取的数据我们进行下一步的数据分析。

如果你刚听到"数据分析"觉得高深莫测,别怕!今天我们将通过一个真实的电影案例,带你一步步拆解代码,浅浅体验一下 Python 数据分析界的大明星------Pandas

我们的目标很清晰:读入一份电影数据,洗一洗脏数据,然后画出 4 张图,看看电影圈到底藏着什么秘密!


第一步:把数据"端上桌" ------ 数据读取

做饭得先买菜,分析数据得先把数据读进来。Pandas 最擅长的事情之一,就是把各种格式的文件变成它认识的对象------ DataFrame(数据框)。你可以把它想象成一张超级加强版的 Excel 表格。

python 复制代码
import pandas as pd
import matplotlib.pyplot as plt

def main():
    # 读取数据
    # pd.read_csv: Pandas的读文件神器,一行代码把CSV变成DataFrame
    # usecols: 就像在餐厅点菜,原表格列很多,我们只提取需要分析的这7列,省时省力
    # dtype: 提前告诉Pandas,"年份"这列请用Int64(整数)类型对待,不要当成纯文本
    df = pd.read_csv('data/movie.csv', 
                     usecols=["电影名","年份","上映时间","类型","时长","评分","语言"], 
                     dtype={"年份": "Int64"})

第二步:给数据"洗个澡" ------ 缺失值处理

现实中的数据往往很脏,比如有些老电影连"年份"都没填。如果我们想看历年电影数量变化,有空缺可不行。

我们的策略是:如果"年份"为空,就从"上映时间"(如 1994-01-01)里截取前 4 位作为替补。

python 复制代码
    # 展示中文: 如果不设置这行,图表里的中文标题会变成方块口口口
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 创建画布: nrows=2, ncols=2 表示画一个2行2列的网格,放4张图
    # figsize=(15, 10) 设置画布宽15英寸,高10英寸
    # gridspec_kw={'hspace': 0.5, 'wspace': 0.4} 设置子图之间的高度和宽度留白,防止挤在一起
    fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(15, 10), gridspec_kw={'hspace': 0.5, 'wspace': 0.4})

    # 设置整个大画布的顶部大标题
    fig.suptitle('电影数据统计', fontsize=16, x=0.5, y=0.92)

    # axes是一个2x2的数组,我们分别把它们取出来,方便后面画图时调用
    axes1 = axes[0, 0] # 第1行第1列
    axes2 = axes[0, 1] # 第1行第2列
    axes3 = axes[1, 0] # 第2行第1列
    axes4 = axes[1, 1] # 第2行第2列

    # --- 数据清洗:处理年份缺失 ---
    # astype(str): 先把上映时间列转成字符串格式
    # .str[:4]: 使用Pandas的字符串切片方法,截取前4个字符(即年份,如"1994")
    extracted_year = df['上映时间'].astype(str).str[:4]
    
    # fillna: 神奇的填充函数。它自动检查df['年份'],哪里是空,就用对应行的extracted_year填上;哪里有值,就保留原样
    df['年份'] = df['年份'].fillna(extracted_year)

💡 Pandas 哲学初体验:向量化操作 在传统编程中,你想对一列数据做处理,得写 for 循环挨个判断。但在 Pandas 里,你直接对整列(Series)下达指令(如 .fillna),它会在底层瞬间帮你搞定所有行,这就叫"向量化",不仅代码优雅,速度还快得飞起!


第三步:让数据"开口说话" ------ 统计与可视化

数据洗干净了,接下来进入正题:统计画图。

📈 图 1:历年电影数量变化(折线图)

想知道电影产业是不是越来越繁荣?我们需要按年份统计电影数量,并确保年份是连续的。

python 复制代码
    # --- 图1:折线图 ---
    # groupby('年份'): 把电影按年份分装进不同的"文件夹"
    # ['电影名'].count(): 数一下每个"文件夹"里有几部电影
    year_count = df.groupby('年份')['电影名'].count()

    # year_count是一个带标签的Series,标签是年份,值是数量
    # .index.min() 获取标签的最小值(最早年份),.index.max() 获取最大值(最新年份)
    min_year = year_count.index.min()
    max_year = year_count.index.max()

    # 生成X轴数据:从最早年份到最新年份的连续整数列表,确保折线图时间轴不断裂
    x = [i for i in range(min_year, max_year + 1)]
    
    # 生成Y轴数据:遍历连续的年份x,去year_count里取数量
    # .get(i, 0) 的意思是:获取年份i的数量,如果找不到(说明这年没电影),就返回0填补
    y = [int(year_count.get(i, 0)) for i in x]

    # 绘制折线图:linestyle='-'表示实线,color='green'表示绿色
    axes1.plot(x, y, linestyle='-', color='green')
    axes1.set_title('每一年上映的电影数量的变化')
    axes1.set_xlabel('年份')
    axes1.set_ylabel('数量')
    axes1.grid(True, linestyle='--', alpha=0.5) # 添加虚线网格,透明度0.5,方便对齐看数
    
    # x[::8]: 列表切片步长为8,表示每隔8个年份才显示一个刻度,防止X轴挤满数字
    axes1.set_xticks(x[::8])
    # range(0, 31, 3): 从0到30,步长为3,表示每隔3个数量显示一个刻度
    axes1.set_yticks([i for i in range(0, 31, 3)])

📊 图 2:不同语言电影数量(柱状图)

这次我们用更简练的 Pandas 风格一步到位:

python 复制代码
    # --- 图2:柱状图 ---
    # 分组、计数、画图一气呵成!
    # kind='bar': 画柱状图
    # ax=axes2: 把图画到第2个子图区域
    df.groupby('语言')['电影名'].count().plot(kind='bar', ax=axes2)
    axes2.set_title('不同语言电影数量')
    axes2.set_xlabel('语言')
    axes2.set_ylabel('数量')
    axes2.grid(True, linestyle='--', alpha=0.5)

📊 图 3:不同类型电影数量(嵌套数据的破局之法)

图 2 的语言很简单,因为一部电影通常只有一种语言。但"类型"不同,一部电影往往是 "剧情,动作,科幻" 混合体。如果直接用 value_counts,Pandas 会把整个字符串当成一种类型。

这时候,我们不得不暂时告别向量化,请出基础的 for 循环来拆分数据:

python 复制代码
    # --- 图3:柱状图(多标签拆分) ---
    count_types={}
    # 第一层循环:遍历df['类型']的每一行,type是一个字符串,如"剧情,动作"
    for type in df['类型']:
        # 第二层循环:用split(',')按逗号把字符串拆成列表,遍历每一个具体类型
        for t in type.split(','):
            # 如果这个类型t还没在字典里,初始化为1;如果已经有了,数量+1
            if t not in count_types:
                count_types[t] = 1
            else:
                count_types[t] += 1

    # 画柱状图:X轴是字典的键,Y轴是字典的值
    axes3.bar(count_types.keys(), count_types.values())
    axes3.set_title('不同类型电影数量')
    axes3.set_xlabel('类型')
    
    # 必须先设置刻度位置,再设置刻度标签!
    # range(len(count_types)): 生成0,1,2...的刻度位置
    axes3.set_xticks(range(len(count_types)))
    # rotation=45: 标签旋转45度,防止文字重叠
    axes3.set_xticklabels(count_types.keys(), rotation=45)
    axes3.set_ylabel('数量')
    axes3.grid(True, linestyle='--', alpha=0.5)

何时用循环? 当数据格式本身需要"拆解重组",且 Pandas 没有提供直接的向量化方法时,回归循环是务实的选择。

🍕 图 4:电影评分比例(饼图与数据合并)

评分种类太多,饼图会密密麻麻看不清。我们需要把占比极小的评分合并为"其他"。

python 复制代码
    # --- 图4:饼状图 ---
    # value_counts(): 专门用来数各类值出现次数的统计神器
    score_counts = df['评分'].value_counts()

    # 计算比例:每类数量除以总数量
    score_percentage = score_counts / score_counts.sum()

    # 条件筛选:score_percentage < 0.05 会返回一串True/False
    # 用它去切片Series,挑出占比小于5%的项,并取出它们的索引(即具体评分值)
    other_scores = score_percentage[score_percentage < 0.05].index

    # apply + lambda: Pandas里的"微创手术"
    # lambda是匿名函数,这行的意思是:遍历每行的评分x,如果x在小比例名单里,就改成"其他",不然保留原样
    df['处理后评分'] = df['评分'].apply(lambda x: '其他' if x in other_scores else x)

    # 对处理后的新列重新统计数量
    processed_counts = df['处理后评分'].value_counts()

    # 画饼图:autopct='%1.1f%%' 表示显示百分比,保留1位小数
    axes4.pie(processed_counts, labels=processed_counts.index, autopct='%1.1f%%')
    axes4.set_title('各个电影评分的比例')
    # loc='lower center': 图例放在底部中间;bbox_to_anchor: 精细调整图例的位置,防止挡住饼图
    axes4.legend(loc='lower center', ncol=5, bbox_to_anchor=(0.5, -0.2))

第四步:收尾保存

图表画完了,最后一步是把成果保存下来,并展示给用户看。

python 复制代码
    # 将绘制好的4合1图表保存为当前目录下的png图片
    plt.savefig('movie.png')

    # 在屏幕上弹出窗口展示图表
    plt.show()

# Python的标准入口写法:只有当直接运行这个脚本时,才会执行main()函数
if __name__ == '__main__':
    main()

总结

回顾这份代码,我们经历了:

  1. 读取:将杂乱文件变成规整的 DataFrame。
  2. 清洗 :用 fillna 搞定缺失值。
  3. 分析 :用 groupbyvalue_counts 从不同维度透视数据,遇到复杂拆分灵活运用循环。
  4. 展现:用 Matplotlib 将枯燥的数字变成直观的折线、柱状和饼图。

这就是 Pandas 的魅力所在:它让你能像拼积木一样,用极少的代码完成从数据到洞察的完整闭环。希望这次浅浅的体验,能为你推开数据分析的大门!

相关推荐
人工干智能3 小时前
科普:pandas 时间偏移别名:ts.resample(“5Min“).sum()
python·pandas
benchmark_cc5 天前
批量获取量化数据时,如何设置合理的超时和重试机制?——QuantDash 高性能实战指南
开发语言·人工智能·python·pandas·量化·quantdash
2601_966949655 天前
使用 Pandas 读取批量数据时如何避免内存溢出?QuantDash 量化数据工程师避坑指南
开发语言·python·pandas·tushare·akshare·quantdash
三十岁老牛再出发6 天前
08.18每日总结
c++·python·numpy·pandas
虎头金猫9 天前
如何在群晖NAS上通过Docker部署CloudSaver?群晖部署CloudSaver教程|聚合资源搜索并实现远程访问
运维·服务器·网络·python·docker·容器·pandas
Uncommon.10 天前
使用pandas处理csv并转为张量
pytorch·python·深度学习·pandas
STR_Liang12 天前
pandas.read_html 报错FileNotFoundError、OSError Traceback (most recent call last)
pandas
㳺三才人子13 天前
初探 Data Analysis - Matplotlib
python·plotly·pandas·matplotlib
quantdash_cc14 天前
告别自建 Requests/BS4 网页爬虫:基于 QuantDash 搭建零维保的高性能量化行情流水线
开发语言·爬虫·python·pandas·量化·quantdash