python基于机器学习的姓名预测性别网页app开发

2023-11-13

前言

做这个项目的起因是之前csdn给我推荐了一个问答:基于机器学习的姓名预测性别的手机app开发。我点进去发现已经有人回答了,链接点进去一看,好家伙,这不是查表算概率吗,和机器学习有半毛钱关系。而且我觉得用姓名预测性别挺扯淡的,去查了一下,发现某知名爱国企业和国外的都有提供姓名预测性别的api,看来是可以尝试做的。

吐槽完了,先上最后做出来的结果:
在这里插入图片描述
准确性还是可以的,并且支持人名批量查询,整个网页响应速度也很快。

环境

我用的是python3.10,需要安装以下包:
numpy
pandas
pypinyin
tensorflow-cpu
plotly(网页)
dash(网页)

方法

1.如何拿到人名和性别的数据集。这个我一开始去搜那篇查表文章背后所用的数据库从哪来的,在github上找到了它的人名出现频率图,但是没有找到原始数据库,据说是从什么泄露的kaifangjilu里拿出来的,我一想这tm不是违法吗,难道没有合法手段拿到这样的数据集资源了吗?我还是在github上找到了120万人名和性别的数据集:
点进去找到Chinese_Names_Corpus_Gender(120W).txt这个文件
2.如何对中文姓名进行特征提取,转化为机器能理解的语言。 这个想来想去还是决定把中文先转换为无注音的拼音,然后对每一个字母进行字母表数字的转换,事实证明确实效果不错。

具体如下图所示:
在这里插入图片描述

代码

代码分为三块,数据准备代码,数据训练代码,网页app代码。

数据准备代码

首先把下载下来的txt转换为csv文件:
在这里插入图片描述
把前面的东西去掉,然后文件后缀一改,就摇身一变成为了以逗号为分割的经典csv文件。
在这里插入图片描述
接下来开始读取处理数据:

import pandas as pd
df = pd.read_csv("test.csv")
df

这里我是在notebook里运行的,结果如下:

在这里插入图片描述

我们首先需要把性别转换为0,1表示男,女:

df['sex'].replace(['男', '女','未知'],
                        [0, 1, 2], inplace=True)

然后批量转换姓名并保存到新的csv文件中:

from pypinyin import lazy_pinyin
import time
count = 0
a1 = time.time()
for x in df['dict']:
    list_pinyin = lazy_pinyin(x) #["a","zuo"]
    c = ''.join(list_pinyin) #["azuo"]
    num_pinyin = [max(0.0, ord(char)-96.0) for char in c]
    num_pinyin_pad = num_pinyin + [0.0] * max(0, 20 - len(num_pinyin))
    df['dict'][count] = num_pinyin_pad[:15] #为了使输入向量固定长度,取前15个字符。
    count+=1
    a2 = time.time()
    if count % 10000 == 0:
        print(a2-a1)
df.to_csv('after_2.csv')

这里时间挺久的,因为数据量大,大概需要个半小时,我让它每10000个数据打印一下运行时间,可以去掉。然后有个细节就是因为要输入模型,所以要固定向量长度,即短的名字给它补0,长的名字给它截掉,一律取前十五个字母。 保存完csv之后就可以退出了。

数据训练代码

先把数据读进来,因为发现二分类表现更佳,所以我们这里排除性别为2也就是未知的名字。

import pandas as pd
import numpy as np
df = pd.read_csv('after_2.csv')
df_binary = df[df['sex']!=2]

准备输入向量:

import json
test_list = df_binary['dict'].values.tolist()
for i in range(len(test_list)):
    test_list[i] = eval(test_list[i])
X = np.array(test_list,dtype = np.float32)
y = np.asarray(df_binary['sex'].values.tolist())

其中X的形状是(1050353, 15),y的形状是(1050353,)。

划分训练集和测试集:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,
y,test_size=0.2,random_state=0)

准备模型:

from tensorflow.keras import Sequential
from tensorflow.keras.layers import Embedding, Bidirectional, LSTM, Dense
from tensorflow.keras.optimizers import Adam

def lstm_model(num_alphabets=27, name_length=15, embedding_dim=256):
    model = Sequential([
        Embedding(num_alphabets, embedding_dim, input_length=15),
        Bidirectional(LSTM(units=128, recurrent_dropout=0.2, dropout=0.2)),
        Dense(1, activation="sigmoid")
    ])

    model.compile(loss='binary_crossentropy',
                  optimizer=Adam(learning_rate=0.001),
                  metrics=['accuracy'])

    return model

