基于python的数据分析工具

文件目录
    data_analysis_app/
    ├── main.py               # 主程序文件,负责启动界面和整体流程
    ├── data_processing.py    # 处理数据的模块,包括读取文件和数据预处理
    ├── plotting.py           # 绘图模块,根据用户选择绘制不同类型的图表
    ├── ui.py                 # 界面设计模块,创建用户界面
    ├── requirements.txt      # 项目依赖的 Python 库列表     
    └── sample.csv          # 用于存放示例数据文件
需要确保已经安装了 Python 环境(建议使用 Python 3.6 及以上版本),并且安装了程序所需的依赖库。上述程序主要依赖于 pandas 和 matplotlib 这两个库。
    创建虚拟环境(可选但推荐)
    为了避免不同项目之间的依赖冲突,你可以创建一个虚拟环境。在命令行中执行以下操作:
    # 创建名为 data_analysis_env 的虚拟环境
        python -m venv data_analysis_env

    # 激活虚拟环境(Windows)
        data_analysis_envScriptsactivate

    # 激活虚拟环境(Linux/Mac)
        source data_analysis_env/bin/activate

    在命令行中,进入 data_analysis_app 目录,然后运行 main.py 文件:  
        cd data_analysis_app
        python main.py
. 使用程序
    选择文件:程序运行后,会弹出一个窗口,点击 “Select File” 按钮,会弹出文件选择对话框,你可以选择要分析的 CSV 或 Excel 文件。
    选择图表类型:通过下拉菜单选择要绘制的图表类型,目前支持 “Bar”(柱状图)和 “Line”(折线图)。
    查看结果:选择好文件和图表类型后,程序会读取文件中的数据,并绘制相应的图表展示分析结果。
5. 退出程序
    关闭绘制的图表窗口后,你可以关闭程序的主窗口来退出程序。如果使用了虚拟环境,在退出程序后,你可以在命令行中执行以下命令来停用虚拟环境:
    # 停用虚拟环境(Windows、Linux/Mac)
        deactivate


要打包 Python 程序,你可以使用pyinstaller这个常用的工具
    安装 pip install pyinstaller

在命令行中,进入到你的项目目录(即包含main.py文件的data_analysis_app目录),然后执行以下命令:
    cd 数据分析/data_analysis_app
    pyinstaller --onefile main.py

主窗口创建

    # 创建按钮框架
    button_frame = tk.Frame(root)
    # 设置按钮框架的位置
    button_frame.grid(row=0, column=0, columnspan=2, sticky=tk.W + tk.E, padx=5, pady=2)

    # 创建打开文件按钮
    open_button = tk.Button(button_frame, text="打开文件", command=select_file)
    # 设置按钮的位置
    open_button.pack(side=tk.LEFT, padx=3)

    # 创建数据清洗按钮
    clean_button = tk.Button(button_frame, text="数据清洗", command=clean_data)
    # 设置按钮的位置
    clean_button.pack(side=tk.LEFT, padx=3)

    chart_types = list(chart_type_mapping.keys())
    # 创建一个StringVar对象,用于存储当前选择的图表类型
    chart_type_var = tk.StringVar(root)
    # 设置默认选择的图表类型为第一个
    chart_type_var.set(chart_types[0])
    # 创建一个OptionMenu对象,用于选择图表类型
    chart_type_menu = tk.OptionMenu(button_frame, chart_type_var, *chart_types, command=update_sub_chart_menu)
    # 将OptionMenu对象放置在button_frame中,并设置位置和间距
    chart_type_menu.pack(side=tk.LEFT, padx=3)

    # 创建一个StringVar对象,用于存储当前选择的子图表类型
    sub_chart_type_var = tk.StringVar(root)
    # 创建一个OptionMenu对象,用于选择子图表类型,初始值为空
    sub_chart_type_menu = tk.OptionMenu(button_frame, sub_chart_type_var, "")
    # 将OptionMenu对象放置在button_frame中,并设置位置和间距
    sub_chart_type_menu.pack(side=tk.LEFT, padx=3)
    # 更新子图表类型菜单
    update_sub_chart_menu()

