import pandas as pd import numpy as np import re from collections import defaultdict from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding, Conv1D, GlobalMaxPooling1D, Dense, Dropout from tensorflow.keras.utils import to_categorical from tensorflow.keras.callbacks import EarlyStopping
data = pd.read_csv("dataset/ccnc.csv") print(f"原始数据量:{len(data)}")
def clean_name(name): """清理姓名:保留中文字符,去除特殊符号和数字""" name = str(name).strip() return re.sub(r'[^\u4e00-\u9fa5]', '', name)
data["姓名"] = data["姓名"].apply(clean_name)
data = data[data["姓名"].str.len() >= 2]
data = data[data["性别"].isin(["男", "女"])] print(f"清洗后数据量:{len(data)}")
label_encoder = LabelEncoder() data["性别编码"] = label_encoder.fit_transform(data["性别"]) y = data["性别编码"].values
names = data["姓名"].tolist()
max_length = int(np.percentile([len(name) for name in names], 95)) print(f"最大姓名长度:{max_length}")
tokenizer = Tokenizer(char_level=True) tokenizer.fit_on_texts(names) vocab_size = len(tokenizer.word_index) + 1 print(f"词汇表大小(不同汉字数量):{vocab_size}")
sequences = tokenizer.texts_to_sequences(names)
X = pad_sequences(sequences, maxlen=max_length, padding="post")
X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y )
model = Sequential([ Embedding( input_dim=vocab_size, output_dim=32, input_length=max_length ), Conv1D( filters=64, kernel_size=2, activation="relu" ), GlobalMaxPooling1D(), Dense(32, activation="relu"), Dropout(0.5), Dense(1, activation="sigmoid") ])
model.compile( loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"] )
model.summary()
early_stopping = EarlyStopping( monitor="val_accuracy", patience=3, mode="max", restore_best_weights=True )
history = model.fit( X_train, y_train, epochs=20, batch_size=32, validation_split=0.1, callbacks=[early_stopping], verbose=1 )
print("\n测试集评估:") loss, accuracy = model.evaluate(X_test, y_test, verbose=0) print(f"损失:{loss:.4f},准确率:{accuracy:.4f}")
def predict_gender(name): """预测姓名对应的性别""" name_clean = clean_name(name) if len(name_clean) == 0: return "无效姓名" seq = tokenizer.texts_to_sequences([name_clean]) seq_pad = pad_sequences(seq, maxlen=max_length, padding="post") prob = model.predict(seq_pad)[0][0] gender = "男" if prob > 0.5 else "女" return f"姓名:{name},预测性别:{gender}(概率:{prob:.2f})"
test_names = ["张三", "李四", "王丽", "赵强", "刘芳", "陈明"] for name in test_names: print(predict_gender(name))
import pickle
model.save("gender_prediction_model.h5") print("模型已保存为:gender_prediction_model.h5")
with open("name_tokenizer.pkl", "wb") as f: pickle.dump(tokenizer, f) print("Tokenizer已保存为:name_tokenizer.pkl")
with open("max_length.pkl", "wb") as f: pickle.dump(max_length, f) print("最大姓名长度已保存为:max_length.pkl")
|
评论