Python实现分类算法

Python实现分类算法,第1张

前言:出自于学校课程数据挖掘与分析布置的实验小作业,案例经典,代码注释较全,供大家参考。


题目:

现有西瓜挑选数据文件:dataset.txt,编程实现朴素贝叶斯算法,并判断有如下特征的瓜是否好瓜:

青绿,稍蜷,浊响,清晰,凹陷,硬滑。


实验数据如下:


要求:

1、自行采用一种语言编程实现算法(注意:计算条件概率、判别分类等核心算法需自己编程实现)

2、用课堂例子进行正确性检验

3、用户界面友好,要考虑到输入输出

4、分析结果,说明理论分析到数值计算的注意问题

python实现

import sys

# readfile, remove_place, get_conditions, NoneException都是自己封装的方法
from FirstExp.kam import readfile, remove_place, get_conditions, NoneException
import easygui as gui

'''
这里捕获一下异常,文本中的数据如果有空格、空隙则需要处理文本信息
处理数据

数据中的空格,导致的Bug是因为取值的方法不对,
parameters["好瓜"] => parameters[col[columns - 2]] 则不会引起这样的问题
'''
try:
    # 读取txt文件
    df = readfile()
    txt = df.data
    # 获取列数
    columns = txt.shape[1]
    # 算好瓜与坏瓜的概率
    col = txt.columns[1:columns]

    # 好瓜、不好的瓜分别是多少
    parameters = txt[col]
    # 总体为好瓜的个数
    good_num_y = parameters["好瓜"].value_counts()["是"]
    # 总体不是好瓜的个数
    good_num_n = parameters["好瓜"].value_counts()["否"]
    # 是好瓜的概率
    p_y = parameters["好瓜"].value_counts(normalize=True)["是"]
    # 不是好瓜的概率
    p_n = parameters["好瓜"].value_counts(normalize=True)["否"]

    # 获取用户输入条件,如果用户选进行条件选择时,点击了“cancel”,或直接关闭选择框
    # 则会引起异常,给出异常原因
    try:
        conditions = get_conditions(txt)
    except NoneException as e:
        print(e)
        sys.exit(0)

    # 判断条件是否符合要求
    j = 0
    # 临时变量
    yes = 1
    no = 1
    # 使用双层遍历获取各个属性下指定类别的概率
    for i in col[: columns - 2]:
        while j < len(conditions):
            # 满足各个条件为好瓜的数量
            condition_num_y = parameters[(parameters["好瓜"] == "是") & (parameters[i] == conditions[j])].shape[0]
            # 满足各个条件不是好瓜的数量
            condition_num_n = parameters[(parameters["好瓜"] == "否") & (parameters[i] == conditions[j])].shape[0]
            # 使用累乘获取是好瓜的概率
            yes = yes * (condition_num_y / good_num_y)
            # 使用累乘获取不是好瓜的概率
            no = no * (condition_num_n / good_num_n)
            j = j + 1
            # 这里必须添加break,内层循环只需要循环一次
            break
    # 结果是好瓜的概率
    yes = yes * p_y
    # 结果不是好瓜的概率
    no = no * p_n
    yes_msg = "此瓜是好瓜的概率为:" + str(yes) + "\n此瓜不是好瓜的概率为:" + str(no) + "\n所以条件为:" + ",".join(conditions) + "是好瓜"
    no_msg = "此瓜是好瓜的概率为:" + str(yes) + "\n此瓜不是好瓜的概率为:" + str(no) + "\n所以条件为:" + ",".join(conditions) + "不是好瓜"

    if yes > no:
        gui.msgbox(msg=yes_msg, title="结果", ok_button="确认")
    else:
        gui.msgbox(msg=no_msg, title="结果", ok_button="确认")
except KeyError:
    print(remove_place(df.path))

kam.py

"""
用户选择文件,并以矩阵的形式返回
主要思想还是使用pandas库下的read函数
"""
# Author: KamTang
# Date:   November  28, 2021

import os
import time

import pandas as pd
import numpy as np
import tkinter as tk
from tkinter import filedialog
import easygui as gui


class KamData(object):
    """
    自定义返回类

    Parameters
        ----------
        data : 数据部分
        path : 路径
    """

    def __init__(self, data, path):
        self.data = data
        self.path = path


