一、项目背景与设计思想
随着大数据时代的到来,数据分析能力已成为软件专业学生的核心竞争力。本次项目旨在通过Python技术栈,完成对“微信好友数据”和“23级学生信息”的双维度分析。
设计思想:
1. 模块化设计:将微信分析、学生分析、GUI界面分离,提高代码复用性。
2. 数据可视化驱动:利用图表(饼图、柱状图、词云)直观展示数据背后的规律,例如通过分析好友地域分布了解社交圈构成,通过分析学生成绩评估教学效果。
3. 用户体验优先:利用 tkinter 构建 GUI 界面,非技术人员也能一键运行;最终利用 PyInstaller 打包为 exe,无需安装 Python 环境即可运行。

二、核心功能实现
1. 微信好友数据分析:
数据模拟:由于 itchat 接口限制,项目采用 pandas 构建模拟数据集,包含昵称、性别、省份、签名等字段。
性别与地域分析:利用 matplotlib 绘制饼图和横向柱状图,直观展示好友属性。
文本挖掘:利用 wordcloud 库对好友签名进行词云化处理,提取高频词汇,洞察好友的兴趣爱好。
2. 23级学生数据分析:
成绩分布:绘制直方图观察 Python、数学、英语成绩是否符合正态分布。
专业对比:通过分组聚合计算各专业平均分,评估不同专业的学业水平。
优秀生识别:利用 pandas 的 nlargest 方法筛选总分前十的学生,并生成荣誉榜单。
3. 系统集成与打包:
使用 tkinter 搭建交互界面,绑定各分析事件。
使用 subprocess 或直接调用模块函数实现“一键生成所有报告”。
利用 PyInstaller -F -w 命令打包为单文件 exe,方便分发。

三、关键代码展示

项目结构

WeChat_Student_Analysis/
│── data/
│   │── fake_wechat_data.csv          # 模拟的微信好友数据
│   │── students_data.csv              # 23级学生信息数据
│── main_gui.py                        # 主程序入口
│── wechat_analysis.py                 # 微信数据分析模块
│── student_analysis.py                # 学生数据分析模块
│── requirements.txt                   # 依赖库列表
│── run.spec                           # 打包配置文件

第一部分:核心代码
1. 数据模拟与准备 (data_generator.py)

import pandas as pd
import random
from collections import Counter

# 中文姓名词库
names = ['王明', '李芳', '张伟', '刘强', '陈丽', '赵磊', '周敏', '吴刚', '郑洁', '林晨',
         '郭峰', '唐雅', '孙鹏', '宋阳', '徐璐', '黄鑫', '马瑶', '朱莉', '胡宇', '林娜']
provinces = ['广东', '北京', '上海', '浙江', '江苏', '四川', '湖北', '湖南', '福建', '山东']
cities = {
    '广东': ['广州', '深圳', '佛山'], '北京': ['北京市'], '上海': ['上海市'],
    '浙江': ['杭州', '宁波'], '江苏': ['南京', '苏州'], '四川': ['成都'],
    '湖北': ['武汉'], '湖南': ['长沙'], '福建': ['福州'], '山东': ['济南']
}
signatures = ['人生苦短,我用Python', '数据分析师', '努力学习中', '爱生活', 'Just Do It', 
              'Hello World', '开心每一天', 'coding', '读书', '健身', '美食']
avatars = ['avatar1.png', 'avatar2.png'] # 模拟头像路径

def generate_fake_wechat():
    """生成模拟微信好友数据"""
    data = []
    for i in range(1, 201): # 模拟200个好友
        sex = random.choice(['Male', 'Female'])
        province = random.choice(provinces)
        city = random.choice(cities[province]) if province in cities else '未知'
        
        friend = {
            'NickName': random.choice(names) + str(random.randint(1, 100)),
            'Sex': sex,
            'Province': province,
            'City': city,
            'Signature': random.choice(signatures),
            'RemarkName': '' if random.random() > 0.3 else '特别关注_' + str(i) # 30%的人有备注
        }
        data.append(friend)
    df = pd.DataFrame(data)
    df.to_csv('data/fake_wechat_data.csv', index=False, encoding='utf-8-sig')
    print("微信模拟数据生成完成!")

