机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

2017年11月7日23:44:34 61 6,483 °C
摘要

上篇文章机器学习实战教程(四):朴素贝叶斯基础篇之言论过滤器讲解了朴素贝叶斯的基础知识。本篇文章将在此基础上进行扩展,你将看到以下内容:拉普拉斯平滑、垃圾邮件过滤(Python3)、新浪新闻分类(sklearn)

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

一、前言

上篇文章机器学习实战教程(四):朴素贝叶斯基础篇之言论过滤器讲解了朴素贝叶斯的基础知识。本篇文章将在此基础上进行扩展,你将看到以下内容:

  • 拉普拉斯平滑
  • 垃圾邮件过滤(Python3)
  • 新浪新闻分类(sklearn)

二、朴素贝叶斯改进之拉普拉斯平滑

上篇文章提到过,算法存在一定的问题,需要进行改进。那么需要改进的地方在哪里呢?利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算p(w0|1)p(w1|1)p(w2|1)。如果其中有一个概率值为0,那么最后的成绩也为0。我们拿出上一篇文章的截图。

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

从上图可以看出,在计算的时候已经出现了概率为0的情况。如果新实例文本,包含这种概率为0的分词,那么最终的文本属于某个类别的概率也就是0了。显然,这样是不合理的,为了降低这种影响,可以将所有词的出现数初始化为1,并将分母初始化为2。这种做法就叫做拉普拉斯平滑(Laplace Smoothing)又被称为加1平滑,是比较常用的平滑方法,它就是为了解决0概率问题。

除此之外,另外一个遇到的问题就是下溢出,这是由于太多很小的数相乘造成的。学过数学的人都知道,两个小数相乘,越乘越小,这样就造成了下溢出。在程序中,在相应小数位置进行四舍五入,计算结果可能就变成0了。为了解决这个问题,对乘积结果取自然对数。通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。下图给出函数f(x)和ln(f(x))的曲线。

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

检查这两条曲线,就会发现它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。因此我们可以对上篇文章的trainNB0(trainMatrix, trainCategory)函数进行更改,修改如下:

运行代码,就可以得到如下结果:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

瞧,这样我们得到的结果就没有问题了,不存在0概率。当然除此之外,我们还需要对代码进行修改classifyNB(vec2Classify, p0Vec, p1Vec, pClass1)函数,修改如下:

为啥这么改?因为取自然对数了。logab = loga + logb。

这样,我们的朴素贝叶斯分类器就改进完毕了。

三、朴素贝叶斯之过滤垃圾邮件

在上篇文章那个简单的例子中,我们引入了字符串列表。使用朴素贝叶斯解决一些现实生活中的问题时,需要先从文本内容得到字符串列表,然后生成词向量。下面这个例子中,我们将了解朴素贝叶斯的一个最著名的应用:电子邮件垃圾过滤。首先看一下使用朴素贝叶斯对电子邮件进行分类的步骤:

  • 收集数据:提供文本文件。
  • 准备数据:将文本文件解析成词条向量。
  • 分析数据:检查词条确保解析的正确性。
  • 训练算法:使用我们之前建立的trainNB0()函数。
  • 测试算法:使用classifyNB(),并构建一个新的测试函数来计算文档集的错误率。
  • 使用算法:构建一个完整的程序对一组文档进行分类,将错分的文档输出到屏幕上。

1、收集数据

数据我已经为大家准备好了,可以在我的Github上下载: 

有两个文件夹ham和spam,spam文件下的txt文件为垃圾邮件。

2、准备数据

对于英文文本,我们可以以非字母、非数字作为符号进行切分,使用split函数即可。编写代码如下:

这样我们就得到了词汇表,结果如下图所示:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

根据词汇表,我们就可以将每个文本向量化。我们将数据集分为训练集和测试集,使用交叉验证的方式测试朴素贝叶斯分类器的准确性。编写代码如下:

运行结果如下:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

函数spamTest()会输出在10封随机选择的电子邮件上的分类错误概率。既然这些电子邮件是随机选择的,所以每次的输出结果可能有些差别。如果发现错误的话,函数会输出错误的文档的此表,这样就可以了解到底是哪篇文档发生了错误。如果想要更好地估计错误率,那么就应该将上述过程重复多次,比如说10次,然后求平均值。相比之下,将垃圾邮件误判为正常邮件要比将正常邮件归为垃圾邮件好。为了避免错误,有多种方式可以用来修正分类器,这些内容会在后续文章中进行讨论。