def readfile():
    """
    读取文件
    param select_path:文件路径
    return: 根据文件类型,返回数据
    """
    # 开启选择文件窗口
    root = tk.Tk()
    root.withdraw()
    # 获取选择好的文件
    select_path = filedialog.askopenfilename()
    # 获取文件类型(后缀)
    file_type = os.path.splitext(select_path)[1]
    if file_type == ".csv" or file_type == ".txt":
        data = pd.read_csv(select_path, encoding="utf-8")
        res = KamData(data, select_path)
        return res
    elif file_type == ".excel":
        return pd.read_excel(select_path)
    else:
        return "该文件类型暂时无法读取"


def remove_place(path):
    """
    去除文件中的空格


    Parameters
    ----------
    path : 选择的文件路劲

    Returns
    -------
    new_path : 重新生成的文件路径,基于你所选择的文件位置
    """
    # 获取文件路径
    out_path = path.rsplit("/", 1)[0]
    # 获取文件类型
    file_type = os.path.splitext(path)[1]
    f = open(path, 'r+', encoding='utf-8')
    new_f = open(out_path + "/" + time.strftime('%Y%m%d', time.localtime(time.time())) + file_type, 'w',
                 encoding='utf8')
    for line in f.readlines():
        new_str = line.replace(" ", "")
        new_f.write(new_str)
    f.close()
    new_f.close()
    # 使用字符串拼接获取新文件路径
    new_path = out_path + "/" + time.strftime('%Y%m%d', time.localtime(time.time())) + file_type
    print("由于选择的文件数据存在脏数据,现已重新为您生成与您选择文件数据一致的文件,路径为:")
    return new_path


# 自定义异常
class NoneException(Exception):
    pass


def get_conditions(read_file):
    """
    :param read_file: 读取的文件
    :return: 用户选择的条件
    """
    # 获取列数
    columns = read_file.shape[1]
    # 算好瓜与坏瓜的概率
    col = read_file.columns[1:columns]

    # 好瓜、不好的瓜分别是多少
    parameters = read_file[col]
    conditions = {}
    # 使用字典的形式存入各个类别
    for i in col[: columns - 2]:
        conditions[i] = np.unique(parameters[i].values)
    # 获取所有元素下标
    index = conditions.keys()
    # 存入用户选择的类别
    temp = []
    j = 0
    for i in index:
        while j < len(conditions[i]):
            temp.append(gui.choicebox(msg=i, choices=conditions[i], title="请选择特征"))
            break
    for t in range(len(temp)):
        if temp[t] is None:
            raise NoneException("条件存在漏选,无法分析结果。


") else: return temp

执行流程

选取文件


由于文件的部分数据带有空格,重新为用户生成一份数据一致的临时文件,提示用户选择临时文件(后面已解决该问题,数据中的空格部分不会影响整体结果)

选择瓜的属性:

结果:


总结:

此实验就是自己实现朴素贝叶斯算法,那么就需要求出各个元素的个数,对应真假概率。


我最开始是手动一个一个地将元素对应符合条件的个数取出,再求出概率。


这样没有问题,但是在代码就会显得十分冗余,而且如果数据量十分大,需要取的元素也随之增大,当然这完全能应付这个实验的,但是自己有一点点的强迫症,所以后面使用了循环处理,这样不仅使得代码更加简洁,而且增加了其可读性,也不用再定义那么多参数。



后面又觉得在读取文件时每次需要手动输入文件路径,十分麻烦,索性自己又封装了读取文件的方法,与之前的不同的是,自己封装的是通过窗口选择文件,取代了手动输入路径形式,并且还封装了“清理数据”的方法。


主要思想是如果出现KeyError异常,或者能肯定是读取的文件数据有问题,则重新生成一份文件读取。



在用第一行的标题获取文本最后一列数据时,执行的代码直接报KeyError错误,后来以矩阵的形式输出全部数据,发现个别的数据有空格,所以在读取时,会报错。


那么怎么解决呢?我的想法是我们不能修改原文件,而是重新生成一个临时文件,内部数据完全一致,我们不动原文件,相当于只是一个复制粘贴过程,实质上就是进行了一次“数据清理”。


源码(DMA文件下)

文件获取,提取码:9vw6
界面随便弄的,不要太关注。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/570934.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存