只有一层LSTM,cpu也可以轻松训练(指训练一个epoch需要半小时)

训练:

import numpy as np
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from tensorflow.keras.callbacks import EarlyStopping
# Step 1: Instantiate the model
model = lstm_model(num_alphabets=27, name_length=15, embedding_dim=256)

# Step 2: Split Training and Test Data

X_train, X_test, y_train, y_test = train_test_split(X,
                                                    y,
                                                    test_size=0.2,
                                                    random_state=0)

# Step 3: Train the model
callbacks = [
    EarlyStopping(monitor='val_accuracy',
                  min_delta=1e-3,
                  patience=5,
                  mode='max',
                  restore_best_weights=True,
                  verbose=1),
]

history = model.fit(x=X_train,
                    y=y_train,
                    batch_size=64,
                    epochs=3,
                    validation_data=(X_test, y_test),
                    callbacks=callbacks)

# Step 4: Save the model
model.save('boyorgirl.h5')

# Step 5: Plot accuracies
plt.plot(history.history['accuracy'], label='train')
plt.plot(history.history['val_accuracy'], label='val')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()

网络这一块是别人造好的轮子,我直接拿来用了,因为训练速度比较慢所以我这里只训练了三轮,训练集和测试集的准确率都在提升,已经接近0.88,说明继续训练还有提升空间:

在这里插入图片描述

网页开发代码

这块比较长,就不解释了,需要注意的是我结尾设置app是在0.0.0.0上的3000端口运行的,也就是说如果你把它部在服务器上,可以直接访问服务器的ip地址加端口号访问网页。如果是本地查看设置127.0.0.1即可。
另外需要在同目录底下准备一个faq.md的说明文件,是放在网页底部进行说明的,比如下图:
在这里插入图片描述

import os
import pandas as pd
import numpy as np
import re
from tensorflow.keras.models import load_model
from pypinyin import lazy_pinyin
import plotly.express as px
import dash
from dash import dash_table
import dash_bootstrap_components as dbc
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State

pred_model = load_model('boyorgirl.h5')

# Setup the Dash App
external_stylesheets = [dbc.themes.LITERA]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# Server
server = app.server

# FAQ section
with open('faq.md', 'r') as file:
    faq = file.read()

# App Layout
app.layout = html.Table([
    html.Tr([
        html.H1(html.Center(html.B('男孩或者女孩?'))),
        html.Div(
            html.Center("根据名字预测性别"),
            style={'fontSize': 20}),
        html.Br(),
        html.Div(
            dbc.Input(id='names',
                      value='李泽,李倩',
                      placeholder='输入多个名字请用逗号或者空格分开',
                      style={'width': '700px'})),
        html.Br(),
        html.Center(children=[
            dbc.Button('提交',
                       id='submit-button',
                       n_clicks=0,
                       color='primary',
                       type='submit'),
            dbc.Button('重置',
                       id='reset-button',
                       color='secondary',
                       type='submit',
                       style={"margin-left": "50px"})
        ]),
        html.Br(),
        dcc.Loading(id='table-loading',
                    type='default',
                    children=html.Div(id='predictions',
                                      children=[],
                                      style={'width': '700px'})),
        dcc.Store(id='selected-names'),
        html.Br(),
        dcc.Loading(id='chart-loading',
                    type='default',
                    children=html.Div(id='bar-plot', children=[])),
        html.Br(),
        html.Div(html.Center(html.B('关于该项目')),
                 style={'fontSize': 20}),
        dcc.Markdown(faq, style={'width': '700px'})
    ])
],
                        style={
                            'marginLeft': 'auto',
                            'marginRight': 'auto'
                        })


# Callbacks
@app.callback([Output('submit-button', 'n_clicks'),
               Output('names', 'value')], Input('reset-button', 'n_clicks'),
              State('names', 'value'))
def update(n_clicks, value):
    if n_clicks is not None and n_clicks > 0:
        return -1, ''
    else:
        return 0, value


@app.callback(
    [Output('predictions', 'children'),
     Output('selected-names', 'data')], Input('submit-button', 'n_clicks'),
    State('names', 'value'))