这部分代码获取:

四、朴素贝叶斯之新浪新闻分类(Sklearn)

1、中文语句切分

考虑一个问题,英文的语句可以通过非字母和非数字进行切分,但是汉语句子呢?就比如我打的这一堆字,该如何进行切分呢?我们自己写个规则?

幸运地是,这部分的工作不需要我们自己做了,可以直接使用第三方分词组件,即jieba,没错就是"结巴"。

jieba已经兼容Python2和Python3,使用如下指令直接安装即可:

Python中文分词组件使用简单:

新闻分类数据集我也已经准备好,可以到我的Github进行下载:

数据集已经做好分类,分文件夹保存,分类结果如下:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

数据集已经准备好,接下来,让我们直接进入正题。切分中文语句,编写如下代码:

代码运行结果如下所示,可以看到,我们已经顺利将每个文本进行切分,并进行了类别标记。

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

2、文本特征选择

我们将所有文本分成训练集和测试集,并对训练集中的所有单词进行词频统计,并按降序排序。也就是将出现次数多的词语在前,出现次数少的词语在后进行排序。编写代码如下:

all_words_list就是将所有训练集的切分结果通过词频降序排列构成的单词合集。观察一下打印结果,不难发现,这里包含了很多标点符号,很显然,这些标点符号是不能作为新闻分类的特征的。总不能说,应为这个文章逗号多,所以它是xx类新闻吧?为了降低这些高频的符号对分类结果的影响,我们应该怎么做呢?答曰:抛弃他们! 除了这些,还有"在","了"这样对新闻分类无关痛痒的词。并且还有一些数字,数字显然也不能作为分类新闻的特征。所以要消除它们对分类结果的影响,我们可以定制一个规则。

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

一个简单的规则可以这样制定:首先去掉高频词,至于去掉多少个高频词,我们可以通过观察去掉高频词个数和最终检测准确率的关系来确定。除此之外,去除数字,不把数字作为分类特征。同时,去除一些特定的词语,比如:"的","一","在","不","当然","怎么"这类的对新闻分类无影响的介词、代词、连词。怎么去除这些词呢?可以使用已经整理好的stopwords_cn.txt文本。下载地址:

这个文件是这个样子的:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

所以我们可以根据这个文档,将这些单词去除,不作为分类的特征。我们先去除前100个高频词汇,然后编写代码如下:

运行结果如下:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

可以看到,我们已经滤除了那些没有用的词组,这个feature_words就是我们最终选出的用于新闻分类的特征。随后,我们就可以根据feature_words,将文本向量化,然后用于训练朴素贝叶斯分类器。这个向量化的思想和第三章的思想一致,因此不再累述。

3、使用Sklearn构建朴素贝叶斯分类器

数据已经处理好了,接下来就可以使用sklearn构建朴素贝叶斯分类器了。

官方英文文档地址:

朴素贝叶斯是一类比较简单的算法,scikit-learn中朴素贝叶斯类库的使用也比较简单。相对于决策树,KNN之类的算法,朴素贝叶斯需要关注的参数是比较少的,这样也比较容易掌握。在scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先验为高斯分布的朴素贝叶斯,MultinomialNB就是先验为多项式分布的朴素贝叶斯,而BernoulliNB就是先验为伯努利分布的朴素贝叶斯。上篇文章讲解的先验概率模型就是先验概率为多项式分布的朴素贝叶斯。

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

对于新闻分类,属于多分类问题。我们可以使用MultinamialNB()完成我们的新闻分类问题。另外两个函数的使用暂且不再进行扩展,可以自行学习。MultinomialNB假设特征的先验概率为多项式分布,即如下式:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

其中, P(Xj = Xjl | Y = Ck)是第k个类别的第j维特征的第l个取值条件概率。mk是训练集中输出为第k类的样本个数。λ为一个大于0的常数,常常取值为1,即拉普拉斯平滑,也可以取其他值。

接下来,我们看下MultinamialNB这个函数,只有3个参数:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

参数说明如下:

  • alpha:浮点型可选参数,默认为1.0,其实就是添加拉普拉斯平滑,即为上述公式中的λ ,如果这个参数设置为0,就是不添加平滑;
  • fit_prior:布尔型可选参数,默认为True。布尔参数fit_prior表示是否要考虑先验概率,如果是false,则所有的样本类别输出都有相同的类别先验概率。否则可以自己用第三个参数class_prior输入先验概率,或者不输入第三个参数class_prior让MultinomialNB自己从训练集样本来计算先验概率,此时的先验概率为P(Y=Ck)=mk/m。其中m为训练集样本总数量,mk为输出为第k类别的训练集样本数。
  • class_prior:可选参数,默认为None。

