华杰手把手教你大数据分析

  题目貌似取得有些大,准确的说应该叫基于大数据的机器学习,不过就这样吧>_<

  

  每当说到大数据分析,有些人就很讳莫如深,故意讲得很复杂,生怕别人听懂就low了。然而其实可能没那么复杂,就像陈皓说的——所谓大数据不就是因为硬盘便宜了,所以不用删日志了吗?  <_<

 

  好了,废话不多说,这次实现的目标很简单,就是通过已知数据,通过某人的姓名分析出他的性别。如你所知,中国的姓名那是千千万万,不像老外来来回回就是那几个名字,拿个数据表对照一下就可以了——毛子更懒,男的叫朱可夫,女的就叫朱可娃,自带性别标识,生怕别人以为自己是伪娘。。。

  也许此刻你或许会问这有什么用啊,简单来说你想给自己的网站做一个性别统计,并分析出各自的爱好,购买习惯等,类似淘宝每年的公众那个统计报表,此时就可以用到——也许你会说可以直接统计用户信息里面啊,然而你确定有多少用户会愿意填?又有多少是认真的呢?不过有一个数据一般是真实的,那就是快递单及收货人姓名!

 

  以下内容均在win10+python2.7+mysql5.5上验证通过。

 

  数据分析,数据分析,没数据当然不行,所以程序未动,数据先行。本次我选择的是某2000w的那个数据——不要问我为什么会有,这不是本次的重点——之所以选择这个是有一定理由的,这个我下面会说到。

  首先这次我们要做的是基于中文名的数据,所以老外很多开源的训练数据库直接over了。。。然后要有足够的基础量,也就是说作为训练数据库应该有200w左右的数据,这样可以保证数据的覆盖面足够广。其次需要有自检功能,也就是说我能通过已知的数据去修复某些受损数据,且不带来其他任何影响,这点尤其重要!因此你可以选择这个2000w或者某数字订票的。。。

  不过这个数据也并不是完美的,最明显的一点就是本身其性别差就很大,男的多,女的少,而标准的训练数据应该保证所有姓名的单字值总和为0,即未计算前这个名字是男是女各是0.5,不过影响不算特别大,可以通过程序修正部分。

  导数据这部分我就不说了,导完之后就是苦逼的洗数据。这是大头,也是占这次示例里面时间最多的部分。

  1、筛选出是中文名的数据,并在info表添加一个is_China。

  select * from info where not name regexp '^[1-9A-Za-z]';

   或者直接删除这部分不用的数据

  delete from info where  name regexp '^[1-9A-Za-z]';

 

  2、进行数据自检

  之前说过之所以选择这个数据,一个很重要的原因就是可以自检。因为你可以通过身份证号来重新计算性别。

  如果你之前已经看过这个数据库,应该会发现其中有很多的数据实际上是不对的,比如,你查看“雯”这个字,会发现几乎男女的性别是各一半,这显然是不对的——当然也有一种可能,就是现在已经基佬遍地了<_<

  为此,首先第一步是将正确的身份证号筛选出来,虽然你可以通过相互对照来修复部分身份证,但还是不推荐这么做,所以只需将不符合规则的身份证给剔除掉。

  delete FROM info
  WHERE
      is_China = 1
  AND CtfTp = 'ID'
  AND (CHAR_LENGTH(CtfId) <>18 and CHAR_LENGTH(CtfId) <>15) 

  当有了正确的身份证之后,就可以进行自检修复了。

    update info a inner join
    (
    SELECT
        id,
        NAME,
        Gender,
        CASE (CASE CHAR_LENGTH(CtfId)
        WHEN 18 THEN substring(CtfId, 17, 1)
        ELSE substring(CtfId, 15, 1)
        END)%2
        WHEN 0 THEN 'F'
        WHEN 1 THEN 'M'
        END sex,
        CtfId
        
    FROM
        `info`
    WHERE
        is_China = 1
    AND CtfTp = 'ID') b
    set a.Gender = b.sex 
    where a.id=b.id

  以上SQL基本上没什么难度,就是截取和更新。执行的时候,你可以出去喝杯咖啡,或者运动一番,又或是去趟卫生间。。。反正什么打发时间做什么。

  基本上上述工作做完,你的可用数据在180w左右。

  

  3、建立字符表,将文本转化为数值

  首先先建表

  CREATE TABLE `name` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `chars` varchar(2) COLLATE utf8_unicode_ci DEFAULT NULL,
    `val` int(11) DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `IDX_NAME` (`chars`,`val`)
  ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

 

  这里我偷懒选择了将值直接插入数据库,即每个文字都是有多行的,而不是分类统计的方法,如果你有兴趣可以试着改写一下表结构,val变成三列——男、女、总和,使得读取更加快速方便。

  接着我们就要往里面灌数据了。虽然用复杂的SQL应该也能实现,不过这里我们使用python来完成这项工作。如果你对python还不是很熟悉,可以去这里学习一下

  

  

