教你成为全栈工程师(Full Stack Developer) 四十四-如何基于数据统计做网站页面布局的优化和适配

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

移动适配的必要性

pc的页面布局的特点是宽度比较大,一般可以分成两栏或三栏,除了正文部分,左侧和右侧都可以放置一些相关的组件,比如:相关链接、推广等。而移动端宽度一般比较窄,只能做一栏,因此这些相关组件只能放在底部或以其他方式展现。因此特殊针对移动端做适配是有必要的。

 

怎么做移动适配

移动适配属于表现层的范畴,因此最好在前端代码中实现,bootstrap已经为我们抽象出了方便的适配方法,在div布局中可以通过区分class是col-sm-*和col-xs-*来分别表示pc端和移动端的视图,而hidden-xs表示移动端这个div隐藏,这为移动适配提供了极大的方便

 

我是怎么做移动适配的

搜索框的移动适配

文章搜索需求是为了满足用户针对特殊关键词做搜索提供的,放置在了我们网站右上角,如下:

<div class="col-sm-3 hidden-xs">
    <form action="{{ path('blog_search') }}" style="margin-top: 10px;">
        <input type="search" name="q" placeholder="搜文章" maxlength="200" style="background-color: transparent;">
    </form>
</div>

这里面声明了hidden-xs,表示在移动端隐藏,因为在移动端搜索是一个高成本的功能,用户需要手工输入文字,一般情况下,用户在手机主要是阅览,因此这个在手机端做了隐藏

 

右侧系列链接的移动适配

为了方便用户浏览全部相关文章,也为了提升网站的pv,在右侧加入了本文章所属tag的相关链接

首先修改src/AppBundle/Controller/BlogController.php在showAction()方法中添加如下代码:

       $tags = $this->blogPost->getTags();
        $pagination = null;
        if (!empty($tags) && sizeof($tags) > 0) {
            $tag = $tags[0];
            $tagName = $tag->getName();
            $this->em = $this->get('doctrine.orm.entity_manager');
            $this->builder = $this->em->createQueryBuilder();
            $query = $this->builder->select('b')
                ->add('from', 'AppBundle:BlogPost b INNER JOIN b.tags t')
                ->where('t.name=:tag_name')
                ->setParameter('tag_name', $tagName)
                ->getQuery();
            $paginator = $this->get('knp_paginator');
            $pagination = $paginator->paginate(
                $query,
                $request->query->get('page', 1)/*page number*/,
                100/*limit per page*/
            );
        }
	……
	return $this->render('blog/show.html.twig', array('blogpost' => $this->blogPost,
                'latestblogs' => BlogController::getLatestBlogs($this),
                'tophotblogs' => BlogController::getTopHotBlogs($this),
                'is_original' => true,
                'lastblog' => $this->findLastBlog($blogId),
                'nextblog' => $this->findNextBlog($blogId),
                'pagination' => $pagination,
                'tags' => $this->getAllTagNames()
            ));

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

其中的getAllTagNames()方法如下:

    private function getAllTagNames()
    {
        $blogPostRepository = $this->getDoctrine()->getRepository('AppBundle:Tag');
        $tags = $blogPostRepository->findAll();
        return $tags;
    }

 

再修改app/Resources/views/blog/show.html.twig,先把原来的中部文章标题、内容、评论布局原封不动提出来放到重新设计的一个四列网格中的第二列,然后第三列加入如下内容:

        <div class="col-sm-2 hidden-xs">
            <br/>
            <h4>
                {% for tag in blogpost.tags %}
                    系列:{{ tag.name }}
                {% endfor %}
            </h4>
            <div style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">
                {% for article in pagination %}
                    {% if blogpost.id == article.id %}
                        <h6 style="color: red;">{{ article.simpleTitle }}</h6>
                    {% else %}
                        <h6><a href="{{ path('blog_show', {'blogId':article.id}) }}"
                               onclick="_czc.push(['_trackEvent', '右侧链接', '点击', '{{ article.title }}']);"
                            >{{ article.simpleTitle }}</a></h6>
                    {% endif %}
                {% endfor %}
            </div>
            <h4>
                全部系列
            </h4>
            {% for tag in tags %}
                <h6><a href="{{ path('blog_listbytag', {'tagname':tag.name}) }}"
                       onclick="_czc.push(['_trackEvent', '全部系列', '点击', '{{ tag.name }}']);"
                    >{{ tag.name }}</a></h6>
            {% endfor %}
        </div>

讲解一下,根据当前文章所属的tag,找到这个tag下所有的链接并展示,同时再展示全部tag,这都是为了方便用户点击,同时你会发现网格的第三列声明了hidden-xs,也就是移动端不展示,因为移动端屏幕无法容纳两列内容,因此这部分隐藏。另外在右侧链接中我们也加入了点击事件,通过cnzz来统计事件触发情况

看下最终的效果:

 

数据统计

我们观察了一段时间的点击统计如下:

 

我们发现右侧链接的点击次数比页面底部的“最新文章”、“最热文章”点击次数多很多,这说明我们可以完善右侧来替代底部的链接,这是我们基于数据统计来做的页面布局优化的过程

教你成为全栈工程师(Full Stack Developer) 四十三-网站优化必备良器:点击事件的上报与统计

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

为什么要做网站优化

先来看一下我的网站当前的页面:

 

在这个页面中除了正文部分,还有一些链接是希望能够带来用户点击的,比如顶部的github和weibo链接,还有底部的最新文章和最热文章,但是我设计在顶部和底部,而不是设计在正文左侧和右侧,完全是因为我觉得这样好看,然而用户会不会点击我并不清楚,所以我需要埋下点击事件来监控用户的行为,来判断我这样的设计是不是最优的

 

为什么要通过事件上报而不是访问日志

访问日志我们是不清楚用户是点击哪里的链接,即使有referrer字段也无法判断细节,因此我们通过js的点击事件来上报。这样做还有一个好处,就是可以排除掉爬虫的足迹,因为爬虫为了降低成本,一般不会渲染js,也就不会触发点击上报事件。

 

利用cnzz做事件上报和统计

自己实现上报事件需要做的事情包括:定接口、埋js、配置http服务、开发自动统计和可视化等。这一系列工作cnzz已经帮我们实现了大部分了,智者当借力而行,推荐直接用cnzz,当然也有很多其他类似的工具可以选择

cnzz的事件上报文档见http://open.cnzz.com/a/new/trackevent/

首先注册账号添加站点,然后在你要添加事件上报的页面中(可以统一放到模板中)的<head>标签里的地方添加如下代码(这里和官方文档的描述有些不同,因为按照官方文档的方法你页面上总会出现一个跳到cnzz的一个链接):

<script type="text/javascript">
    var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");
    var _czc = _czc || [];
    _czc.push(["_setAccount", "*******"]);
</script>

这里的******替换成你在siteid(可以在你的页面统计代码里找到)

然后在你想上报点击事件的标签里添加如下属性:

onclick="_czc.push(['_trackEvent', category,action,label,value,nodeid);"

比如我埋在github和微博点击事件的代码如下:

<div class="fa fa-github" style="margin-top: 40px; margin-left: 20px;">
    <a href="https://github.com/lcdevelop" style="color: white;"
       onclick="_czc.push(['_trackEvent', 'github链接', '点击']);"
    >
        github
    </a>
</div>
<div class="fa fa-weibo" style="margin-top: 40px; margin-left: 20px;">
    <a href="http://weibo.com/chuangwanglaile" style="color: white;"
       onclick="_czc.push(['_trackEvent', 'weibo链接', '点击']);"
    >
        weibo
    </a>
</div>

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

我在底部“最新文章”和“最热文章”中也埋下了:

<div class="row" style="margin: 10px;margin-left: 0; overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">
    <span style="color: #959595;">({{ article.createDate }})</span>
    <a title="{{ article.title }}" style="color: #959595;"
       href="{{ path('blog_show', {'blogId':article.id}) }}"
       onclick="_czc.push(['_trackEvent', '最新文章', '点击', '{{ article.title }}']);"
    >{{ article.title }}</a>
</div>

<div class=“row” style=“margin: 10px;margin-left: 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"> <span style=“color: #FFFFFF; background-color: #AAAAAA; border-radius: 12px;padding-left: 5px;padding-right: 5px;">{{ article.pv }}</span> <a title="{{ article.title }}” style=“color: #959595;” href="{{ path(‘blog_show’, {‘blogId’:article.id}) }}” onclick="_czc.push(['_trackEvent', ‘最热文章’, ‘点击’, ‘{{ article.title }}']);" >{{ article.title }}</a> </div>

 

以上完成后可以在cnzz后台看到页面上的点击事件统计效果:

我们还可以看点击事件发生的url:

 

还可以看每次点击发生在什么操作系统下:

 

总之,无论是什么点击上报的第三方服务,基本都能覆盖我们想做的各种基础性统计,当然如果想要做更深层次的分析,还需要你自己按照自己的业务逻辑来做进一步挖掘分析

给技术路上迷茫的兄弟

1. 语言是什么不重要,但至少要把一种语言搞精,要懂得精髓 
2. 语言之间都是相通的,一种搞精了,其他的上手都很快,现学现卖 
3. 没有一种语言是最好的,也没有一种语言是万能的,哪个行哪个上,我也搞 php ,但是说“ php 是世界上最好的语言”那个人,你用 php 给我刷个工控板我看看 
4. 计算机生来就是解决问题的,不是用来炫技的,所以不管你现在擅长什么语言,能解决实际问题,你就是人才,把马云、李彦宏、马化腾拉过来编程,你比他们都强,但是人家为什么更算得上人才 
5. 别听大家宣扬国外的工程师文化,哪里都是少数精英多数水军,国内高手如云,只是真人不露相,因为都憋在大公司里呢,是封闭的文化导致的,如果有开放的平台和开放的机制,中国工程师文化一定是最帅的那个 
6. 别听任何人忽悠,做你自己你就是最成功的,哪怕你选择了 ruby ,那也坚持到底,不出 5 年你就是中国最牛的 rubyer 

自己动手做聊天机器人 十六-大话自然语言处理中的囊中取物

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

本篇故事纯属酒后性情大作,如有巧合,纯属雷同

话说天下大事,分久必合,合久必分。

 

之前谈到中文分词把文本切分成一个一个词语,现在我们要反过来,把该拼一起的词再拼到一起,找到一个命名实体,比如:“亚太经合组织”

 

条件随机场的用武之地

上回书说到,概率图模型中的条件随机场适用于在一定观测值条件下决定的随机变量有有限个取值的情况,它特殊就特殊在给定观察序列X时某个特定的标记序列Y的概率是一个指数函数exp(∑λt+∑μs),这也正符合最大熵原理。基于条件随机场的命名实体识别方法属于有监督的学习方法,需要利用已经标注好的大规模语料库进行训练,那么已经标注好的语料里面有什么样的特征能够让模型得以学习呢?

 

谈命名实体的放射性

为什么说命名实体是有放射性的呢?举个栗子:“中国积极参与亚太经合组织的活动”,这里面的“亚太经合组织”是一个命名实体,定睛一瞧,这个实体着实不凡啊,有“组织”两个字,这么说来这个实体是一种组织或机构,记住,下一次当你看到“组织”的时候和前面几个字组成的一定是一个命名实体。继续观察,在它之前辐射出了“参与”一次,经过大规模语料训练后能发现,才“参与”后面有较大概率跟着一个命名实体。继续观察,在它之后有“的活动”,那么说明前面很可能是一个组织者,组织者多半是一个命名实体。这就是基于条件随机场做命名实体识别的奥秘,这就是命名实体的放射性

 

特征模板

前面讲了放射性,那么设计特征模板就比较容易了,我们采用当前位置的前后n个位置上的字/词/字母/数字/标点等作为特征,因为是基于已经标注好的语料,所以这些特征是什么样的词性、词形都是已知的。

特征模板的选择是和具体我们要识别的实体类别有关系的,识别人名和识别机构名用的特征模板是不一样的,因为他们的特点就不一样,事实上识别中文人名和识别英文人名用的特征模板也是不一样的,因为他们的特点就不一样

 

且说命名实体

前面讲了一揽子原理,回过头来讲讲命名实体是什么,命名实体包括:人名(政治家、艺人等)、地名(城市、州、国家、建筑等)、组织机构名、时间、数字、专有名词(电影名、书名、项目名、电话号码等)、……。其实领域很多,不同人需求不一样,关注的范围也不一样。总之不外乎命名性指称、名词性指称和代词性指称

 

自古英雄周围总有谋士

基于条件随机场的命名实体方法虽好,但如何利用好还是需要各路谋士献计献策。有的人提出通过词形上下文训练模型,也就是给定词形上下文语境中产生实体的概率;有的人提出通过词性上下文训练模型,也就是给定词性上下文语境中产生实体的概率;有的人提出通过给定实体的词形串作为实体的概率;有的人提出通过给定实体的词性串作为实体的概率;当大家发现这四点总有不足时,有谋士提出:把四个结合起来!这真是:英雄代有人才出,能摆几出摆几出啊

 

语料训练那些事儿

语料训练那些事儿,且看我机器学习教程相关文章《机器学习精简入门教程》,预知后事如何,下回我也不分解了

自己动手做聊天机器人 十五-一篇文章读懂拿了图灵奖和诺贝尔奖的概率图模型

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

首先我们说说什么是图论

能点进这篇文章说明你一定是有一定数学基础的,所以我做个比喻,你来看看是不是这么回事。糖葫芦吃过吧?几个山楂串在一根杆上,这其实就是一个图。

稍稍正式一点说:图就是把一些孤立的点用线连起来,任何点之间都有可能连着。它区别于树,树是有父子关系,图没有。