总结如下:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

除此之外,MultinamialNB也有一些方法供我们使用:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

MultinomialNB一个重要的功能是有partial_fit方法,这个方法的一般用在如果训练集数据量非常大,一次不能全部载入内存的时候。这时我们可以把训练集分成若干等分,重复调用partial_fit来一步步的学习训练集,非常方便。GaussianNB和BernoulliNB也有类似的功能。 在使用MultinomialNB的fit方法或者partial_fit方法拟合数据后,我们可以进行预测。此时预测有三种方法,包括predict,predict_log_proba和predict_proba。predict方法就是我们最常用的预测方法,直接给出测试集的预测类别输出。predict_proba则不同,它会给出测试集样本在各个类别上预测的概率。容易理解,predict_proba预测出的各个类别概率里的最大值对应的类别,也就是predict方法得到类别。predict_log_proba和predict_proba类似,它会给出测试集样本在各个类别上预测的概率的一个对数转化。转化后predict_log_proba预测出的各个类别对数概率里的最大值对应的类别,也就是predict方法得到类别。具体细节不再讲解,可参照官网手册。

了解了这些,我们就可以编写代码,通过观察取不同的去掉前deleteN个高频词的个数与最终检测准确率的关系,确定deleteN的取值:

运行结果如下:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

我们绘制出了deleteNs和test_accuracy的关系,这样我们就可以大致确定去掉前多少的高频词汇了。每次运行程序,绘制的图形可能不尽相同,我们可以通过多次测试,来决定这个deleteN的取值,然后确定这个参数,这样就可以顺利构建出用于新闻分类的朴素贝叶斯分类器了。我测试感觉450还不错,最差的分类准确率也可以达到百分之50以上。将if __name__ == '__main__'下的代码修改如下:

运行结果:

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

五、总结

  • 在训练朴素贝叶斯分类器之前,要处理好训练集,文本的清洗还是有很多需要学习的东西。
  • 根据提取的分类特征将文本向量化,然后训练朴素贝叶斯分类器。
  • 去高频词汇数量的不同,对结果也是有影响的的。
  • 拉普拉斯平滑对于改善朴素贝叶斯分类器的分类效果有着积极的作用。
  • 如有问题,请留言。如有错误,还望指正,谢谢!

PS: 如果觉得本篇本章对您有所帮助,欢迎关注、评论、赞!

本文出现的所有代码和数据集,均可在我的github上下载,欢迎Follow、Star:github.com/Jack-Cherish