按钮和菜单创建

 # 创建一个列表,包含数据量的选项
    data_volumes = ["10", "50", "100", "500", "1000", "全部"]
    # 创建一个StringVar对象,用于存储当前选择的数据量
    data_volume_var = tk.StringVar(root)
    # 设置默认选择的数据量为“10”
    data_volume_var.set("10")
    # 创建一个OptionMenu对象,用于选择数据量
    data_volume_menu = tk.OptionMenu(button_frame, data_volume_var, *data_volumes)
    # 将OptionMenu对象放置在button_frame中,并设置位置和间距
    data_volume_menu.pack(side=tk.LEFT, padx=3)

    # 创建一个Button对象,用于生成图表
    generate_button = tk.Button(button_frame, text="生成图像", command=generate_chart)
    # 将Button对象放置在button_frame中,并设置位置和间距
    generate_button.pack(side=tk.LEFT, padx=3)

    # 创建一个Button对象,用于保存图表
    save_button = tk.Button(button_frame, text="保存图像", command=save_image)
    # 将Button对象放置在button_frame中,并设置位置和间距
    save_button.pack(side=tk.LEFT, padx=3)

    # 创建一个Button对象,用于清除显示
    clear_button = tk.Button(button_frame, text="清除显示", command=clear_image)
    # 将Button对象放置在button_frame中,并设置位置和间距
    clear_button.pack(side=tk.LEFT, padx=3)

关键字选择区实现

    # 创建垂直滚动条
    scrollbar = Scrollbar(keyword_scroll_frame, orient=tk.VERTICAL)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    # 创建一个Canvas,用于显示关键字列表
    keyword_frame = tk.Canvas(keyword_scroll_frame, yscrollcommand=scrollbar.set)
    keyword_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    # 将滚动条与Canvas关联
    scrollbar.config(command=keyword_frame.yview)

    # 创建一个Frame,用于放置关键字列表
    inner_frame = tk.Frame(keyword_frame)
    # 将Frame放置在Canvas中
    keyword_window = keyword_frame.create_window((0, 0), window=inner_frame, anchor=tk.NW)

    def configure_canvas(event):
        keyword_frame.update_idletasks()  # 确保所有的布局更新已经完成
        keyword_frame.configure(scrollregion=keyword_frame.bbox("all"))
        keyword_frame.itemconfig(keyword_window, width=keyword_frame.winfo_width())

    inner_frame.bind("<Configure>", configure_canvas)
    keyword_frame.bind("<Configure>", configure_canvas)  # 绑定画布的配置事件

    image_frame = tk.Frame(root)
    image_frame.grid(row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W, padx=5, pady=5)

数据读取实现

import matplotlib.pyplot as plt
import pandas as pd
import os
import sys

# 读取数据文件
def read_data(file_path):
    """
    读取数据文件
    :param file_path: 文件路径
    :return: 读取的数据 DataFrame
    """
    try:
        if getattr(sys, 'frozen', False):
            # 打包后的情况
            base_path = sys._MEIPASS
        else:
            # 开发环境
            base_path = os.path.dirname(os.path.abspath(__file__))

        if file_path == 'sample.csv':
            # 对于 sample.csv 特殊处理
            full_path = os.path.join(base_path, file_path)
        else:
            full_path = file_path

        print(f"尝试读取文件: {full_path}")  # 添加调试信息

        # 以默认方式读取数据
        data = pd.read_csv(full_path)
        return data
    except Exception as e:
        print(f"Error reading data: {e}")
        return None

数据清洗实现

# 去除重复值
def remove_duplicates(data):
    """
    去除重复值
    :param data: 原始数据 DataFrame
    :return: 去除重复值后的数据 DataFrame 和各列重复值数量
    """
    # 避免不必要的数据复制,使用引用
    duplicate_counts = {}
    
    # 使用向量化操作计算统计信息
    total_count = len(data)
    unique_counts = data.nunique()
    duplicate_counts_series = data.apply(lambda x: x.duplicated().sum())
    value_counts_dict = {col: data[col].value_counts().to_dict() for col in data.columns}
    
    # 构建统计信息字典
    duplicate_counts = {
        col: {
            '总数': total_count,
            '唯一值数量': unique_counts[col],
            '重复值数量': duplicate_counts_series[col],
            '值分布': value_counts_dict[col]
        } for col in data.columns
    }
    
    # 直接去除重复行
    deduplicated_data = data.drop_duplicates(keep='first')
    
    return deduplicated_data, duplicate_counts