再深入一点点:从质上来说,图可以表达的某些事物之间的关联关系,也可以表达的是一种转化关系;从量上来说,它能表达出关联程度,也能表达出转化的可能性大小

图论一般有什么用途呢?著名的七桥问题、四色问题、欧拉定理都是在图论基础上说事儿的

 

再说说概率论

概率论从中学到大学再到工作中都在学,它原理很简单:投个硬币出现人头的概率是1/2,最常用的就是条件概率P(B|A),联合概率P(A,B),贝叶斯公式:P(B|A)=P(A|B)P(B)/P(A),各种估计方法。

 

提前解释一下概率图模型里的几个常见词汇

贝叶斯(Bayes):无论什么理论什么模型,只要一提到他,那么里面一定是基于条件概率P(B|A)来做文章的。ps:贝叶斯老爷爷可是18世纪的人物,他的理论到现在还这么火,可见他的影响力绝不下于牛顿、爱因斯坦

马尔可夫(Markov):无论什么理论什么模型,只要一提到他,那么里面一定有一条链式结构或过程,前n个值决定当前这个值,或者说当前这个值跟前n个值有关

熵(entropy):熵有火字旁,本来是一个热力学术语,表示物质系统的混乱状态。延伸数学上表达的是一种不确定性。延伸到信息论上是如今计算机网络信息传输的基础理论,不确定性函数是f(p)=-logp,信息熵H(p)=-∑plogp。提到熵必须要提到信息论鼻祖香农(Shannon)

场(field):只要在数学里见到场,它都是英文里的“域”的概念,也就是取值空间,如果说“随机场”,那么就表示一个随机变量能够赋值的全体空间

 

再说概率图模型

概率图模型一般是用图来说明,用概率来计算的。所以为了清晰的说明,我们每一种方法我尽量配个图,并配个公式。

首先,为了脑子里有个体系,我们做一个分类,分成有向图模型和无向图模型,顾名思义,就是图里面的边是否有方向。那么什么样的模型的边有方向,而什么样的没方向呢?这个很好想到,有方向的表达的是一种推演关系,也就是在A的前提下出现了B,这种模型又叫做生成式模型。而没有方向表达的是一种“这样就对了”的关系,也就是A和B同时存在就对了,这种模型又叫做判别式模型。生成式模型一般用联合概率计算(因为我们知道A的前提了,可以算联合概率),判别式模型一般用条件概率计算(因为我们不知道前提,所以只能"假设"A条件下B的概率)。生成式模型的代表是:n元语法模型、隐马尔可夫模型、朴素贝叶斯模型等。判别式模型的代表是:最大熵模型、支持向量机、条件随机场、感知机模型等

 

贝叶斯网络

按照前面说的,提到贝叶斯就是条件概率,所以也就是生成式模型,也就是有向图模型。

为了说明什么是贝叶斯网络,我从网上盗取一个图

 

图中每一个点都可能未True或False,他们的概率是已知的,比如x7的概率需要有x4和x5来决定,可能是这样的

x4 x5  T   F

T  T   0.5 0.5

T  F   0.4 0.6

F  T   0.7 0.3

F  F   0.2 0.8

 

那么可以通过上面的贝叶斯网络来估计如果x1为False情况下x6为True的概率:

P(x6=T|x1=F)=P(x6=T,x1=F)/P(x1=F)

这个值继续推导,最终可以由每个节点的概率数据计算求得,这么说来,贝叶斯网络模型可以通过样本学习来估计每个节点的概率,从而达到可以预测各种问题的结果

贝叶斯网络能够在已知有限的、不完整的、不确定信息条件下进行学习推理,所以广泛应用在故障诊断、维修决策、汉语自动分词、词义消歧等问题上

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

 

马尔可夫模型和隐马尔可夫模型

按照前面说的,提到马尔可夫就是一个值跟前面n个值有关,所以也就是条件概率,也就是生成式模型,也就是有向图模型。

继续盗图

 

音乐的每一个音不是随意作出来的,是根据曲子的风格、和弦、大小调式等来决定的,但是因为可选的音高有多种,也就出现了无数美妙的旋律。因为有约束,所以其实可以说新的音和前面的n个音有关,这其实是一个马尔可夫模型可以解释的事情。

马尔可夫模型还可以看成是一个关于时间t的状态转换过程,也就是随机的有限状态机,那么状态序列的概率可以通过计算形成该序列所有状态之间转移弧上的概率乘积得出。

如果说这个马尔可夫是两阶的,那么转移概率可能是这个样子:

 

当然后面的概率只是举了个例子,这种情况由前两列决定的第三列任意值都会有一个概率

我们通过训练样本来得出每一个概率值,这样就可以通过训练出的模型来根据前两个音是什么而预测下一个音是1、2、3、4、5任意一个的概率是多少了,也就是可以自动作曲了,当然这样做出的曲子肯定是一个无线循环的旋律,你猜猜为什么。

 

那么我们再说隐马尔可夫模型,这里的“隐”指的是其中某一阶的信息我们不知道,就像是我们知道人的祖先是三叶虫,但是由三叶虫经历了怎样的演变过程才演变到人的样子我们是不知道的,我们只能通过化石资料了解分布信息,如果这类资料很多,那么就可以利用隐马尔可夫模型来建模,因为缺少的信息较多,所以这一模型的算法比较复杂,比如前向算法、后向算法之类晦涩的东西就不说了。相对于原理,我们更关注它的应用,隐马尔可夫模型广泛应用在词性标注、中文分词等,为什么能用在这两个应用上呢?仔细想一下能看得出来,比如中文分词,最初你是不知道怎么分词的,前面的词分出来了,你才之后后面的边界在哪里,但是当你后面做了分词之后还要验证前面的分词是否正确,这样前后有依赖关系,而不确定中间状态的情况最适合用隐马尔可夫模型来解释

 

最大熵模型

按照前面所说的,看到熵那么一定会用到H(p)=-∑plogp,怎么理解最大熵模型呢?我们的最终目的是想知道在某一个信息条件B下,得出某种可能的结果A的最大的概率,也就是条件概率P(A|B)最大的候选结果。因为最大熵就是不确定性最大,其实也就是条件概率最大,所以求最大的条件概率等同于求最大熵,而我们这里的熵其实是H(p)=H(A|B)=-∑p(b)p(a|b)log(p(a|b)),为了使用训练数据做估计,这里的p(a|b)可以通过训练数据的某些特征来估计,比如这些特征是fi(a,b),那么做模型训练的过程就编程了训练∑λf(a,b)中的λ参数的过程,至此就有些像机器学习的线性回归了,该怎么做就清晰了。所以其实最大熵模型就是利用熵的原理和熵的公式来用另外一种形式来描述具有概率规律的现实的

 

条件随机场