def predict(n_clicks, value):
    if n_clicks >= 0:
        # Split on all non-alphabet characters
        # Restrict to first 10 names only
        names = re.findall(r"\w+", value)

        # Convert to dataframe
        pred_df = pd.DataFrame({'name': names})
        list_list = []
        # Preprocess
        for x in names:
            list_pinyin = lazy_pinyin(x)
            c = ''.join(list_pinyin)
            num_pinyin = [max(0.0, ord(char)-96.0) for char in c]
            num_pinyin_pad = num_pinyin + [0.0] * max(0, 20 - len(num_pinyin))
            list_list.append(num_pinyin_pad[:15])
        # Predictions
        result = pred_model.predict(list_list).squeeze(axis=1)
        pred_df['男还是女'] = [
            '女' if logit > 0.5 else '男' for logit in result
        ]
        pred_df['可能性'] = [
            logit if logit > 0.5 else 1.0 - logit for logit in result
        ]

        # Format the output
        pred_df['name'] = names
        pred_df.rename(columns={'name': '名字'}, inplace=True)
        pred_df['可能性'] = pred_df['可能性'].round(2)
        pred_df.drop_duplicates(inplace=True)

        return [
            dash_table.DataTable(
                id='pred-table',
                columns=[{
                    'name': col,
                    'id': col,
                } for col in pred_df.columns],
                data=pred_df.to_dict('records'),
                filter_action="native",
                filter_options={"case": "insensitive"},
                sort_action="native",  # give user capability to sort columns
                sort_mode="single",  # sort across 'multi' or 'single' columns
                page_current=0,  # page number that user is on
                page_size=10,  # number of rows visible per page
                style_cell={
                    'fontFamily': 'Open Sans',
                    'textAlign': 'center',
                    'padding': '10px',
                    'backgroundColor': 'rgb(255, 255, 204)',
                    'height': 'auto',
                    'font-size': '16px'
                },
                style_header={
                    'backgroundColor': 'rgb(128, 128, 128)',
                    'color': 'white',
                    'textAlign': 'center'
                },
                export_format='csv')
        ], names
    else:
        return [], ''


@app.callback(Output('bar-plot', 'children'), [
    Input('submit-button', 'n_clicks'),
    Input('predictions', 'children'),
    Input('selected-names', 'data')
])
def bar_plot(n_clicks, data, selected_names):
    if n_clicks >= 0:
        # Bar Chart
        data = pd.DataFrame(data[0]['props']['data'])
        fig = px.bar(data,
                     x="可能性",
                     y="名字",
                     color='男还是女',
                     orientation='h',
                     color_discrete_map={
                         '男': 'dodgerblue',
                         '女': 'lightcoral'
                     })

        fig.update_layout(title={
            'text': '预测正确的可能性',
            'x': 0.5
        },
                          yaxis={
                              'categoryorder': 'array',
                              'categoryarray': selected_names,
                              'autorange': 'reversed',
                          },
                          xaxis={'range': [0, 1]},
                          font={'size': 14},
                          width=700)

        return [dcc.Graph(figure=fig)]
    else:
        return []


if __name__ == '__main__':
    app.run_server(host='0.0.0.0', port='3000', proxy=None, debug=False)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python基于机器学习的姓名预测性别网页app开发 的相关文章