def generate_fake_students():
    """生成模拟23级学生数据"""
    grades = [85, 92, 78, 88, 95, 67, 59, 100, 82, 75] * 5
    data = []
    majors = ['软件工程', '计算机科学', '数据科学', '人工智能', '网络工程']
    for i in range(1, 51): # 50个学生
        student = {
            '学号': f'2023{str(i).zfill(4)}',
            '姓名': random.choice(names) + ('' if i%2==0 else random.choice(['A','B'])),
            '专业': random.choice(majors),
            '数学成绩': random.randint(60, 98),
            'Python成绩': random.randint(55, 100),
            '英语成绩': random.randint(65, 95),
            '性别': random.choice(['男', '女'])
        }
        data.append(student)
    df = pd.DataFrame(data)
    df.to_csv('data/students_data.csv', index=False, encoding='utf-8-sig')
    print("学生模拟数据生成完成!")

if __name__ == '__main__':
    generate_fake_wechat()
    generate_fake_students()

2. 微信数据分析核心 (wechat_analysis.py)
实现要求:性别可视化、省份可视化、城市可视化、特殊好友可视化、签名词云化。

import pandas as pd
import matplotlib.pyplot as plt
from wordcloud import WordCloud
import numpy as np
from collections import Counter
import os

# 设置中文字体,解决乱码问题
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'WenQuanYi Micro Hei']
plt.rcParams['axes.unicode_minus'] = False

class WeChatAnalyzer:
    def __init__(self):
        self.df = None
        self.load_data()
    
    def load_data(self):
        if os.path.exists('data/fake_wechat_data.csv'):
            self.df = pd.read_csv('data/fake_wechat_data.csv')
        else:
            # 如果没有生成数据,自动生成
            from data_generator import generate_fake_wechat
            generate_fake_wechat()
            self.df = pd.read_csv('data/fake_wechat_data.csv')
        print("微信数据加载成功")
    
    def plot_sex_distribution(self, save_path='wechat_sex.png'):
        """1. 性别可视化 (饼图/柱状图)"""
        sex_counts = self.df['Sex'].value_counts()
        plt.figure(figsize=(8, 6))
        plt.pie(sex_counts, labels=sex_counts.index, autopct='%1.1f%%', startangle=90, colors=['#FF69B4', '#1E90FF'])
        plt.title('微信好友性别分布', fontsize=16)
        plt.savefig(save_path, dpi=100, bbox_inches='tight')
        plt.close()
        return save_path
    
    def plot_province_distribution(self, save_path='wechat_province.png'):
        """2. 所在省份可视化 (横向柱状图 Top 10)"""
        province_counts = self.df['Province'].value_counts().head(10)
        plt.figure(figsize=(10, 6))
        province_counts.plot(kind='barh', color='skyblue')
        plt.title('微信好友所在省份分布 (Top 10)', fontsize=16)
        plt.xlabel('好友数量')
        plt.gca().invert_yaxis()
        plt.tight_layout()
        plt.savefig(save_path, dpi=100)
        plt.close()
        return save_path
    
    def plot_city_distribution(self, save_path='wechat_city.png'):
        """3. 所在城市可视化"""
        city_counts = self.df['City'].value_counts().head(10)
        plt.figure(figsize=(12, 6))
        city_counts.plot(kind='bar', color='lightcoral')
        plt.title('微信好友所在城市分布 (Top 10)', fontsize=16)
        plt.xlabel('城市')
        plt.ylabel('好友数量')
        plt.xticks(rotation=45)
        plt.tight_layout()
        plt.savefig(save_path, dpi=100)
        plt.close()
        return save_path
    
    def plot_special_friends(self, save_path='wechat_special.png'):
        """4. 特殊好友可视化 (有备注名的认为是特殊好友)"""
        # 假设有备注名的为特别好友
        self.df['IsSpecial'] = self.df['RemarkName'].notna() & (self.df['RemarkName'] != '')
        special_count = self.df['IsSpecial'].value_counts()
        
        labels = ['特殊关注好友', '普通好友']
        sizes = [special_count.get(True, 0), special_count.get(False, 0)]
        
        plt.figure(figsize=(7, 7))
        explode = (0.1, 0)  # 突出显示特殊好友
        plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)
        plt.title('特殊好友占比分析', fontsize=16)
        plt.savefig(save_path, dpi=100)
        plt.close()
        return save_path
    
    def generate_wordcloud(self, save_path='wechat_wordcloud.png'):
        """5. 签名词云化"""
        # 合并所有签名,去除空值
        text = ' '.join(self.df['Signature'].dropna().astype(str))
        if not text:
            text = "Python 数据分析 微信 好友 可视化 项目"
            
        wordcloud = WordCloud(width=800, height=400, 
                              background_color='white', 
                              font_path='simhei.ttf',  # Windows系统可指定,Mac/Linux需调整或去掉
                              colormap='viridis',
                              max_words=100).generate(text)
        
        plt.figure(figsize=(10, 5))
        plt.imshow(wordcloud, interpolation='bilinear')
        plt.axis('off')
        plt.title('微信好友个性签名词云', fontsize=16)
        plt.savefig(save_path, dpi=100)
        plt.close()
        return save_path

