机器学习实验(十三):90%的准确率,根据中文名字预测性别!
声明:版权所有,转载请联系作者并注明出处 http://blog.csdn.net/u013719780?viewmode=contents 90%的准确率,根据中文名字预测性别!一、概述 性别是人类差异最大的特征之一,不同的性别拥有不同的特征,譬如购物、电视剧、书籍等方面男生和女生的爱好有很大的不同。因此,知道了用户的性别就
声明:版权所有,转载请联系作者并注明出处 http://blog.csdn.net/u013719780?viewmode=contents
90%的准确率,根据中文名字预测性别!
一、概述
性别是人类差异最大的特征之一,不同的性别拥有不同的特征,譬如购物、电视剧、书籍等方面男生和女生的爱好有很大的不同。因此,知道了用户的性别就可以更加准确的判断用户的潜在行为和需求。由此可知,性别识别的重要性和价值性不言而喻,每个机器学习模型的构建,基本都会需要准确识别用户的性别。
目前业内预测用户性别的方法有很多,大多数都是基于用户的行为数据、兴趣等方面进行性别判定,识别的准确性也参差不齐。但是,很多的时候我们拿不到用户的行为数据,这个时候用用户的行为数据、兴趣数据建立机器学习模型就显得力不从心了。同时,从用户的行为数据着手建立模型去预测用户的性别效果也并不会见得有多好,因为影响模型准确性的主要原因是这些用户的行为在性别上区分度有多大,如果区分度不明显,那模型和算法的准确性将会遇到明显的瓶颈。同时,基于用户行为的性别识别涉及的数据面非常广、数据依赖链条很长、数据计算复杂度很高,识别效能反而成为了痛点!
二、模型建立
在这里,我们分享一下我们MSO用户性别预测模型:基于用户中文名字的用户性别预测方法!我们仅仅是根据用户的中文名字进行预测,没有用到用户的行为数据,但是实际识别准确率却高达 90% 以上,为什么准确率这么高?主要是因为男生、女生在取名上有很大的差异!下面我们分步骤来讲解下MSO的用户性别识别模型构建过程。
首先,做一个声明,本文中送列举的名字均是泛指,如果正好与你名字相同,纯属巧合!在详细讲解模型之前,为了规范,我们来一个约定,本文中的姓名指的是包括姓和名字,比如‘谭文’,姓是‘谭’,名字是‘文’。名字不包括姓,例如‘谭文’的名字就是‘文’。首先,我们对用户的名字进行简单的处理,本文我们主要讨论两个字和三个字的姓名,超过三个字的姓名不予考虑。对于两个字的姓名(也就是只有一个名字的姓名)我们认为名字的第一个字是‘ ’,第二个字是名字的本身。为了阐述清楚,就以‘谭文’这个姓名为例,我们会将其处理成‘谭 文’。
接下里,我们看看用户名字在第一个字和第二个字上面的差异:
def name_count_bygender(rdd):
rdd = rdd.map(lambda x: (x[0][0], x[0][1], x[1]))
rdd = pd.DataFrame(rdd.collect(), columns = ['first_name', 'gender', 'num'])
rdd = rdd.sort(['num'], ascending=False)
return rdd
first_name_count_bygender = name_count_bygender(first_name_count_bygender)
first_name_count_bygender[first_name_count_bygender.gender=='男'].head(30)
first_name_count_bygender[first_name_count_bygender.gender=='女'].head(30)
second_name_count_bygender = name_count_bygender(second_name_count_bygender)
second_name_count_bygender[second_name_count_bygender.gender=='男'].head(30)
second_name_count_bygender[second_name_count_bygender.gender=='女'].head(30)
从以上可以看出,男生、女生的名字中常用的字有很大的差别,同时在名字中第一个字和第二个字上又有不同,表明位置也是一个需要考虑的重要因素。因此,我们建立用户名字中每个字的‘男性偏好极性’,这里的男性偏好极性是我自己命名的,字的‘男性偏好极性’指的是用户名字中的每个字是拥有男生的概率,譬如说‘谭文’,前文已经说了,我们需要将其处理成‘谭 文’,则
' '的男性偏好极性 = 第一个是' '的男生数第一个字是' '的所有用户数
'文'的男性偏好极性 = 第二个字是文的男生数第二个字是文的所有用户数
这样,我们就得到了每个名字的第一个字和第二个字的男性偏好极性。则每个名字的性别预测概率就是第一个名字的男性偏好极性与第二个名字的男性偏好极性的加权平均。这样我们根据每个用户的名字最终得到了其性别。
接下来我们看看测试结果:
test_rdd = test.rdd.map(lambda x: (x[0], x[1], drop_alnum(x[2]), x[3]))
test_rdd = test_rdd.filter(lambda x: len(x[2])<4 and len(x[2])>1)
def accuracy(rdd, p=0.5, threshold=0.5):
rdd = rdd.map(lambda x: (predict(x[2], p), encode_label(x[3])))
data = rdd.collect()
label = [label for pre, label in data]
pre = [1. if pre>0.5 else 0. for pre, label in data]
count = 0
for i, j in zip(label, pre):
if i==j:
count += 1
return count/len(label)
accuracy(test_rdd, p=0.5, threshold=0.5)
从上可以看出,我们的测试结果准确率达到了0.818,是不是不相信自己的眼睛,没看错,效果就是这么好,在我们仅仅根据名字并且没有用到任何算法的条件下得到这样好的结果,应该算是很满意的结果了。
接下来,我们用一些算法来跑跑,看看准确率能否得到提升,我尝试了分别用randomforest、GBDT、LR和MLP神经网络模型进行预测,所用到的特征就是前文提取到的每个名字中第一个字、第二个字的男性偏好极性以及做了一些特征交互,得到的准确率分别如下:
depths = [2, 3, 4, 5, 6, 7, 8]
steps = [0.001, 0.01, 0.1]
best_gbdtAccuracy = 0
best_gbdtModel = None
for depth in depths:
for step in steps:
gbdt = GBTClassifier(maxIter=100, maxDepth=depth, stepSize=step, featuresCol="features", labelCol="label",
predictionCol="prediction")
gbdtModel = gbdt.fit(train)
gbdtPredictions = gbdtModel.transform(test)
gbdtAccuracy = evaluator.evaluate(gbdtPredictions)
if gbdtAccuracy > best_gbdtAccuracy:
best_gbdtAccuracy = gbdtAccuracy
best_gbdtModel = gbdtModel
print("gbdtModel Test set accuracy = " + str(best_gbdtAccuracy))
reg_params = [0.001, 0.01]
reg_types = ['l1', 'l2']
best_lrAccuracy = 0
best_lrModel = None
for reg_param in reg_params:
lr = LogisticRegression(maxIter=100, regParam=reg_param)
lrModel = lr.fit(train)
lrPredictions = lrModel.transform(test)
lrAccuracy = evaluator.evaluate(lrPredictions)
if lrAccuracy > best_lrAccuracy:
best_lrAccuracy = lrAccuracy
best_lrModel = lrModel
print("lrModel Test set accuracy = " + str(best_lrAccuracy))
steps=[0.005, 0.01, 0.03]
batchs = [32, 64, 128]
best_mlpAccuracy = 0
best_mlpModel = None
for step in steps:
for batch_size in batchs:
mlp = MultilayerPerceptronClassifier(maxIter=100, layers=[6, 32, 8, 2],
blockSize=batch_size, stepSize=step, seed=123)
mlpModel = mlp.fit(train)
mlpPredictions = mlpModel.transform(test)
mlpAccuracy = evaluator.evaluate(mlpPredictions)
if mlpAccuracy > best_mlpAccuracy:
best_mlpAccuracy = mlpAccuracy
best_mlpModel = mlpModel
print("mlpModel Test set accuracy = " + str(best_mlpAccuracy))
depths = [2, 3, 4, 5, 6, 7, 8]
num_trees = [10, 20, 30]
best_rfAccuracy = 0
best_rfModel = None
for depth in depths:
for num_tree in num_trees:
rf = RandomForestClassifier(maxDepth=depth, numTrees=num_tree,
featuresCol="features", labelCol="label",
predictionCol="prediction")
rfModel = rf.fit(train)
rfPredictions = rfModel.transform(test)
rfAccuracy = evaluator.evaluate(rfPredictions)
if rfAccuracy > best_rfAccuracy:
best_rfAccuracy = rfAccuracy
best_rfModel = rfModel
print("rfModel Test set accuracy = " + str(best_rfAccuracy))
从上述结果可以看到,我们训练的randomforest、GBDT、LR和MLP神经网络模型的准确率已经超过0.88了。最后,对前面做的5个模型做一个简单的ensemble,准确率超过了90%。
三、结果分析
仅仅根据姓名达到0.9的准确率,应该算是很不错了,其实,另外将近百分之十的错误主要是一些中性名字、女生使用偏向男生的名字、男生使用偏向女生的名字导致的,比如我就看到原始数据里有个叫‘某莎莎’的,预测模型将其预测为女性,但是其真实性别是男生。这里我就不贴具体结果了,因为是公司项目。很显然,在没有行为数据的情况下,这样的名字总有一部分是错误的,譬如说“某莎莎”,大多数情况下是女生,但是也有一些男生取名某莎莎,这个时候仅仅根据姓名来预测的结果就是将名字叫莎莎的要么都预测为男生要么都预测为女生,当然,如果有了某莎莎的行为数据,那么模型的准确率应该能够得到进一步提升。譬如说,有两个用户,一个男生一个女生,都叫某莎莎,其中一个某莎莎经常购买女生的生活用品,另一个某莎莎经常购买一些男生的衣服之类的,那么这个时候我们就可以有很大的自信将两个某莎莎都预测准确。但是,有些童鞋可能会说,如果两个某莎莎都是女生,只不过经常购买男生衣服的那个某莎莎是帮她男朋友买的而已,那么这个时候模型也会预测错误。嗯~说的没错,这个时候算法也会预测为男生,但我们仔细想想,其实将其预测为男生应该更合理,因为我们我们更加关注的是其行为性别而不是生理性别,譬如说你给这个某莎莎推荐衣服,她对她男朋友特别好,就是经常给她男朋友买衣服,很少给自己买衣服,你给她推荐女生衣服很大的可能性不会点击进去看,然而你给她推荐男生衣服她反而很感兴趣,点击的可能性很大~
更多推荐
所有评论(0)