场表示取值范围,随机场表示随机变量有取值范围,也就是每个随机变量有固定的取值,条件指的是随机变量的取值由一定的条件概率决定,而这里的条件来自于我们有一些观察值,这是它区别于其他随机场的地方。条件随机场也可以看做是一个无向图模型,它特殊就特殊在给定观察序列X时某个特定的标记序列Y的概率是一个指数函数exp(∑λt+∑μs),其中t是转移函数,s是状态函数,我们需要训练的是λ和μ。条件随机场主要应用在标注和切分有序数据上,尤其在自然语言处理、生物信息学、机器视觉、网络智能等方面

 

总结一下,概率图模型包括多种结合概率论和图论的模型,根据特定场景特定需求选择不同的模型,每种模型的参数都需要大量样本训练得出,每种模型都是用来根据训练出来的概率做最优结论选择的,比如根据训练出来的模型对句子做最正确的词性标注、实体标注、分词序列等,本文只是从理念上的解释和总结,真的用到某一种模型还是需要深入研究原理和公式推导以及编程实现,那就不是本文这种小篇幅能够解释的完的了,等我们后面要遇到必须用某一种模型来实现时再狠狠地深入一下。

自己动手做聊天机器人 十四-探究中文分词的艺术

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

中文分词是怎么走到今天的

话说上个世纪,中文自动分词还处于初级阶段,每句话都要到汉语词表中查找,有没有这个词?有没有这个词?所以研究集中在:怎么查找最快、最全、最准、最狠......,所以就出现了正向最大匹配法、逆向最大匹配法、双向扫描法、助词遍历法......,用新世纪比较流行的一个词来形容就是:你太low了!

中文自动分词最难的两个问题:1)歧义消除;2)未登陆词识别。说句公道话,没有上个世纪那么low的奠定基础,也就没有这个世纪研究重点提升到这两个高级的问题

ps:未登录词就是新词,词表里没有的词

本世纪计算机软硬件发展迅猛,计算量存储量都不再是问题,因此基于统计学习的自动分词技术成为主流,所以就出现了各种新分词方法,也更适用于新世纪文本特点

 

从n元语法模型开始说起

上节讲到了n元语法模型,在前n-1个词出现的条件下,下一个词出现的概率是有统计规律的,这个规律为中文自动分词提供了统计学基础,所以出现了这么几种统计分词方法:N-最短路径分词法、基于n元语法模型的分词法

N-最短路径分词法其实就是一元语法模型,每个词成为一元,独立存在,出现的概率可以基于大量语料统计得出,比如“确实”这个词出现概率的0.001(当然这是假设,别当真),我们把一句话基于词表的各种切词结果都列出来,因为字字组合可能有很多种,所以有多个候选结果,这时我们利用每个词出现的概率相乘起来,得到的最终结果,谁最大谁就最有可能是正确的,这就是N-最短路径分词法。

这里的N的意思是说我们计算概率的时候最多只考虑前N个词,因为一个句子可能很长很长,词离得远,相关性就没有那么强了

这里的最短路径其实是传统最短路径的一种延伸,由加权延伸到了概率乘积

而基于n元语法模型的分词法就是在N-最短路径分词法基础上把一元模型扩展成n元模型,也就是统计出的概率不再是一个词的概率,而是基于前面n个词的条件概率

 

人家基于词,我来基于字

由字构词的分词方法出现可以说是一项突破,发明者也因此得到了各项第一和很多奖项,那么这个著名的分词法是怎么做的呢?

每个字在词语中都有一个构词位置:词首、词中、词尾、单独构词。根据一个字属于不同的构词位置,我们设计出来一系列特征,比如:前一个词、前两个词、前面词长度、前面词词首、前面词词尾、前面词词尾加上当前的字组成的词……

我们基于大量语料库,利用平均感知机分类器对上面特征做打分,并训练权重系数,这样得出的模型就可以用来分词了,句子右边多出来一个字,用模型计算这些特征的加权得分,得分最高的就是正确的分词方法

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

 

分词方法纵有千万种,一定有适合你的那一个

分词方法很多,效果上一定是有区别的,基于n元语法模型的方法的优势在于词表里已有的词的分词效果,基于字构词的方法的优势在于未登陆词的识别,因此各有千秋,你适合哪个就用哪个。

 

异性相吸,优势互补

既然两种分词各有优缺点,那么就把他们结合起来吧,来个插值法折中一下,用过的人都说好

 

流行分词工具都是用的什么分词方法

jieba中文分词

官方描述:

  • 基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG)
  • 采用了动态规划查找最大概率路径, 找出基于词频的最大切分 组合
  • 对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法

前两句话是说它是基于词表的分词,最后一句是说它也用了由字构词,所以它结合了两种分词方法

 

ik分词器

基于词表的最短路径切词

 

ltp云平台分词

主要基于机器学习框架并部分结合词表的方法

 

其他分词工具判断方法类似,网上对各种分词工具好坏的判断多数是功能上比较,个人建议通过原理来判断,如果结合了基于词表和由字构词并且充分利用统计学习的方法,这样的分词工具才是最好的

自己动手做聊天机器人 十三-把语言模型探究到底

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

什么是数学模型

数学模型是运用数理逻辑方法和数学语言建构的科学或工程模型。说白了,就是用数学的方式来解释事实。举个简单的例子:你有一只铅笔,又捡了一只,一共是两只,数学模型就是1+1=2。举个复杂的例子:你在路上每周能捡到3只铅笔,数学模型就是P(X)=3/7,这个数学模型可以帮你预测明天捡到铅笔的可能性。当然解释实事的数学模型不是唯一的,比如每周捡三只铅笔的数学模型还可能是P(qt=sj|qt-1=si,qt-2=sk,...),s=0,1,也就是有两个状态的马尔可夫模型,意思就是明天是否捡到铅笔取决于前几天有没有捡到铅笔

 

什么是数学建模

数学建模就是通过计算得到的结果来解释实际问题,并接受实际的检验,来建立数学模型的全过程。

 

什么是语言模型

语言模型是根据语言客观事实而进行的语言抽象数学建模。说白了,就是找到一个数学模型,让它来解释自然语言的事实。

 

业界认可的语言模型

业界目前比较认可而且有效的语言模型是n元语法模型(n-gram model),它本质上是马尔可夫模型,简单来描述就是:一句话中下一个词的出现和最近n个词有关(包括它自身)。详细解释一下:

如果这里的n=1时,那么最新一个词只和它自己有关,也就是它是独立的,和前面的词没关系,这叫做一元文法

如果这里的n=2时,那么最新一个词和它前面一个词有关,比如前面的词是“我”,那么最新的这个词是“是”的概率比较高,这叫做二元文法,也叫作一阶马尔科夫链

依次类推,工程上n=3用的是最多的,因为n越大约束信息越多,n越小可靠性更高

n元语法模型实际上是一个概率模型,也就是出现一个词的概率是多少,或者一个句子长这个样子的概率是多少。

这就又回到了之前文章里提到的自然语言处理研究的两大方向:基于规则、基于统计。n元语法模型显然是基于统计的方向。

 

概率是如何统计的