#encoding=utf-8
import sys
import MySQLdb
import random
import time
import traceback
import math

reload(sys)
sys.setdefaultencoding('utf-8') #设置Python的默认编码为 utf-8

########################################################################


db=MySQLdb.connect(host="localhost",user="root",passwd="",charset='utf8')
cur=db.cursor(cursorclass = MySQLdb . cursors . DictCursor )    #让返回的是字典类型
cur.execute('use 2000w')
cur.execute('SELECT id,Name,Gender FROM `info` WHERE is_China=1;')
rets=cur.fetchall()

chars=[]
chars_gender=[]
for ret in rets:
    length=len(ret['Name'])/2
    char=ret['Name'][length:]
    for x in xrange(length,len(char)+1):
        c=char[x-1:x]
        chars.append(c);
        sex=0
        if(ret['Gender']=='M'):
            sex=1
        else:
            sex=-1
        chars_gender.append(sex)

for k in xrange(0,len(chars)):
    
    sql="INSERT INTO name (chars, val) VALUES ('"+chars[k]+"',"+(str)(chars_gender[k])+");"
    # print sql
    try:
        cur.execute(sql)
        db.commit()        #加上这句之后才会提交执行,否则不执行
    except:
        # 发生错误时回滚
        db.rollback()

 

  现在知道我为什么偷懒了吧,因为这样可以少些很多行,顺带可以不用动脑筋——哈哈哈哈哈哈哈哈——pia飞。。。

  接着你又可以去喝杯咖啡,上趟厕所了。。。

  至此,我们的数据处理部分就全部结束了。是不是很简单呢。理论上应该没什么不容易理解的,那么,OK,下面就是使用这些数据了。

 

  模型设计。老实说,这部分一般都是由Scientist来设计完成的,不过这次我们不需要这么复杂,就用最简单的条件概率就OK了。

  条件概率,如果你还记的高中或大学的知识的话应该知道,他是计算在某条件下某事发生的概率。因此我们将这次的命题转化一下就可以知道,其实质是已知我们选了某字则该字是属于女生/男生的概率。至于公式的话,自己翻书吧。

 

  好,接下来就到了coding时间了。废话不多说,直接上代码

 

  

#encoding=utf-8
import sys
import MySQLdb
import random
import time
import traceback
import math
import decimal

reload(sys)
sys.setdefaultencoding('utf-8') #设置Python的默认编码为 utf-8

########################################################################

name=raw_input('please input name:');
name=name.decode("gbk")
chars=[]
length=len(name)/2
char=name[length:]
for x in xrange(length,len(char)+1):
    c=char[x-1:x]
    chars.append(c);

# 简单的叠字处理修正

chars_unique=set(chars)

is_overlapping=False

if len(chars_unique)!=len(chars):
    is_overlapping=True