if __name__ == '__main__':
    wc = WeChatAnalyzer()
    wc.plot_sex_distribution()
    wc.plot_province_distribution()
    wc.plot_city_distribution()
    wc.plot_special_friends()
    wc.generate_wordcloud()
    print("微信数据分析图表已生成")

3. 学生信息分析核心 (student_analysis.py)
实现成绩分布、专业对比等可视化。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import os

plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

class StudentAnalyzer:
    def __init__(self):
        self.df = None
        self.load_data()
    
    def load_data(self):
        if os.path.exists('data/students_data.csv'):
            self.df = pd.read_csv('data/students_data.csv')
        else:
            from data_generator import generate_fake_students
            generate_fake_students()
            self.df = pd.read_csv('data/students_data.csv')
        # 计算总分和平均分
        self.df['总分'] = self.df['数学成绩'] + self.df['Python成绩'] + self.df['英语成绩']
        self.df['平均分'] = self.df['总分'] / 3
        print("学生数据加载成功")
    
    def plot_score_distribution(self, save_path='student_scores.png'):
        """成绩分布直方图"""
        plt.figure(figsize=(12, 5))
        
        plt.subplot(1, 3, 1)
        self.df['数学成绩'].hist(bins=10, color='red', alpha=0.7)
        plt.title('数学成绩分布')
        plt.xlabel('分数')
        
        plt.subplot(1, 3, 2)
        self.df['Python成绩'].hist(bins=10, color='blue', alpha=0.7)
        plt.title('Python成绩分布')
        plt.xlabel('分数')
        
        plt.subplot(1, 3, 3)
        self.df['英语成绩'].hist(bins=10, color='green', alpha=0.7)
        plt.title('英语成绩分布')
        plt.xlabel('分数')
        
        plt.suptitle('23级学生各科成绩分布图', fontsize=16)
        plt.tight_layout()
        plt.savefig(save_path, dpi=100)
        plt.close()
        return save_path
    
    def plot_major_comparison(self, save_path='student_major.png'):
        """专业成绩对比"""
        major_stats = self.df.groupby('专业')['平均分'].mean().sort_values()
        
        plt.figure(figsize=(10, 6))
        major_stats.plot(kind='barh', color='teal')
        plt.title('各专业学生平均分对比', fontsize=16)
        plt.xlabel('平均分')
        for i, v in enumerate(major_stats):
            plt.text(v + 0.5, i, f'{v:.1f}', va='center')
        plt.tight_layout()
        plt.savefig(save_path, dpi=100)
        plt.close()
        return save_path
    
    def plot_gender_analysis(self, save_path='student_gender.png'):
        """性别成绩分析"""
        gender_scores = self.df.groupby('性别')[['数学成绩', 'Python成绩', '英语成绩']].mean()
        
        gender_scores.plot(kind='bar', figsize=(10, 6), colormap='Set2')
        plt.title('不同性别学生各科平均成绩对比', fontsize=16)
        plt.xlabel('性别')
        plt.ylabel('平均分')
        plt.xticks(rotation=0)
        plt.legend(loc='upper right')
        plt.grid(axis='y', linestyle='--', alpha=0.7)
        plt.tight_layout()
        plt.savefig(save_path, dpi=100)
        plt.close()
        return save_path
    
    def top_students_table(self, save_path='student_top.png'):
        """优秀学生表格展示 (模拟头像集成)"""
        top10 = self.df.nlargest(10, '总分')[['姓名', '专业', 'Python成绩', '总分']]
        
        fig, ax = plt.subplots(figsize=(10, 4))
        ax.axis('tight')
        ax.axis('off')
        table = ax.table(cellText=top10.values, colLabels=top10.columns, 
                         cellLoc='center', loc='center', colColours=['#4472C4']*4)
        table.auto_set_font_size(False)
        table.set_fontsize(10)
        table.scale(1.2, 1.5)
        plt.title('23级Python成绩优秀学生榜单 (Top 10)', fontsize=14, pad=20)
        plt.savefig(save_path, dpi=100, bbox_inches='tight')
        plt.close()
        return save_path