weinxin
微信公众号
分享技术,乐享生活:Jack Cui公众号每周五推送“程序员欢乐送”系列资讯类文章,欢迎您的关注!
Jack Cui

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:61   其中:访客  34   博主  27

    • avatar 呆头代劳 来自天朝的朋友 谷歌浏览器 Windows 7 湖南省湘潭市 联通 1

      test_accuracy_list.append(test_accuracy)
      ave = lambda c: sum(c) / len(c)
      print(ave(test_accuracy_list))
      请问test_accuracy只有一个浮点数,为什么还要有append和这个lambda?直接print(test_accuracy),是还有其他后招吗?

        • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 10 北京市 百度网讯科技联通节点

          @呆头代劳 为了保存所有精度啊。后面可以看精度曲线。

            • avatar 呆头代劳 来自天朝的朋友 谷歌浏览器 Windows 7 湖南省湘潭市 联通 1

              @Jack Cui 喔喔,不好意思,跳过了deleteNs的确定部分:lol: ,最终程序才可以不要 ,谢谢! :mrgreen:

          • avatar Susy Australia 谷歌浏览器 Mac OS X 10_13_5 北京市 微软(中国)有限公司 2

            listOfTokens = re.split(r’\W+’, bigString) 这里得是加号才行。另外文件路径可以用path join一下,否则有些编辑器运行时会找不到文件。

              • avatar Jack Cui Admin 来自天朝的朋友 火狐浏览器 Windows 7 北京市 百度网讯科技联通节点

                @Susy *零次或多次也行吧?

                  • avatar 浪淘尽 来自天朝的朋友 谷歌浏览器 Windows 7 浙江省杭州市 电信 1

                    @Jack Cui 零次好像就把单词也给切割了,比如Word就成了W o r d

                      • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                        @浪淘尽 soga~ :wink:

                  • avatar twpsuperman 来自天朝的朋友 QQ浏览器 Windows 7 重庆市 电信 4

                    博主请问下程序这里: listOfTokens=re.split(r’\W*’,bigString)
                    运行是FutureWarning: split() requires a non-empty pattern match. return _compile(pattern, flags).split(string, maxsplit)
                    改成 listOfTokens=re.split(r’\W+’,bigString)这样才没有警告,不知道为什么。
                    在网上查了很久也没看明白,麻烦博主给我解释下。

                      • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                        @twpsuperman 正则表达式的问题,+是至少一个,*是任意一个。

                          • avatar twpsuperman 来自天朝的朋友 QQ浏览器 Windows 7 重庆市 电信 4

                            @Jack Cui 谢谢!

                        • avatar twpsuperman 来自天朝的朋友 QQ浏览器 Windows 7 重庆市 电信 4

                          for t in range(deleteN, len(all_words_list), 1):
                          if n > 1000: # feature_words的维度为1000
                          break
                          请问这里为什么选择n>1000呢?
                          还有就是每次执行时文本特征选取的个数都不同,
                          经过词频降序排序的训练集列表all_words_list里的总个数也是不同的。
                          请问这是什么原因呢?
                          def text_features(text, feature_words): # 出现在特征集中,则置1。哪里来的text呢

                            • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                              @twpsuperman 维度自己定,你想用多少维度的可以设置。不同是因为统计出来的不同啊。

                            • avatar 黑大小学生 来自天朝的朋友 谷歌浏览器 Windows 8.1 黑龙江省 移动 3

                              博主在新浪新闻分类中说“在scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先验为高斯分布的朴素贝叶斯,MultinomialNB就是先验为多项式分布的朴素贝叶斯,而BernoulliNB就是先验为伯努利分布的朴素贝叶斯。上篇文章讲解的先验概率模型就是先验概率为多项式分布的朴素贝叶斯。”这里的“上篇文章”指的是《机器学习四》简易言论过滤器那篇吗?
                              另外,想问问博主,拿文本分类为例,MultinomialNB和GaussianNB在计算贝叶斯公式中的“p(w1|c类)、p(w2|c类)……p(wn|c类)”这些条件概率时,计算方法一样吗?MultinomialNB和GaussianNB各自适合什么情况使用呢?
                              以下是我在别的博客上看到的,不知道对不对,还请博主看一下,麻烦啦!
                              2.1多项式模型
                              基本原理:
                              在多项式模型中, 设某文档d=(t1,t2,…,tk),tk是该文档中出现过的单词,允许重复,则
                              先验概率P(c)= 类c下单词总数/整个训练样本的单词总数
                              类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)
                              V是训练样本的单词表(即抽取单词,单词出现多次,只算一个),|V|则表示训练样本包含多少种单词。 P(tk|c)可以看作是单词tk在证明d属于类c上提供了多大的证据,而P(c)则可以认为是类别c在整体上占多大比例(有多大可能性)。

                              2.2伯努利模型
                              基本原理:
                              P(c)= 类c下文件总数/整个训练样本的文件总数
                              P(tk|c)=(类c下包含单词tk的文件数+1)/(类c下文件总数+2)

                                • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                                  @黑大小学生 对就是指的那篇文章。
                                  区别你可以看着个:https://www.cnblogs.com/pinard/p/6074222.html
                                  讲得很详细。

                                    • avatar 黑大小学生 来自天朝的朋友 谷歌浏览器 Windows 8.1 黑龙江省 移动 3

                                      @Jack Cui 感谢博主回复,推荐博客我看过啦!
                                      博主你先看一下我前面提问的那个留言呗,里面有我摘自别人博客的关于多项式和伯努利在计算条件概率“p(w1|c类)、p(w2|c类)……p(wn|c类)”的计算方法的异同,您看一下所说的对不对呗!
                                      如果说的对的话,还有一些疑问烦请博主解惑!
                                      在简易言论过滤器中博主说使用的是多项式的朴素贝叶斯(垃圾邮件分类与简易言论的代码如出一辙,由此可见使用的也是多项式的),若多项式模型中,类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)正确,那您为什么在对训练集中的训练文本向量化时不用词袋模型而用词集模型呢?还有就是,为什么设置p0Denom = 2,p1Denom = 2而不是所创建的词汇表(用来向量化训练集中的训练文本)中所含的单词数量呢?
                                      博主,我今天看了一天这个问题,也想了一天,着实捉摸不透!希望博主有时间的时候能讲解一下,万分感谢您!

                                        • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                                          @黑大小学生 朴素贝叶斯,就是假设先验概率属于什么分布,如果数据是离散的,那就用多项式分布,如果是非常稀疏的离散值,即各个特征出现概率很低,那就用伯努利分布,如果是数据是连续的,就用正态分布。
                                          显然,这里的数据适合使用多项式分布。这里使用词袋模型还是词集模型,个人理解是一种统计方法的不同而已,词袋模型是一种基于词频的统计,词集模型是一种基于空间向量的统计。
                                          p0Denom和p1Denom是引入了拉普拉斯平滑,就相当于公式里的λ。

                                            • avatar 黑大小学生 来自天朝的朋友 谷歌浏览器 Windows 8.1 黑龙江省 移动 3

                                              @Jack Cui 博主,请问您推荐的博客文章https://www.cnblogs.com/pinard/p/6074222.html中
                                              “MultinomialNB类使用总结”中的公式 P(Xj=xjl|Y=Ck)=(xjl+λ)/(mk+nλ)
                                              其中的n是什么含义呀?是第j维特征Xj的取值个数?还是特征向量X=(X1,X2,X3,…….)的特征维数呢?

                                              • avatar 黑大小学生 来自天朝的朋友 谷歌浏览器 Windows 8.1 黑龙江省 移动 3

                                                @Jack Cui 博主,求解求解呀!感谢感谢啦!

                                              • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                                                @黑大小学生 看这个:http://www.cnblogs.com/pinard/p/6069267.html
                                                有对应的公式详解。

                                          • avatar 黑大小学生 来自天朝的朋友 谷歌浏览器 Windows 8.1 黑龙江省 移动 3

                                            博主,您本文中对文本向量化时,是根据feature_words这个词汇表来的(假设词汇表含有n个单词),即将文本转化为向量X=(x1,x2,x3,…,xn),这里的x1一直到xn取值非0即1,含义是文本中是否含有词汇表中相应位置的单词。按照您的这种文本向量化,不正应该适合用伯努利朴素贝叶斯模型吗?怎么就适合用多项式了呢?
                                            感谢博主百忙之中回复!盼复!

                                              • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                                                @黑大小学生 我理解是伯努利分布是多项式分布的特殊情况吧。可以看下这个:https://blog.csdn.net/michael_r_chang/article/details/39188321

                                              • avatar 黑大小学生 来自天朝的朋友 谷歌浏览器 Windows 8.1 黑龙江省 移动 3

                                                博主,什么叫做稀疏的多元离散值?能举个例子吗
                                                比如某n维特征向量X=(x1,x2,…,xn),x1的取值个数有6个分别为1,2,3,4,5,6,这6种应该就是多元离散值的意思吧?那稀疏该怎么解释呢?

                                                  • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                                                    @黑大小学生 多元就是多个特征把,多个维度的。离散的就是分布没有规律。

                                                  • avatar donghonor 来自天朝的朋友 谷歌浏览器 Windows 10 山东省东营市 联通 2

                                                    额……博主GitHub的资料没办法colone or download……

                                                      • avatar donghonor 来自天朝的朋友 谷歌浏览器 Windows 10 山东省东营市 联通 2

                                                        @donghonor 好吧, 我错了,我没注意原来不是根目录啊,现在找到了,打扰了哈

                                                          • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器  Android 8.0.0 MIX 2 Build/OPR1.170623.027 辽宁省沈阳市 联通GSM/WCDMA/LTE共用出口

                                                            @donghonor 加油

                                                        • avatar anonymous 来自天朝的朋友 谷歌浏览器 Windows 10 广东省广州市天河区 电信 1

                                                          :cool: 博主厉害

                                                            • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器  Android 8.0.0 MIX 2 Build/OPR1.170623.027 辽宁省沈阳市 联通GSM/WCDMA/LTE共用出口

                                                              @anonymous 感谢支持

                                                            • avatar 似水无痕 来自天朝的朋友 谷歌浏览器 Windows 10 安徽省马鞍山市 铁通 0

                                                              wc,亲学长,东北大学计算机本科学弟前来报道,学长方便加个联系方式吗,qq 825091124

                                                                • avatar Jack Cui Admin 来自天朝的朋友 谷歌浏览器 Windows 7 辽宁省沈阳市 东北大学三舍南(研究生)

                                                                  @似水无痕 已加。