​​​​​​​图表绘制函数实现

        if chart_type == '柱状图':
            if sub_chart_type == '簇状柱形图':
                plot_data.plot(kind='bar', ax=ax)
            elif sub_chart_type == '堆积柱形图':
                plot_data.plot(kind='bar', stacked=True, ax=ax)
            elif sub_chart_type == '百分比堆积柱形图':
                plot_data_percentage = plot_data.div(plot_data.sum(axis=1), axis=0)
                plot_data_percentage.plot(kind='bar', stacked=True, ax=ax)
        elif chart_type == '折线图':
            if sub_chart_type == '折线图':
                plot_data.plot(kind='line', ax=ax)
            elif sub_chart_type == '堆积折线图':
                plot_data.plot(kind='line', stacked=True, ax=ax)
            elif sub_chart_type == '百分比堆积折线图':
                plot_data_percentage = plot_data.div(plot_data.sum(axis=1), axis=0)
                plot_data_percentage.plot(kind='line', stacked=True, ax=ax)
        elif chart_type == '饼图':
            if sub_chart_type == '饼图':
                plot_data.sum().plot(kind='pie', ax=ax)
            elif sub_chart_type == '圆环图':
                plot_data.sum().plot(kind='pie', ax=ax, wedgeprops=dict(width=0.3))
        elif chart_type == '线条图':
            if sub_chart_type == '单线条图':
                if len(selected_keywords) > 0:
                    plot_data[selected_keywords[0]].plot(kind='line', ax=ax)
            elif sub_chart_type == '多线条图':
                plot_data.plot(kind='line', ax=ax)
        elif chart_type == '面积图':
            if sub_chart_type == '面积图':
                plot_data.plot(kind='area', ax=ax)
            elif sub_chart_type == '堆积面积图':
                plot_data.plot(kind='area', stacked=True, ax=ax)
            elif sub_chart_type == '百分比堆积面积图':
                plot_data_percentage = plot_data.div(plot_data.sum(axis=1), axis=0)
                plot_data_percentage.plot(kind='area', stacked=True, ax=ax)
        elif chart_type == '雷达图':

文字数据处理

# 生成文本频率统计的表格数据
def generate_frequency_table(frequency_stats):
    """
    生成文本频率统计的表格数据
    :param frequency_stats: 文本频率统计结果,字典形式,键为列名,值为该列的频率统计 Series
    :return: 包含所有频率统计信息的 DataFrame
    """
    # 使用列表推导式替代嵌套循环,提高性能
    table_data = [(col, value, freq) 
                 for col, frequency in frequency_stats.items() 
                 for value, freq in frequency.items()]
    # 直接使用table_data创建DataFrame,避免append操作
    return pd.DataFrame(table_data, columns=['Column', 'Value', 'Frequency'])

# 生成文本频率统计的图表
def generate_frequency_chart(frequency_stats, chart_type='bar', sub_chart_type=None):
    """
    生成文本频率统计的图表
    :param frequency_stats: 文本频率统计结果,字典形式,键为列名,值为该列的频率统计 Series
    :param chart_type: 图表类型,默认为柱状图
    :param sub_chart_type: 子图表类型
    :return: 绘制的图表的 Figure 对象
    """
    # 创建图表对象并设置合适的大小
    fig = plt.Figure(figsize=(10, 6), dpi=100)
    ax = fig.add_subplot(111)
    
    # 优化数据转换,直接使用pandas的DataFrame构造
    data = pd.DataFrame(frequency_stats)
    
    # 使用字典映射简化图表类型判断
    plot_params = {
        'bar': {'kind': 'bar'},
        'line': {'kind': 'line'},
        'area': {'kind': 'area'},
        'pie': {'kind': 'pie'}
    }

打包

import os

# 项目根目录
root_dir = os.path.dirname(os.path.abspath(__file__))

# 图标文件路径
icon_path = os.path.join(root_dir, 'icon.ico')

# 主程序入口文件
main_script = os.path.join(root_dir, 'main.py')

# sample.csv 文件路径
sample_csv_path = os.path.join(root_dir, 'sample.csv')

# 需要添加的额外数据
add_data_param = f"{sample_csv_path}{os.pathsep}." if os.name == 'nt' else f"{sample_csv_path}:."

# 排除无关模块,避免打包过大或冲突
excluded_modules = [
    "unittest", "torch", "tensorflow", "PyQt5", "PySide6", "IPython",
    "scipy", "sphinx", "pytest", "docutils", "zmq", "cryptography",
    "lxml", "sympy", "jedi"
]
exclude_modules = " ".join([f"--exclude-module={mod}" for mod in excluded_modules])

# 控制是否显示命令行窗口
no_console = "--noconsole" if os.name == 'nt' else "--windowed"

# 最终打包命令
command = f'pyinstaller --name "数据分析" --icon "{icon_path}" --onefile --add-data "{add_data_param}" {exclude_modules} {no_console} "{main_script}"'

# 打印命令,方便调试
print("打包命令:", command)

# 执行打包
os.system(command)

效果显示 ​​​​​

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容