db=MySQLdb.connect(host="localhost",user="root",passwd="",charset='utf8')
cur=db.cursor(cursorclass = MySQLdb . cursors . DictCursor )    #让返回的是字典类型
cur.execute('use 2000w')

# sql="SELECT Gender,COUNT(Name) total_num FROM `info` WHERE is_China=1 GROUP BY Gender"
# cur.execute(sql)
# rets=cur.fetchall()
# F_total_num=rets[0]['total_num']
# M_total_num=rets[1]['total_num']
# total_num=M_total_num+F_total_num
# 加速运行 每次都去统计其实意义不大,因为当数量足够大时,微小的变化并不会影响统计结果,因为在那之前精度已经不足了
total_num=1870562
F_total_num=562496
M_total_num=1308066

pro1_arr=[]
pro2_arr=[]
overlapping_word=''
for x in xrange(0,len(chars)):
    sql="SELECT SUM(val) v FROM `name` WHERE chars='" +chars[x]+ "' GROUP BY val"
    cur.execute(sql)
    rets=cur.fetchall()

    if(len(rets)==1):
        if(rets[0]['v']>=0):
            m_nums=rets[0]['v']
            f_nums=0;
        else:
            f_nums=rets[0]['v']
            m_nums=0;
    else:
        try: 
            f_nums=rets[0]['v']
        except: 
            f_nums=0

        try: 
            m_nums=rets[1]['v']
        except: 
            m_nums=0    


    if f_nums==0 and m_nums==0:
        # 此处为不存在的字符做异常处理,可以调用类似createSex.py的方法将不存在的数据加入那么表
        print "Sorry,I don't know the name sex,maybe you can help me"
        sys.exit(0)

    char_total_num=abs(m_nums)+abs(f_nums)
    pro1_val=(abs(f_nums)/total_num)/(char_total_num/total_num)
    pro2_val=(abs(m_nums)/total_num)/(char_total_num/total_num)
    pro1_arr.append(pro1_val)
    pro2_arr.append(pro2_val)

    if overlapping_word==chars[x]:
        if pro1_val > 0.8 or pro2_val > 0.8:
            is_overlapping=False
    else:
        overlapping_word=chars[x]

pro1=sum(pro1_arr)/len(chars);
pro2=sum(pro2_arr)/len(chars);

if is_overlapping:
    pro1+=decimal.Decimal(0.3)
    pro2-=decimal.Decimal(0.3)

if pro1>decimal.Decimal(1):   pro1=decimal.Decimal(1);   pro2=decimal.Decimal(0);
if pro1>pro2: print "The Name have "+(str)(pro1*100)+" is a woman name"; else: print "The Name have "+(str)(pro2*100)+" is a man name";

 

  看到这里,也许有人会说,卧槽,这不是坑爹吗?就这100来行的代码就完成了?这他喵的也算大数据分析?但是,why not ?

  好了,收起无谓的口水仗吧,来看看我们的程序做了什么。第一将新的名字处理成单字,然后分别再去计算每个单字的条件概率,最后将所有的概率相加然后平均。然后还为叠字做了一些小小的处理。别看虽然代码不多,但如果只看结果的话,还是可以接受的,基本上可以达到80%以上的识别率(日文名字不行,哪怕是汉字,不要问我为什么——自己往前看,当然有例外,比如西木野真姬<_<)。

  是不是感觉很简单!蹭蹭几下,你就会大数据分析了!(伪

  

  如你所见,除了陆无双判断有些失误之外其他均可以,当然这里还有一部分原因是由于之前提到过的本身数据问题造成的,还有部分是程序的原因,比如这边计算总的概率时只是简单的相加平均,这会导致某些字由于两极分化严重而导致总结果的不准确,因此应该才用加权计算来消磨掉这部分的错误。当然其他方法也是有的,我在这里只是做一个抛砖引玉的作用,如果各位有兴趣或者有更好的思路欢迎来这里,互相探♂讨

 

转载于:https://www.cnblogs.com/buckets/p/4890764.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值