随机推荐

  • 微软重磅开源 Visual ChatGPT! 一个月内斩获30K star

    点击上方 Github中文社区 关注 看Github 每天提升 第067期分享 github中文社区 大家好 我是Huber 今年由于大环境恶化 为了生活本人这一年在某外企从事某个秘密项目 正经的那种 的研发 所以没有时间 动力 和精力 钱
  • 微软修改 MIT 项目原作者版权声明引发争议;白宫为提高开源安全性邀请软件行业者座谈;Ruby 3.1.0 发布

    整理 宋彤彤 责编 屠敏 开源吞噬世界的趋势下 借助开源软件 基于开源协议 任何人都可以得到项目的源代码 加以学习 修改 甚至是重新分发 关注 开源日报 一文速览国内外今日的开源大事件吧 一分钟速览新闻点 白宫邀请软件行业者座谈 以提高开源
  • Android设备接入阿里云IoT物联网平台

    1 准备工作 1 1 注册阿里云账号 使用个人淘宝账号或手机号 开通阿里云账号 并通过 实名认证 可以用支付宝认证 1 2 免费开通IoT物联网套件 产品官网 https www aliyun com product iot 1 3 软件环
  • 拒绝摆烂!C语言练习打卡第六天

    博客主页 小王又困了 系列专栏 每日一练 人之为学 不日近则日退 感谢大家点赞 收藏 评论 目录 一 选择题 1 第一题 2 第二题 3 第三题 4 第四题 二 编程题 1 第一题 2 第二题 前言 在前面我们学习完C语言的所以知识 当然练
  • 【华为OD机试真题 python】积木最远距离【2022 Q4

    题目描述 积木最远距离 小华和小薇一起通过玩积木游戏学习数学 他们有很多积木 每个积木块上都有一个数字 积木块上的数字可能相同 小华随机拿一些积木挨着排成一排 请小薇找到这排积木中数字相同且所处位置最远的2块积木块 计算他们的距离 小薇请你
  • Java中的反射

    Java中的反射 Java反射是指在运行时动态地获取和操作类的信息 包括类的属性 方法和构造函数等 通过反射机制 我们可以在运行时检查类的信息 并动态创建对象 调用方法和访问属性 而不需要在编译时确定类的具体信息 Java反射机制提供了以下
  • 写一本技术书籍

    作者 董伟明 链接 https zhuanlan zhihu com p 22207407 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 在过去的8个多月的时间里面 我完成了一本504页的 Python W
  • stm32f1系列 使用前需在keil配置中添加预定义符号STM32F10X_HD,USE_STDPERIPH_DRIVER

    stm32f1系列 使用前需在keil配置中添加预定义符号STM32F10X HD USE STDPERIPH DRIVER 因为在stm32系列建立底层库时 为了逻辑方便管理头文件 将库函数的头文件都放在了stm32f10x conf h
  • docker镜像(Ubuntu)安装jdk

    1 查找干净的Ubuntudocker search ubuntu2 下载镜像docker pull ubuntu3 编辑dockerfile文件 文件内容开始 FROM ubuntu latestMAINTAINER guodongADD
  • [ASP.NET MVC 小牛之路]17 - 捆绑(Bundle)

    本文介绍 MVC 4 提供的一个新特性 捆绑 Bundle 一个在 View 和 Layout 中用于组织优化浏览器请求的 CSS 和 JavaScript 文件的技术 本文目录 了解VS默认加入的脚本库 当我们创建一个基本模板的 MVC
  • 数据可视化第四章答案

    热狗大赛大胃王前三 from pyecharts import Pie import pandas as pd hotplace pd read csv hot dog places csv header None hotplace pd
  • Spring框架中的Resource接口是什么,以及它在加载和访问资源时的关键作用

    文章目录 什么是 Resource 接口 使用 Resource 加载资源 使用 Resource 访问文件系统资源 总结 个人主页 程序员 小侯 CSDN新晋作者 欢迎 点赞 评论 收藏 收录专栏 Java框架 文章内容 Resource
  • 告别枯燥,247个Python经典实战案例集合(附代码)

    今天为大家推荐一个Python从入门到进阶的实战案例合集 共计247个案例 185页内容 从此告别枯燥 60秒学会 个 例 系统学习Python 从 门到 师 所有均含有实例代码 可直接运行 感受python之美 用最短的代码实现 02 P
  • 基于STM32单片机的智能家居毕设

    文章目录 一 硬件选型 1 硬件清单 2 硬件展示 部分 二 效果展示 1 整体效果展示 2 显示屏 触摸 效果展示 三 功能分析 1 系统总体结构框图 2 主要包含的功能 四 怎么做 1 STM32单片机部分 2 语音识别与播报部分 3
  • 【JeecgBoot】点击返回关闭当前页面(tab)且返回上一层

    首先要在你需要关闭得页面组件里面加上inject closeCurrent 如下图位置 之后写一个触发函数 这里面得reBack即是返回函数
  • HTMl中的各种标签(常见)

    HTML的元素以开始标签开始 结束标签结束 被它们包起来 且一半可以嵌套 分类 html的标签主要分为双标签和单标签 双标签
  • xmL 特殊符号转换

    一共有五个 所有的特殊字符对应的编码 特殊字符 代替符号 特殊原因 amp 每一个代表符号的开头字符 gt gt 标记的结束字符 lt lt 标记的开始字符 quot 设定属性值 apos 设定属性值 代替符号都以 开始 都包含分号 以分号
  • CUDA中动态Global Memory分配和操作

    CUDA中动态Global Memory分配和操作 CUDA中动态Global Memory分配和操作 1 Heap Memory Allocation 2 Interoperability with Host Memory API 3 E
  • vue中利用自定义指令修改elementUI对话框到顶部的距离

    Vue directive alterELDialogMarginTop 修改elementUI中el dialog顶部的距离 传入值eg marginTop 5vh inserted el binding vnode el firstEl
  • python基于机器学习的姓名预测性别网页app开发

    前言 做这个项目的起因是之前csdn给我推荐了一个问答 基于机器学习的姓名预测性别的手机app开发 我点进去发现已经有人回答了 链接点进去一看 好家伙 这不是查表算概率吗 和机器学习有半毛钱关系 而且我觉得用姓名预测性别挺扯淡的 去查了一下