说到基于统计,那么就要说概率是如何估计的了,通常都是使用最大似然估计,怎么样理解“最大似然估计”,最大似然就是最最最最最相似的,那么和谁相似,和历史相似,历史是什么样的?10个词里出现过2次,所以是2/10=1/5,所以经常听说过的“最大似然估计”就是用历史出现的频率来估计概率的方法。这么说就懂了吧?

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

语言模型都有哪些困难

1. 千变万化的自然语言导致的0概率问题

基于统计的自然语言处理需要基于大量语料库进行,而自然语言千变万化,可以理解所有词汇的笛卡尔积,数量大到无法想象,有限的语料库是难以穷举语言现象的,因此n元语法模型会出现某一句话出现的概率为0的情况,比如我这篇博客在我写出来之前概率就是0,因为我是原创。那么这个0概率的问题如何解决呢?这就是业界不断在研究的数据平滑技术,也就是通过各种数学方式来让每一句话的概率都大于0。具体方法不列举,都是玩数学的,比较简单,无非就是加个数或者减个数或者做个插值平滑一下,效果上应用在不同特点的数据上各有千秋。平滑的方法确实有效,各种自然语言工具中都实现了,直接用就好了。

 

2. 特定领域的特定词概率偏大问题

每一种领域都会有一些词汇比正常概率偏大,比如计算机领域会经常出现“性能”、“程序”等词汇,这个解决办法可以通过缓存一些刚刚出现过的词汇来提高后面出现的概率来解决。当然这里面是有很多技巧的,我们并不是认为所有出现过的词后面概率都较大,而是会考虑这些词出现的频率和规律(如:词距)来预测。

 

3. 单一语言模型总会有弊端

还是因为语料库的不足,我们会融合多种语料库,但因为不同语料库之间的差异,导致我们用单一语言模型往往不够准确,因此,有一种方法可以缓和这种不准确性,那就是把多种语言模型混到一起来计算,这其实是一种折中,这种方法low且有效。

还有一种方法就是用多种语言模型来分别计算,最后选择熵最大的一种,这其实也是一种折中,用在哪种地方就让哪种模型生效。

 

神经网络语言模型

21世纪以来,统计学习领域无论什么都要和深度学习搭个边,毕竟计算机计算能力提升了很多,无论多深都不怕。神经网络语言模型可以看做是一种特殊的模型平滑方式,本质上还是在计算概率,只不过通过深层的学习来得到更正确的概率。

 

语言模型的应用

这几乎就是自然语言处理的应用了,有:中文分词、机器翻译、拼写纠错、语音识别、音子转换、自动文摘、问答系统、OCR等

自己动手做聊天机器人 十二-教你如何利用强大的中文语言技术平台做依存句法和语义依存分析

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

什么是依存句法分析呢?

叫的晦涩的术语,往往其实灰常简单,句法就是句子的法律规则,也就是句子里成分都是按照什么法律规则组织在一起的。而依存句法就是这些成分之间有一种依赖关系。什么是依赖:没有你的话,我存在就是个错误。“北京是中国的首都”,如果没有“首都”,那么“中国的”存在就是个错误,因为“北京是中国的”表达的完全是另外一个意思了。

 

什么是语义依存分析呢?

“语义”就是说句子的含义,“张三昨天告诉李四一个秘密”,那么语义包括:谁告诉李四秘密的?张三。张三告诉谁一个秘密?李四。张三什么时候告诉的?昨天。张三告诉李四什么?秘密。

 

语义依存和依存句法的区别

依存句法强调介词、助词等的划分作用,语义依存注重实词之间的逻辑关系

另外,依存句法随着字面词语变化而不同,语义依存不同字面词语可以表达同一个意思,句法结构不同的句子语义关系可能相同。

 

依存句法分析和语义依存分析对我们的聊天机器人有什么意义呢?

依存句法分析和语义分析相结合使用,对对方说的话进行依存和语义分析后,一方面可以让计算机理解句子的含义,从而匹配到最合适的回答,另外如果有已经存在的依存、语义分析结果,还可以通过置信度匹配来实现聊天回答。

 

依存句法分析到底是怎么分析的呢?

依存句法分析的基本任务是确定句式的句法结构(短语结构)或句子中词汇之间的依存关系。依存句法分析最重要的两棵树:

依存树:子节点依存于父节点

依存投射树:实线表示依存联结关系,位置低的成分依存于位置高的成分,虚线为投射线

 

依存关系的五条公理

1. 一个句子中只有一个成分是独立的

2. 其他成分直接依存于某一成分

3. 任何一个成分都不能依存于两个或两个以上的成分

4. 如果A成分直接依存于B成分,而C成分在句子中位于A和B之间,那么C或者直接依存于B,或者直接依存于A和B之间的某一成分

5. 中心成分左右两面的其他成分相互不发生关系

 

什么地方存在依存关系呢?比如合成词(如:国内)、短语(如:英雄联盟)很多地方都是

 

LTP依存关系标记

主谓关系

SBV

subject-verb

我送她一束花 (我 <-- 送)

动宾关系

VOB

直接宾语,verb-object

我送她一束花 (送 --> 花)

间宾关系

IOB

间接宾语,indirect-object

我送她一束花 (送 --> 她)

前置宾语

FOB

前置宾语,fronting-object

他什么书都读 (书 <-- 读)

兼语

DBL

double

他请我吃饭 (请 --> 我)

定中关系

ATT

attribute

红苹果 (红 <-- 苹果)

状中结构

ADV

adverbial

非常美丽 (非常 <-- 美丽)

动补结构

CMP

complement

做完了作业 (做 --> 完)

并列关系

COO

coordinate

大山和大海 (大山 --> 大海)

介宾关系

POB

preposition-object

在贸易区内 (在 --> 内)

左附加关系

LAD

left adjunct

大山和大海 (和 <-- 大海)

右附加关系

RAD

right adjunct

孩子们 (孩子 --> 们)

独立结构

IS

independent structure

两个单句在结构上彼此独立

核心关系

HED

head

指整个句子的核心

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

那么依存关系是怎么计算出来的呢?

是通过机器学习和人工标注来完成的,机器学习依赖人工标注,那么都哪些需要我们做人工标注呢?分词词性、依存树库、语义角色都需要做人工标注,有了这写人工标注之后,就可以做机器学习来分析新的句子的依存句法了

 

 

LTP云平台怎么用?

首先注册用户,得到每月免费20G的流量,在http://www.ltp-cloud.com/注册一个账号,注册好后登陆并进入你的dashboard:http://www.ltp-cloud.com/dashboard/,可以看到自己唯一的api_key,我的保密,就不贴出来了,在dashboard里还可以查询自己流量使用情况

