本文已参与「新人创作礼」活动,一起开启掘金创作之路。
【资源链接】
提取码:nnx6
【包含文件】
1.需求说明
由于项目需要通过姓名判断性别,在网络上找到了Python
的NGender
包,但项目的技术栈是Java
,首先想到的是使用jython-standalone
来执行 Python 代码,在 idea 成功调用,在部署时却无法找到NGender
模块,最终无法解决部署问题因此有了 Java 版本的 NGender :smile: 有成功部署的小伙伴儿可以分享一下经验。Java 版本说明:
- 82%的准确率(与python版本一致)
- 可用于猜测性别
- 可用于判断名字的男性化/女性化程度
2.代码实现
2.1 依赖
用于解析csv
类型文件,非必须依赖,可自行解析。
<!-- 用于解析csv文件 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.6</version>
</dependency>
复制代码
2.2 源码
源码从 Python 代码转化,并未进行优化。
@Slf4j
@Component
public class GenderUtils {
private Map<String, String> genderMap = new HashMap<>(9443);
private int maleTotal = 0;
private int femaleTotal = 0;
private int genderTotal = 0;
@PostConstruct
private void init() {
// 加载文件
File toFile = new File("data/ngender/charfreq.csv");
// 解析CSV文件
CsvData rows = CsvUtil.getReader().read(toFile);
for (int i = 1, rowCount = rows.getRowCount(); i < rowCount; i++) {
CsvRow row = rows.getRow(i);
maleTotal += Integer.parseInt(row.get(1));
femaleTotal += Integer.parseInt(row.get(2));
}
genderTotal = maleTotal + femaleTotal;
// 封装对象
for (int i = 1, rowCount = rows.getRowCount(); i < rowCount; i++) {
CsvRow row = rows.getRow(i);
String nameChar = row.get(0);
int maleNum = Integer.parseInt(row.get(1));
int femaleNum = Integer.parseInt(row.get(2));
genderMap.put(nameChar, 1.0 * femaleNum / femaleTotal + "," + 1.0 * maleNum / maleTotal);
}
}
/**
* 根据姓名判断性别(仅支持中文)
*
* @param nameString 姓名
* @return 性别信息
*/
public Map<String, String> guessGenderByName(String nameString) {
// 截取【名】的全部字符字符
char[] nameChars = nameString.substring(1).toCharArray();
// 获取性别可能性数据
double maleProb = getGenderProb(nameChars, 1);
double femaleProb = getGenderProb(nameChars, 0);
// 返回结果
if (maleProb > femaleProb) {
return new HashMap<String, String>(2) {{
put("male", String.valueOf(maleProb / (maleProb + femaleProb)));
}};
} else if (femaleProb > maleProb) {
return new HashMap<String, String>(2) {{
put("female", String.valueOf(femaleProb / (maleProb + femaleProb)));
}};
} else {
return new HashMap<String, String>(2) {{
put("unknown", "0");
}};
}
}
/**
* 计算性别可能性
*
* @param nameChars 【名】的全部字符字符
* @param genderFlag 0 female 1 male
* @return 性别及可能性
*/
private double getGenderProb(char[] nameChars, int genderFlag) {
double baseProb;
if (genderFlag == 0) {
baseProb = 1.0 * femaleTotal / genderTotal;
} else {
baseProb = 1.0 * maleTotal / genderTotal;
}
for (char nameChar : nameChars) {
baseProb *= Double.parseDouble(MapUtils.getString(genderMap, nameChar + "", "0,0").split(",")[genderFlag]);
}
return baseProb;
}
}
复制代码
2.3 调用
charfreq.csv
文件有9943条,整个工具类的加载需要88ms【仅测试一次】
。
Map<String, String> resultMap = genderUtils.guessGenderByName("刘芳芳");
// "female": "0.9835037905504539"
复制代码
3.其他
Python 版本的 NGender 下载地址 及介绍。