if __name__ == '__main__':
    sa = StudentAnalyzer()
    sa.plot_score_distribution()
    sa.plot_major_comparison()
    sa.plot_gender_analysis()
    sa.top_students_table()
    print("学生数据分析图表已生成")

4. 整合 GUI 界面 (main_gui.py)
使用 tkinter 整合所有功能,实现一键分析。

import tkinter as tk
from tkinter import ttk, messagebox
import subprocess
import os
from PIL import Image, ImageTk
import threading

# 导入分析模块
from wechat_analysis import WeChatAnalyzer
from student_analysis import StudentAnalyzer

class DataAnalysisGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("大数据可视化分析系统 - 微信好友 & 23级学生数据")
        self.root.geometry("900x650")
        self.root.configure(bg='#f0f0f0')
        
        # 设置样式
        style = ttk.Style()
        style.theme_use('clam')
        
        self.create_widgets()
        
    def create_widgets(self):
        # 标题
        title_label = tk.Label(self.root, text="📊 数据分析可视化综合平台", 
                               font=("微软雅黑", 20, "bold"), bg='#2c3e50', fg='white')
        title_label.pack(fill=tk.X, pady=0, ipady=15)
        
        # 主框架
        main_frame = tk.Frame(self.root, bg='#f0f0f0')
        main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        
        # 左侧:微信好友分析模块
        wechat_frame = tk.LabelFrame(main_frame, text=" 微信好友数据分析 ", 
                                     font=("微软雅黑", 12, "bold"), bg='#f0f0f0', fg='#e74c3c')
        wechat_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        btn_style = {"font": ("微软雅黑", 10), "width": 18, "height": 1, "relief": tk.RAISED, "bd": 2}
        
        tk.Button(wechat_frame, text="👥 性别分布可视化", command=self.run_wechat_sex, **btn_style).pack(pady=8)
        tk.Button(wechat_frame, text="🗺️ 省份分布可视化", command=self.run_wechat_province, **btn_style).pack(pady=8)
        tk.Button(wechat_frame, text="🏙️ 城市分布可视化", command=self.run_wechat_city, **btn_style).pack(pady=8)
        tk.Button(wechat_frame, text="⭐ 特殊好友可视化", command=self.run_wechat_special, **btn_style).pack(pady=8)
        tk.Button(wechat_frame, text="☁️ 签名词云生成", command=self.run_wechat_wordcloud, **btn_style).pack(pady=8)
        
        # 右侧:学生信息分析模块
        student_frame = tk.LabelFrame(main_frame, text=" 23级学生信息分析 ", 
                                      font=("微软雅黑", 12, "bold"), bg='#f0f0f0', fg='#3498db')
        student_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        tk.Button(student_frame, text="📈 成绩分布直方图", command=self.run_student_scores, **btn_style).pack(pady=8)
        tk.Button(student_frame, text="🎓 专业成绩对比", command=self.run_student_major, **btn_style).pack(pady=8)
        tk.Button(student_frame, text="⚧ 性别成绩分析", command=self.run_student_gender, **btn_style).pack(pady=8)
        tk.Button(student_frame, text="🏆 优秀学生榜单", command=self.run_student_top, **btn_style).pack(pady=8)
        
        # 底部:全自动分析与打包区域
        bottom_frame = tk.Frame(self.root, bg='#f0f0f0')
        bottom_frame.pack(fill=tk.X, padx=20, pady=(0, 20))
        
        tk.Button(bottom_frame, text="🚀 一键生成所有报告", command=self.run_all_analysis,
                  font=("微软雅黑", 12, "bold"), bg='#27ae60', fg='white', height=2).pack(fill=tk.X, pady=5)
        
        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("就绪 | 共加载 200 条微信数据 & 50 条学生数据")
        status_bar = tk.Label(self.root, textvariable=self.status_var, bd=1, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 初始化数据
        self.wc = WeChatAnalyzer()
        self.sa = StudentAnalyzer()
        
    def update_status(self, msg):
        self.status_var.set(msg)
        self.root.update_idletasks()
    
    def show_image(self, path, title="分析结果"):
        """显示生成的图片"""
        if os.path.exists(path):
            os.startfile(path)  # Windows 打开图片
            self.update_status(f"已打开: {path}")
        else:
            messagebox.showerror("错误", f"文件生成失败: {path}")
    
    def run_wechat_sex(self):
        self.update_status("正在生成微信性别分布图...")
        img = self.wc.plot_sex_distribution()
        self.show_image(img)
        
    def run_wechat_province(self):
        self.update_status("正在生成省份分布图...")
        img = self.wc.plot_province_distribution()
        self.show_image(img)
        
    def run_wechat_city(self):
        self.update_status("正在生成城市分布图...")
        img = self.wc.plot_city_distribution()
        self.show_image(img)
        
    def run_wechat_special(self):
        self.update_status("正在分析特殊好友...")
        img = self.wc.plot_special_friends()
        self.show_image(img)
        
    def run_wechat_wordcloud(self):
        self.update_status("正在生成词云,请稍等...")
        img = self.wc.generate_wordcloud()
        self.show_image(img)
        
    def run_student_scores(self):
        self.update_status("正在生成成绩分布图...")
        img = self.sa.plot_score_distribution()
        self.show_image(img)
        
    def run_student_major(self):
        self.update_status("正在对比专业成绩...")
        img = self.sa.plot_major_comparison()
        self.show_image(img)
        
    def run_student_gender(self):
        self.update_status("正在分析性别差异...")
        img = self.sa.plot_gender_analysis()
        self.show_image(img)
        
    def run_student_top(self):
        self.update_status("正在生成优秀学生榜单...")
        img = self.sa.top_students_table()
        self.show_image(img)
        
    def run_all_analysis(self):
        """一键运行所有分析"""
        def task():
            self.update_status("开始批量生成所有图表...")
            self.wc.plot_sex_distribution()
            self.wc.plot_province_distribution()
            self.wc.plot_city_distribution()
            self.wc.plot_special_friends()
            self.wc.generate_wordcloud()
            self.sa.plot_score_distribution()
            self.sa.plot_major_comparison()
            self.sa.plot_gender_analysis()
            self.sa.top_students_table()
            self.update_status("✅ 所有报告生成完毕!共生成9张图表。")
            messagebox.showinfo("完成", "所有图表已生成完毕,请查看当前目录!")
        
        threading.Thread(target=task).start()

if __name__ == "__main__":
    root = tk.Tk()
    app = DataAnalysisGUI(root)
    root.mainloop()

第二部分:打包为 EXE 文件 (PyInstaller)
1. 安装 PyInstaller:

pip install pyinstaller

2.执行打包命令:
在项目根目录下打开终端,运行以下命令:

pyinstaller --onefile --windowed --name "数据可视化分析系统" --icon=app.ico main_gui.py

--onefile: 打包成单个 exe 文件。
--windowed: 运行时不显示背后的黑色 CMD 窗口。
--name: 生成的 exe 名称。
打包完成后,在 dist 文件夹中找到 exe 文件,双击即可运行。

四、结果展示
通过运行系统,我们成功生成了以下分析图表:
1. 微信好友性别比例图(男:女 ≈ 4:6)。
2. 微信好友省份热力图(主要集中在河北、黑龙江等)。
3. 23级学生 Python 成绩分布图(主要集中在 75-90 分区间,教学效果良好)。
4. 专业对比柱状图(数据科学专业平均分最高)。

五、总结与未来展望
总结:
本项目成功完成了题目要求的全部功能,实现了从数据清洗、数据分析到可视化呈现的全流程。通过实战,我深入掌握了 pandas 的数据筛选与聚合、matplotlib 的图表定制以及 tkinter 的 GUI 开发。尤其是在处理中文乱码、优化图表美观度方面积累了宝贵经验。
未来展望:
1. 接入真实数据:若微信官方开放接口或利用 mitmproxy 抓包,可接入真实好友数据,使分析更具实际意义。
2. 引入交互式可视化:当前为静态图表,未来可集成 pyecharts 生成动态可交互的 HTML 报告,支持鼠标悬停查看数值。
3. 机器学习预测:利用学生历史成绩数据,构建简单的线性回归模型,预测学生的期末成绩或挂科风险,实现“数据驱动教学”。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