具体使用方法如下(参考http://www.ltp-cloud.com/document):

curl -i "http://api.ltp-cloud.com/analysis/?api_key=YourApiKey&text=我是中国人。&pattern=dp&format=plain"

把这里的YourApiKey换成你自己的api_key,得到结果如下:

我_0 是_1 SBV
是_1 -1 HED
中国_2 人_3 ATT
人_3 是_1 VOB
。_4 是_1 WP

通过这个接口修改pattern参数可以做很多工作,比如:

分词(pattern=ws):

GET http://api.ltp-cloud.com/analysis/?api_key=YourApiKey&text=我是中国人。&pattern=ws&format=plain
我 是 中国 人 。

 

词性标注(pattern=pos):

GET http://api.ltp-cloud.com/analysis/?api_key=YourApiKey&text=我是中国人。&pattern=pos&format=plain
我_r 是_v 中国_ns 人_n 。_wp

 

命名实体识别(pattern=ner):

GET http://api.ltp-cloud.com/analysis/?api_key=YourApiKey&text=我是中国人。&pattern=ner&format=plain
我 是 [中国]Ns 人 。

 

语义依存分析(pattern=sdp):

GET http://api.ltp-cloud.com/analysis/?api_key=YourApiKey&text=我是中国人。&pattern=sdp&format=plain
我_0 是_1 Exp
是_1 -1 Root
中国_2 人_3 Nmod
人_3 是_1 Clas
。_4 是_1 mPunc

语义角色标注(pattern=srl):

GET http://api.ltp-cloud.com/analysis/?api_key=YourApiKey&text=我是中国人。&pattern=srl&format=plain
[我]A0 [是]v [中国 人]A1 。

 

免费终究会有限制,无论是流量还是速度还是一次性分析文本大小,LTP平台有有一定限制,这也是可以理解的,毕竟为大家开放了科研必备的资源和技术,成本也是需要控制的。

自己动手做聊天机器人 十一-0字节存储海量语料资源

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

关键词提取

互联网资源无穷无尽,如何获取到我们所需的那部分语料库呢?这需要我们给出特定的关键词,而基于问句的关键词提取上一节已经做了介绍,利用pynlpir库可以非常方便地实现关键词提取,比如:

# coding:utf-8
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
import pynlpir
pynlpir.open()
s = '怎么才能把电脑里的垃圾文件删除'
key_words = pynlpir.get_key_words(s, weighted=True)
for key_word in key_words:
    print key_word[0], '\t', key_word[1]
pynlpir.close()

提取出的关键词如下:

电脑     2.0
垃圾     2.0
文件     2.0
删除     1.0

 

我们基于这四个关键词来获取互联网的资源就可以得到我们所需要的语料信息

 

充分利用搜索引擎

有了关键词,想获取预料信息,还需要知道几大搜索引擎的调用接口,首先我们来探索一下百度,百度的接口是这样的:

https://www.baidu.com/s?wd=机器学习 数据挖掘 信息检索

把wd参数换成我们的关键词就可以拿到相应的结果,我们用程序来尝试一下:

首先创建scrapy工程,执行:

scrapy startproject baidu_search

自动生成了baidu_search目录和下面的文件(不知道怎么使用scrapy,请见我的文章教你成为全栈工程师(Full Stack Developer) 三十-十分钟掌握最强大的python爬虫

创建baidu_search/baidu_search/spiders/baidu_search.py文件,内容如下:

# coding:utf-8
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
import scrapy
class BaiduSearchSpider(scrapy.Spider):
    name = "baidu_search"
    allowed_domains = ["baidu.com"]
    start_urls = [
            "https://www.baidu.com/s?wd=机器学习"
    ]
    def parse(self, response):
        print response.body

这样我们的抓取器就做好了,进入baidu_search/baidu_search/目录,执行:

scrapy crawl baidu_search

我们发现返回的数据是空,下面我们修改配置来解决这个问题,修改settings.py文件,把ROBOTSTXT_OBEY改为

ROBOTSTXT_OBEY = False

并把USER_AGENT设置为:

USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'

为了避免抓取hang住,我们添加如下超时设置:

DOWNLOAD_TIMEOUT = 5

再次执行

scrapy crawl baidu_search

这次终于可以看到大片大片的html了,我们临时把他写到文件中,修改parse()函数如下:

    def parse(self, response):
        filename = "result.html"
        with open(filename, 'wb') as f:
            f.write(response.body)

重新执行后生成了result.html,我们用浏览器打开本地文件如下:

说明我们抓取到了正确的结果

 

语料提取

上面得到的仅是搜索结果,它只是一种索引,真正的内容需要进入到每一个链接才能拿到,下面我们尝试提取出每一个链接并继续抓取里面的内容,那么如何提取链接呢,我们来分析一下result.html这个抓取百度搜索结果文件

 

我们可以看到,每一条链接都是嵌在class=c-container这个div里面的一个h3下的a标签的href属性

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

所以我们的提取规则就是:

hrefs = response.selector.xpath('//div[contains(@class, "c-container")]/h3/a/@href').extract()

修改parse()函数并添加如下代码:

        hrefs = response.selector.xpath('//div[contains(@class, "c-container")]/h3/a/@href').extract()
        for href in hrefs:
            print href

 

执行打印出:

……
2016-06-30 09:22:51 [scrapy] DEBUG: Crawled (200) <GET https://www.baidu.com/s?wd=%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0> (referer: None)
http://www.baidu.com/link?url=ducktBaLUAdceZyTkXSyx3nDbgLHoYlDVgAGlxPwcNNrOMQrbatubNKGRElo0VWua26AC7JRD2pLxFcaUBjcOq
http://www.baidu.com/link?url=PGU6qW3zUb9g5uMT3W1O4VxPmoH-Fg-jolx8rBmBAeyOuXUl0wHzzNPkX3IDS5ZFSSSHyaBTjHd5f2r8CXBFjSctF9SGKaVock5xaJNuBCy
http://www.baidu.com/link?url=JMirHAkIRJWI_9Va7HNc8zXWXU7JeTYhPGe66cOV4Zi5LH-GB7IQvVng4Gn35IiVhsUYP3IFyn6MKRl4_-byca
http://www.baidu.com/link?url=Et9xy9Qej4XRmLB9UdFUlWD_AugxoDxQt-BZHCFyZEDPYzEx52vL_jsr_AvkNLHC-TfLThm0dKs21IGR1QA6h_
http://www.baidu.com/link?url=Ajb1DXzWj9A6KAYicHl4wS4RV6iDuy44kP_j-G0rbOHYQy5IR5JOigxbJERsqyH3
http://www.baidu.com/link?url=uRDMnVDsmS7sD4frNv8EHd2jKSvOB5PtqxeT8Q7MFzRyHPIVTYyiWEGNReHAbRymMnWOxqF_CSQOXL87v3o4qa
http://www.baidu.com/link?url=18j6NZUp8fknmM1nUYIfsmep5H0JD39k8bL7CkACFtKdD4whoTuZy0ZMsCxZzZOj
http://www.baidu.com/link?url=TapnMj78otilz-AR1NddZCSfG2vqcPYGNCYRu9_z70rmAKWqIVAvjV06iJvcvuECGDbwAefdsAmGRHba6TDpFMV1Pk-_JRs_bt9iE4T3bVi
http://www.baidu.com/link?url=b1j-GMumC7s5eDXTHIMPpsdL7HtxrP4Rb_kw0GNo3z2ZSlkhLVd_4aFEzflPGArPHv7VBtZ1xbyHo3JtG0PEZq
http://www.baidu.com/link?url=dG3GISijkExWf6Sy6Zn1xk_k--eGPUl1BrTCLRBxUOaS4jlrpX-PzV618-5hrCeos2_Rzaqrh0SecqYPloZfbyaj6wHSfbJHG9kFTvY6Spi
2016-06-30 09:22:51 [scrapy] INFO: Closing spider (finished)
……

 

下面我们把这些url添加到抓取队列中继续抓取,修改baidu_search.py文件,如下:

    def parse(self, response):
        hrefs = response.selector.xpath('//div[contains(@class, "c-container")]/h3/a/@href').extract()
        for href in hrefs:
            yield scrapy.Request(href, callback=self.parse_url)
    def parse_url(self, response):
        print len(response.body)

 

抓取效果如下:

……
2016-06-30 09:26:52 [scrapy] DEBUG: Crawled (200) <GET https://www.baidu.com/s?wd=%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0> (referer: None)
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://book.douban.com/subject/1102235/> from <GET http://www.baidu.com/link?url=S1kmtqU1ZBDaSKlVXdeKfNtyv7fErWDMC_TuOEXdedXEe2DzoMqRbMdbejbC4vts4MHm5NQUIRbk0Y0QdohY5_>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://www.kuqin.com/shuoit/20140512/339858.html> from <GET http://www.baidu.com/link?url=_6fKf9IjO_EJ4hw91Y6RnfXnqS5u8VmwvDsJh3tduapsgXKQb-nMjsxMRPLW1bt5JlnzJPgOobHQwyHTgkWolK>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://wenku.baidu.com/link?url=7pAXoiFZz4alDMOjp-41OJaONe3B86GMEiFu96bqQy8qakk37vouey5Q-SxL7oN-r9mnNukKgVjN8iOloEKQoeEmgKLzukIFkX_rpr3dhy3> from <GET http://www.baidu.com/link?url=7pAXoiFZz4alDMOjp-41OJaONe3B86GMEiFu96bqQy8qakk37vouey5Q-SxL7oN-r9mnNukKgVjN8iOloEKQoeEmgKLzukIFkX_rpr3dhy3>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://blog.csdn.net/zouxy09/article/details/16955347> from <GET http://www.baidu.com/link?url=5dh-19wDKE_agNpwz_9YTm01wHLJ9IxBfrZPVWo6RfFECGmIW7bt0vk6POhWDN04O4QHem_v8-iYLTzoeXmQZK>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://open.163.com/special/opencourse/machinelearning.html> from <GET http://www.baidu.com/link?url=ti__XlRN8Oij0rFvqxfTtJz-dLhng6NANkAVwwISlHQ4nKOhRXNSJQhzekflnnFuuW5033lDRcqywOlqrzoANUhB0yQf3Nq-pXMWmBQO7x7>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://www.guokr.com/group/262/> from <GET http://www.baidu.com/link?url=cuifybqWoLRMULYGe70JCzyrZMEKL9GgfAa6V7p_7ONb7Q6KzXPad5zMfIYsKqN6>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://mooc.guokr.com/course/16/Machine-Learning/> from <GET http://www.baidu.com/link?url=93Yp_GA3ZLnSwjN5YREAML4sP5BthETto8Psn7ty5VJHoMB95gWhKTT6iDBFHeAfHjDhqwCf-NBrgeoP7YD1zq>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://tieba.baidu.com/f?kw=%BB%FA%C6%F7%D1%A7%CF%B0&fr=ala0&tpl=5> from <GET http://www.baidu.com/link?url=EjCvUWhJWV1_FEgNyetjTAu6HqImgl-A2229Lp8Kl3BfpcqlrSLOUabc-bzgn6KD1Wbg_s547FunrFp79phQTqXuIx6tkn9NGBhSqxhYUhm>
2016-06-30 09:26:52 [scrapy] DEBUG: Redirecting (302) to <GET http://www.geekpark.net/topics/213883/> from <GET http://www.baidu.com/link?url=kvdmirs22OQAj10KSbGstZJtf8L74bTgd4p1AxYk6c2B9lP_8_nSrLNDlfb9DHW7>
……

看起来能够正常抓取啦,下面我们把抓取下来的网页提取出正文并尽量去掉标签,如下:

    def parse_url(self, response):
        print remove_tags(response.selector.xpath('//body').extract()[0])

 

下面,我们希望把百度搜索结果中的摘要也能够保存下来作为我们语料的一部分,如下:

    def parse(self, response):
        hrefs = response.selector.xpath('//div[contains(@class, "c-container")]/h3/a/@href').extract()
        containers = response.selector.xpath('//div[contains(@class, "c-container")]')
        for container in containers:
            href = container.xpath('h3/a/@href').extract()[0]
            title = remove_tags(container.xpath('h3/a').extract()[0])
            c_abstract = container.xpath('div/div/div[contains(@class, "c-abstract")]').extract()
            abstract = ""
            if len(c_abstract) > 0:
                abstract = remove_tags(c_abstract[0])
            request = scrapy.Request(href, callback=self.parse_url)
            request.meta['title'] = title
            request.meta['abstract'] = abstract
            yield request
    def parse_url(self, response):
        print "url:", response.url
        print "title:", response.meta['title']
        print "abstract:", response.meta['abstract']
        content = remove_tags(response.selector.xpath('//body').extract()[0])
        print "content_len:", len(content)

 

解释一下,首先我们在提取url的时候顺便把标题和摘要都提取出来,然后通过scrapy.Request的meta传递到处理函数parse_url中,这样在抓取完成之后也能接到这两个值,然后提取出content,这样我们想要的数据就完整了:url、title、abstract、content

百度搜索数据几乎是整个互联网的镜像,所以你想要得到的答案,我们的语料库就是整个互联网,而我们完全借助于百度搜索引擎,不必提前存储任何资料,互联网真是伟大!

之后这些数据想保存在什么地方就看后面我们要怎么处理了,欲知后事如何,且听下回分解

我是怎么三个月把个人博客做到日访问量(pv)5000而且不花一分钱的

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

个人博客如今并不好做,因为难以盈利,所以如果不是有一番热血和强烈爱好者,都很难坚持下去,而且最主要的问题是质量低的文章和各种转帖、抄袭太泛滥了,好文章也会被淹没。我是一个喜欢分享的人,我的初衷是心怀一腔热血,希望把自己多年积累的经验分享出去,让更多的人受益,所以我除了分享知识以外,也希望把我个人的推广方法分享出来。

 

有图有真相,我先把我的cnzz统计数据贴上来,然后再说我认为最重要的八点经验

 

 

经验之一:做一个标题党

其实看到本文的标题你就已经看出来了,我是一个在标题上都愿意下功夫的人。

举一个我第一个成功推广的例子,我6月9号的时候在v2ex发了一个标题党的帖子,这个帖子只有一个标题,没有任何内容,结果这成为了我最大的流量来源,不出一天,这个帖子迎来了5000多次点击,70多个收藏,如果感兴趣可以观摩一下(地址在https://www.v2ex.com/t/284399?p=1),唯一的标题是“原创了一个全栈工程师教程,欢迎拍砖”,当时我的v2ex账号上没有任何我的网站的信息,所以就这一个标题,瞬间挤满了评论,可喜的是站内有牛人,他根据我的用户名挖到了我的github(我发誓没有顾演员噢),猜出了链接,引流量正式开始,后来我才补充了网址链接进去。正如你所想的,这绝非偶然,而是源自我的精心设计。

再举一个例子,最初我的前几篇文章的题目不是现在的样子,而是纯技术内容的标题,当我意识到只有标题有吸引力才能让用户点击时,我重新把标题都换了一遍,比如说这篇:《教你成为全栈工程师(Full Stack Developer) 一-各显神通总结八大类编程语言的区别》,再比如:《教你成为全栈工程师(Full Stack Developer) 八-10行代码建起你的网站》,实事上并不是10行代码,而是10行“重要”代码。再回到本篇文章的标题《我是怎么三个月把个人博客做到日访问量(pv)5000而且不花一分钱的》,这里面也需要推敲,我说的是日访问量,并不是日均访问量,因为有高有低,最高是那么多,但日均就没那么多了。

 

经验之二:按系列组织文章

不知道你在逛朋友圈、微博、头条的时候有没有注意到,当你想系统了解某方面知识的时候,是找不到这样的文章的,因为都是各说各的,每篇都是独立存在的,这让我很头疼,所以我自己决定自己的文章要尽量组织成系列,虽然也独立成篇,但是要像一个教程一样,让人从头了解到尾。当然,咱还得回到本文主题“流量”上来,按系列组织文章对流量帮助非常大,因为我的第二大流量来源就是“推酷”app上有人把我的github项目https://github.com/lcdevelop/FullStackDeveloperCourse(我的博客同步列表)分享出来,题目是:《系列文章:教你成为全栈工程师》,内容就是我的博客地址列表,因为是系列文章,所以吸引了非常多的点击。无独有偶,好事成双,我另外一套系列文章《自己动手做聊天机器人》也有同样的效果,都引来了非常多的流量,而且因为网上有很多人转帖,流量一直保持着。

 

经验之三:好好利用github

github是IT人的聚集地,github不只用来管理代码,也成了知识分享的地方,同时也成了推广利器,而且用户群体都比较精准,你会发现在github上star数最多的不是写得好的代码,而是组织的好的知识体系,所以如果你的文章是成体系的,建议也同步到这里,作为你在圈子里的长线渠道。顺便推广一下我的github:https://github.com/lcdevelop,欢迎关注

请尊重原创,转载请注明来源网站www.lcsays.com以及原始链接地址

经验之四:多管齐下

不要把自己吊在一棵树上,这样只有死路一条,同时把自己的文章转发到多个地方,就像投资一样,让各处都有流量,这样总的流量才能更大。比如我会把文章分享到“开发者头条”app上,每天都会给自己带来很多点击,可喜的是我还得到了“开发者头条”官方微博的关注,他也转发了我的系列文章,他有数万粉丝,自然转发数、收藏数一路飙升啦。再比如我也会把写好的文章地址转发到新浪博客、51cto、百度贴吧等很多个博客、社区,这些转发除了带来流量外还能帮助搜索引擎快速收录和形成反链,提升你网站的权重,未来搜索引擎还会成为流量的重要来源

 

经验之五:掐好时间点

人最宝贵的是时间,网站推广最宝贵的也是时间,尤其是在恰到好处的时间点做正确的事。还说v2ex那个标题党的例子,刚好在帖子火到快100条回复的第二天,我开始回复大家的留言,因为这个时间刚刚好,太早的话标题党的计划就会失效,太晚的话帖子会被其他新贴淹没,只有恰到好处才能继续把帖子顶起来,这个事情虽小,但足以说明时间点的重要性。另外一个例子,就是我创建github博客同步列表项目的时间敢的刚刚好,《教你成为全栈工程师》写了40篇,虽然没结束,但是事不宜迟,赶快建github项目,因为过早,文章数目少,而且不够成体系,最重要的就是项目上线那一刹那,当时行就行,当时不行后面再补效果就不一样了,如果过晚,黄花菜都凉了,流量就是这样,要一阵一阵的来,有高潮迭起的感觉来的才叫爽。

 

经验之六:自己造势

雷军经常强调创业要造势,大事造势小事也可以造势,自己有5分的实力,可以夸大到7分,即给自己信心,也能让别人关注。比如我另外一个系列文章叫《自己动手做聊天机器人》,这个事情是一个非常有挑战性的事情,因为据我所知没有人做到,但是我能做到吗?我也没有百分之百的把握,但是我只要说出去就可以惊起一片涟漪,当然这绝不是光说不做,因为我是有相关知识积累并且有思路的,所以不管我能不能做到,我的目标是这个,我就一定会用最大的努力做,越难的事情就越吸引我,自然也就越吸引更多人关注。

 

经验之七:坚持原创

说到底,没有货做再多也是白扯。我能够在短短3个月时间连续写出73篇原创文章,不是一时爆发,也不是生憋硬造,而是厚积薄发,我从事IT技术行业多年,一直钻研技术,不断学习,不断积累,锻造而成。但是,实事上博文里的内容并不是我真正的积累的知识,而是我最新学习的知识,我真正的积累是搜索架构、搜索策略、分布式计算、分布式存储,但是为了督促我不断学习新知识,我只发新学的知识,比如web开发、机器学习、大数据、人工智能,一方面了解和分享新鲜事物,一方面宣传个人品牌,当我后面如果时间不足的时候,也会把我最擅长的部分以系列教程的形式分享出来。话说回来,我希望别人转发我的文章,但我更鼓励原创。

 

经验之八:你的用户都是初学者

我其实并不喜欢网上那种自认为自己是专家的态度的文章,其实谁都做不到面面俱到,同一个领域总有比你强的人才,所以放低姿态,以学习的态度交流,写一些不太深奥的内容,分享一些自己犯过错误的方面是极好的,因为你的用户多数都是初学者,只有少数人喜欢深究深奥的内容,不要觉得自己说的别人看不懂自己就是专家,其实能让每一个人看的懂你才是专家。总而言之,放低姿态,把用户都当做初学者,清晰明了的分享知识,让大家共同融入,才是一个好的分享生态。

 

最后我的总结是:营销推广永远没有固定套路,当你从别人那里读到了他的营销之道的时候,它就已经失效了,所以最重要的是你要自己动脑,每个人都与众不同。