import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
import numpy as np
import re
import random
import pickle
# 定义一个朴素贝叶斯分类器类
class NaiveBayesClassifier:
def __init__(self):
self.word_freq_male = {}
self.word_freq_female = {}
self.prob_male = 0
self.prob_female = 0
self.vocab = set()
# 定义 train() 方法,接收训练数据作为参数
def train(self, training_data):
male_names = []
female_names = []
# 从训练数据中分离男性和女性名字
for line in training_data:
name, gender = line.strip().split('\t')
if gender == '男':
male_names.append(name)
elif gender == '女':
female_names.append(name)
# 计算先验概率
self.prob_male = len(male_names) / len(training_data)
self.prob_female = len(female_names) / len(training_data)
# 计算每个字符在男性和女性名字中的频率
for name in male_names:
for char in name:
if char in self.word_freq_male:
self.word_freq_male[char] += 1
else:
self.word_freq_male[char] = 1
self.vocab.add(char)
for name in female_names:
for char in name:
if char in self.word_freq_female:
self.word_freq_female[char] += 1
else:
self.word_freq_female[char] = 1
self.vocab.add(char)
# 对每个字符应用加一平滑
for char in self.vocab:
if char not in self.word_freq_male:
self.word_freq_male[char] = 1
if char not in self.word_freq_female:
self.word_freq_female[char] = 1
# 标准化字符频率
male_total = sum(self.word_freq_male.values())
female_total = sum(self.word_freq_female.values())
for char in self.vocab:
self.word_freq_male[char] /= male_total
self.word_freq_female[char] /= female_total
# 定义 predict() 方法,接收一个名字作为参数
def predict(self, name):
male_score = np.log(self.prob_male)
female_score = np.log(self.prob_female)
# 计算名字在男性和女性中的得分
for char in name:
if char in self.vocab:
male_score += np.log(self.word_freq_male[char])
female_score += np.log(self.word_freq_female[char])
# 返回得分较高的性别
if male_score > female_score:
return '男'
else:
return '女'
# 定义 save_model() 方法,用于将训练好的模型保存到文件
def save_model(self, file_path):
with open(file_path, "wb") as f:
pickle.dump(self, f)
# 定义一个类方法 load_model(),用于从文件加载模型
@classmethod
def load_model(cls, file_path):
with open(file_path, "rb") as f:
return pickle.load(f)
# 定义一个 Application 类,用于构建和控制 Tkinter 应用程序
class Application:
def __init__(self, master):
self.master = master
master.title("名字性别判断系统")
# 创建星空背景
self.create_starry_background()
# 配置 ttk 组件的样式
style = ttk.Style()
style.configure("TLabel", font=("Helvetica", 12))
style.configure("TButton", font=("Helvetica", 12))
self.frame = tk.Frame(self.canvas, padx=10, pady=10, background="#F0F0F0")
self.frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 创建输入框和标签
self.label_name = ttk.Label(self.frame, text="请输入名字:", background="#F0F0F0")
self.input_name = ttk.Entry(self.frame, width=20)
self.label_name.grid(row=0, column=0, sticky=tk.W)
self.input_name.grid(row=0, column=1, sticky=tk.W)
# 创建预测按钮
self.button_predict = ttk.Button(self.frame, text="预测性别", command=self.predict_gender)
self.button_predict.grid(row=1, column=0, columnspan=2)
# 创建批量预测按钮
self.button_batch_predict = ttk.Button(self.frame, text="批量预测性别", command=self.batch_predict_gender)
self.button_batch_predict.grid(row=2, column=0, columnspan=2)
# 创建结果显示标签
self.label_result = ttk.Label(self.frame, text="", background="#F0F0F0")
self.label_result.grid(row=3, column=0, columnspan=2)
def create_starry_background(self):
self.canvas = tk.Canvas(self.master, width=350, height=150)
self.canvas.pack(fill=tk.BOTH, expand=True)
# 创建渐变背景
for i in range(150):
color = "#{:02x}{:02x}{:02x}".format(0, 0, int(255 * i / 149))
self.canvas.create_line(0, i, 350, i, fill=color)
# 创建星空背景
for _ in range(100):
x = random.randint(0, 350)
y = random.randint(0, 150)
size = random.randint(1, 3)
self.canvas.create_oval(x, y, x + size, y + size, fill="white")
# 适应窗口大小
self.master.bind('<Configure>', self.update_canvas_size)
def update_canvas_size(self, event):
self.canvas.config(width=event.width, height=event.height)
# 重新创建渐变背景
for i in range(event.height):
color = "#{:02x}{:02x}{:02x}".format(0, 0, int(255 * i / (event.height - 1)))
self.canvas.create_line(0, i, event.width, i, fill=color)
# 重新创建星空背景
self.canvas.delete("star")
for _ in range(100):
x = random.randint(0, event.width)
y = random.randint(0, event.height)
size = random.randint(1, 3)
self.canvas.create_oval(x, y, x + size, y + size, fill="white", tags="star")
# 定义预测性别的方法
def predict_gender(self):
name = self.input_name.get().strip()
if name:
gender = nb_classifier.predict(name)
if gender == '男':
self.label_result.config(text=f"{name} 是男性")
else:
self.label_result.config(text=f"{name} 是女性")
else:
self.label_result.config(text="")
# 定义批量预测性别的方法
def batch_predict_gender(self):
file_path = filedialog.askopenfilename()
if file_path:
with open(file_path, 'r', encoding='utf-8') as f:
names = f.read().splitlines()
results = []
for name in names:
gender = self.clf.predict(name)
results.append(f"{name}:{gender}")
with open("batch_prediction_results.txt", "w", encoding="utf-8") as f:
f.write("\n".join(results))
self.label_result.config(text="批量预测完成,请查看 batch_prediction_results.txt 文件")
# 读取训练数据,创建和训练朴素贝叶斯分类器的代码保持不变
# 读取训练数据
with open(r"C:\Users\14812\Desktop\NameData (2).txt", 'r', encoding='utf-8') as f:
training_data = f.readlines()
# 创建朴素贝叶斯分类器
nb_classifier = NaiveBayesClassifier()
# 训练朴素贝叶斯分类器
nb_classifier.train(training_data)
# 保存模型到文件
nb_classifier.save_model("naive_bayes_model.pkl")
# 修改 main 函数:
def main():
root = tk.Tk()
app = Application(root)
# 加载模型
model_path = "naive_bayes_model.pkl"
app.clf = NaiveBayesClassifier.load_model(model_path)
# 设置窗口大小和位置
root.geometry("350x150+400+200")
root.mainloop()
if __name__ == "__main__":
main()
这段代码是一个名字性别预测系统的程序,采用朴素贝叶斯分类器。程序实现了一个基于Tkinter的图形界面,用户可以输入名字,预测该名字的性别。程序分为以下几个部分:
-
定义了一个朴素贝叶斯分类器类(NaiveBayesClassifier)来实现训练和预测功能。
-
定义了一个应用类(Application),用于创建和管理Tkinter图形界面。
-
读取训练数据,创建并训练朴素贝叶斯分类器,然后将训练好的模型保存到文件。
-
main() 函数中初始化Tkinter窗口,加载模型,设置窗口大小和位置,并启动Tkinter的主事件循环。
该程序的功能包括:
- 用户输入名字,预测性别。
- 批量预测名字性别,结果保存到一个文本文件中。
这个程序的核心是朴素贝叶斯分类器。其通过计算先验概率、字符频率等来训练模型,并基于这些概率预测名字的性别。
- 定义朴素贝叶斯分类器类(NaiveBayesClassifier):
# 定义一个朴素贝叶斯分类器类
class NaiveBayesClassifier:
def __init__(self):
# 初始化男性和女性字符频率字典
self.word_freq_male = {}
self.word_freq_female = {}
# 初始化男性和女性的先验概率
self.prob_male = 0
self.prob_female = 0
# 初始化词汇表
self.vocab = set()
# 定义 train() 方法,接收训练数据作为参数
def train(self, training_data):
# 初始化男性和女性名字列表
male_names = []
female_names = []
# 从训练数据中分离男性和女性名字
for line in training_data:
name, gender = line.strip().split('\t')
if gender == '男':
male_names.append(name)
elif gender == '女':
female_names.append(name)
# 计算先验概率
self.prob_male = len(male_names) / len(training_data)
self.prob_female = len(female_names) / len(training_data)
# 计算每个字符在男性和女性名字中的频率
for name in male_names:
for char in name:
if char in self.word_freq_male:
self.word_freq_male[char] += 1
else:
self.word_freq_male[char] = 1
self.vocab.add(char)
for name in female_names:
for char in name:
if char in self.word_freq_female:
self.word_freq_female[char] += 1
else:
self.word_freq_female[char] = 1
self.vocab.add(char)
# 对每个字符应用加一平滑
for char in self.vocab:
if char not in self.word_freq_male:
self.word_freq_male[char] = 1
if char not in self.word_freq_female:
self.word_freq_female[char] = 1
# 标准化字符频率
male_total = sum(self.word_freq_male.values())
female_total = sum(self.word_freq_female.values())
for char in self.vocab:
self.word_freq_male[char] /= male_total
self.word_freq_female[char] /= female_total
# 定义 predict() 方法,接收一个名字作为参数
def predict(self, name):
# 初始化男性和女性得分为先验概率的对数值
male_score = np.log(self.prob_male)
female_score = np.log(self.prob_female)
# 计算名字在男性和女性中的得分
for char in name:
if char in self.vocab:
male_score += np.log(self.word_freq_male[char])
female_score += np.log(self.word_freq_female[char])
# 返回得分较高的性别
if male_score > female_score:
return '男'
else:
return '女'
# 定义 save_model() 方法,用于将训练好的模型保存到文件
def save_model(self, file_path):
with open(file_path, "wb") as f:
pickle.dump(self, f)
# 定义一个类方法 load_model(),用于从文件加载模型
@classmethod
def load_model(cls, file_path):
with open(file_path, "rb") as f:
return pickle.load(f)
这部分代码定义了两个方法用于保存和加载训练好的模型。save_model()
方法使用 pickle 库将模型对象序列化并保存到文件,load_model()
则是一个类方法,用于从文件中加载并反序列化模型对象。
接下来,我们看一下构建和控制 Tkinter 应用程序的 Application 类:
class Application:
def __init__(self, master):
self.master = master
master.title("名字性别判断系统")
# 创建星空背景
self.create_starry_background()
# 配置 ttk 组件的样式
style = ttk.Style()
style.configure("TLabel", font=("Helvetica", 12))
style.configure("TButton", font=("Helvetica", 12))
self.frame = tk.Frame(self.canvas, padx=10, pady=10, background="#F0F0F0")
self.frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 创建输入框和标签
self.label_name = ttk.Label(self.frame, text="请输入名字:", background="#F0F0F0")
self.input_name = ttk.Entry(self.frame, width=20)
self.label_name.grid(row=0, column=0, sticky=tk.W)
self.input_name.grid(row=0, column=1, sticky=tk.W)
# 创建预测按钮
self.button_predict = ttk.Button(self.frame, text="预测性别", command=self.predict_gender)
self.button_predict.grid(row=1, column=0, columnspan=2)
# 创建批量预测按钮
self.button_batch_predict = ttk.Button(self.frame, text="批量预测性别", command=self.batch_predict_gender)
self.button_batch_predict.grid(row=2, column=0, columnspan=2)
# 创建结果显示标签
self.label_result = ttk.Label(self.frame, text="", background="#F0F0F0")
self.label_result.grid(row=3, column=0, columnspan=2)
这部分代码定义了 Application 类的构造函数,用于初始化 Tkinter 界面。首先,设置窗口标题。接着,调用 create_starry_background()
方法创建星空背景。然后,配置 ttk 组件的样式。之后,创建输入框、标签、预测按钮、批量预测按钮和结果显示标签。
def create_starry_background(self):
self.canvas = tk.Canvas(self.master, width=350, height=150)
self.canvas.pack(fill=tk.BOTH, expand=True)
# 创建渐变背景
for i in range(150):
color = "#{:02x}{:02x}{:02x}".format(240 - i, 240 - i, 240 - i)
self.canvas.create_line(0, i, 350, i, fill=color)
# 在背景上随机创建星星
for _ in range(50):
x = random.randint(0, 350)
y = random.randint(0, 150)
size = random.randint(1, 3)
self.canvas.create_oval(x, y, x + size, y + size, fill="#FFFFFF", outline="")
这部分代码定义了create_starry_background()
方法。此方法创建并设置画布大小,然后使用for循环创建渐变背景。接下来,它使用另一个for循环在背景上随机创建星星。
def predict_gender(self):
# 获取输入的名字
name = self.input_name.get().strip()
# 使用朴素贝叶斯分类器进行预测
gender = classifier.predict(name)
# 显示预测结果
self.label_result["text"] = f"预测结果: {gender}"
def batch_predict_gender(self):
# 从文件中加载测试数据
with open("test_data.txt", "r", encoding="utf-8") as f:
test_data = [line.strip() for line in f.readlines()]
# 对测试数据中的名字进行预测,并与实际性别进行比较
correct_count = 0
for line in test_data:
name, actual_gender = line.split("\t")
predicted_gender = classifier.predict(name)
if actual_gender == predicted_gender:
correct_count += 1
# 计算准确率并显示结果
accuracy = correct_count / len(test_data)
self.label_result["text"] = f"批量预测准确率: {accuracy:.2%}"
这部分代码定义了两个方法:predict_gender()
和batch_predict_gender()
。predict_gender()
方法首先获取输入框中的名字,然后使用朴素贝叶斯分类器进行性别预测,并在结果标签中显示预测结果。
batch_predict_gender()
方法从文件中加载测试数据,然后对每个名字进行预测,将预测结果与实际性别进行比较。计算预测准确率并在结果标签中显示。
if __name__ == "__main__":
# 加载训练数据并训练朴素贝叶斯分类器
with open("training_data.txt", "r", encoding="utf-8") as f:
training_data = [line.strip() for line in f.readlines()]
classifier = NaiveBayesClassifier()
classifier.train(training_data)
# 创建并运行 Tkinter 应用程序
root = tk.Tk()
app = Application(root)
root.mainloop()