精华内容
下载资源
问答
  • 2020-12-03 22:58:37

    Preface?前 言为什么要写本书?Python是什么?Python是一种带有动态语义的、解释性的、面向对象的不错编程语言。其不错内置数据结构,结合动态类型和动态绑定,使其对于敏捷软件开发非常具有吸引力。同时,Python作为脚本型(胶水)语言连接现有的组件也十分高效。Python语法简洁,可读性强,从而能降低程序的维护成本。不仅如此,Python支持模块和包,鼓励程序模块化和代码重用。

    Python语言的解释性使其语法更接近人类的表达和思维过程,开发程序的效率极高。习惯使用Python者,总习惯在介绍Python时强调一句话:“人生苦短,我用Python。”由于没有编译步骤,“写代码—测试—调试”的流程能被快速地反复执行。

    作为一款用途广泛的语言,Python在数据分析与机器学习领域的表现,称得上“一任群芳妒”。2016年3月,国外知名技术问答社区StackOverflow发布了《2016年开发者调查报告》。此调查号称是有史以来为全面的开发者调查。其中,数据科学家的十大技术栈中,有7个包含Python。具体来说,数据科学家中有63%正在使用Python,44%正在使用R语言。而且,27%的人同时使用这两种语言。Python还在“多人使用的技术”“受欢迎技术”“需求度高技术”等榜单中名列前十。

    Python的明显优势:

    Preface?前    言为什么要写本书?Python是什么?Python是一种带有动态语义的、解释性的、面向对象的不错编程语言。其不错内置数据结构,结合动态类型和动态绑定,使其对于敏捷软件开发非常具有吸引力。同时,Python作为脚本型(胶水)语言连接现有的组件也十分高效。Python语法简洁,可读性强,从而能降低程序的维护成本。不仅如此,Python支持模块和包,鼓励程序模块化和代码重用。

    Python语言的解释性使其语法更接近人类的表达和思维过程,开发程序的效率极高。习惯使用Python者,总习惯在介绍Python时强调一句话:“人生苦短,我用Python。”由于没有编译步骤,“写代码—测试—调试”的流程能被快速地反复执行。

    作为一款用途广泛的语言,Python在数据分析与机器学习领域的表现,称得上“一任群芳妒”。2016年3月,国外知名技术问答社区StackOverflow发布了《2016年开发者调查报告》。此调查号称是有史以来为全面的开发者调查。其中,数据科学家的十大技术栈中,有7个包含Python。具体来说,数据科学家中有63%正在使用Python,44%正在使用R语言。而且,27%的人同时使用这两种语言。Python还在“多人使用的技术”“受欢迎技术”“需求度高技术”等榜单中名列前十。

    Python的明显优势:

    Python作为一款优雅、简洁的开源编程语言,吸引了世界各地的编程爱好者的注意力。每天都有数量众多的开源项目更新自己的功能,作为第三方模块为其他开发者提供更加高效、便利的支持。

    Python提供了丰富的API和工具,以便程序员能够轻松地使用C、C++、Cython来编写扩充模块,从而集成多种语言的代码,协同工作。一些算法在底层用C实现后,封装在Python模块中,性能非常高效。

    Python受到世界各地开发者的一致喜爱,在世界范围内被广泛使用。这意味着读者可以通过查看代码范例,快速学习和掌握相关内容。

    Python语言简单易学,语法清晰。Python开发者的哲学是“用一种方法,好是只有一种方法来做一件事”。通常,相较其他语言,Python的源代码被认为具有更好的可读性。

    2004年,Python 已在Google 内部使用,他们的宗旨是:Python where we can,C++ where we must,即在操控硬件的场合使用C++,在快速开发时使用Python。

    总的来说,Python是一款用于数据统计、分析、可视化等任务,以及机器学习、人工智能等领域的高效开发语言。它能满足几乎所有数据挖掘下所需的数据处理、统计模型和图表绘制等功能需求。大量的第三方模块所支持的内容涵盖了从统计计算到机器学习,从金融分析到生物信息,从社会网络分析到自然语言处理,从各种数据库各种语言接口到高性能计算模型等领域。随着大数据时代的来临,数据挖掘将更加广泛地渗透到各行各业中去,而Python作为数据挖掘里的热门工具,将会有更多不同行业的人加入到Python爱好者的行列中来。完全面向对象的Python的教学工作也将成为高校中数学与统计学专业的重点发展对象,这是大数据时代下的必然趋势。

    本书特色笔者从实际应用出发,结合实际例子及应用场景,深入浅出地介绍Python开发环境的搭建、Python基础入门、函数、面向对象编程、实用模块和图表绘制及常用的建模算法在Python中的实现方式。本书的编排以Python语言的函数应用为主,先介绍了函数的应用场景及使用格式,再给出函数的实际使用示例,后对函数的运行结果做出了解释,将掌握函数应用的所需知识点按照实际使用的流程展示出来。

    为方便读者理解Python语言中相关函数的使用,本书配套提供了书中使用的示例的代码及所用的数据,读者可以从“泰迪杯”全国数据挖掘挑战赛网站(http://www.tipdm.org/ts/755.jhtml)上免费下载。读者也可通过热线电话(40068-40020)、企业QQ(40068-40020)或以下微信公众号咨询获取。

    TipDM张良均〈大数据挖掘产品与服务〉本书适用对象开设有数据挖掘课程的高校教师和学生。

    目前国内不少高校将数据挖掘引入本科教学中,在数学、计算机、自动化、电子信息、金融等专业开设了数据挖掘技术相关的课程,但目前这一课程的教学使用的工具仍然为SPSS、SAS等传统统计工具,并没有使用Python作为教学工具。本书提供了有关Python语言的从安装到使用的一系列知识,将能有效指导高校教师和学生使用Python。

    数据挖掘开发人员。

    这类人员可以在理解数据挖掘应用需求和设计方案的基础上,结合本书提供的Python的使用方法快速入门并完成数据挖掘应用的编程实现。

    进行数据挖掘应用研究的科研人员。

    许多科研院所为了更好地对科研工作进行管理,纷纷开发了适应自身特点的科研业务管理系统,并在使用过程中积累了大量的科研信息数据。Python可以提供一个优异的环境对这些数据进行挖掘分析应用。

    关注不错数据分析的人员。

    Python作为一个广泛用于数据挖掘领域的编程语言,能为数据分析人员提供快速的、可靠的分析依据。

    如何阅读本书本书主要分为两大部分,基础篇和建模应用篇。基础篇介绍了有关Python开发环境的搭建、Python基础入门、函数、面向对象编程、实用模

    更多相关内容
  • 主要是对于北京市的二手房信息进行分析和预测,分别对于二手房价格和面积、朝向等锋面展开了叙述,进行数据挖掘分析和可视化,(本资源包括代码、数据。word实验报告)
  • 安装Anaconda Python集成环境下载环境anaconda下载选择安装环境下载过程中使用默认,但有一个页面需要确认,如下图。anaconda选择页面第一个勾是是否把 Anaconda 加入环境变量,这涉及到能否直接在 cmd中使用 conda...

    友情提示:此篇文章大约需要阅读 7分钟57秒,不足之处请多指教,感谢你的阅读。

    安装Anaconda Python集成环境

    下载环境

    anaconda下载选择

    安装环境

    下载过程中使用默认,但有一个页面需要确认,如下图。

    anaconda选择页面

    第一个勾是是否把 Anaconda 加入环境变量,这涉及到能否直接在 cmd中使用 conda、jupyter、 ipython 等命令,推荐打勾。

    第二个是是否设置 Anaconda 所带的 Python 3.6 为系统默认的 Python 版本,可以打勾。

    安装完成后,在开始菜单中显示“Anaconda2”如下图所示。

    安装显示界面

    安装第三方程序包 Graphviz

    目的是在决策树算法中八进制最终的树结构。

    1、打开 Anaconda Prompt ,输入 conda install python-graphviz,回车即可完成安装,如下图所示,本图所示已经安装 了 graphviz包,若之前没有安装,这时会花点时间安装,安装不用干预。

    安装决策树依赖包

    安装完成后先输入 python,然后再输入 import graphviz,测试是否成功安装,如上图所示。

    需要设置环境变量,才能使用新安装的 graphviz。

    Anaconda及依赖包环境变量设置

    首先查看 anaconda安装在哪个目录下,可以打开 Spyder的属性,看一看目标是什么目 录。例如本机的 anaconda安装路径为 C:\Users\lenovo\Anaconda2。

    下面设置环境变量

    (1) 在用户变量“path”里添加 C:\Users\lenovo\Anaconda2\Library\bin\graphviz

    (2) 在系统变量的“path”里添加 C:\Users\lenovo\Anaconda2\Library\bin\graphviz\dot.exe

    (3) 如果现在有正在打开的 anaconda 程序,例如正在 Spyder,那么关闭 Spyder,再启动,这 样刚才设置的环境变量生效。

    决策树分析

    格式化原始数据

    将下图的表 demo输入到 Excel中,保存为.csv 文件(.csv为逗号分隔值文件格式)。

    注意将表 demo中的汉字值转换成数据字值,例如“是否是公司职员”列中的“是”为“1”, “否”为“0”。转换后的表中数据如下图所示。

    学习表

    编写数据分析代码

    编写程序对上面的数据进行决策树分类,采用信息熵(entropy)作为度量标准。参考代码如下所示:

    from sklearn.tree import DecisionTreeClassifier,export_graphviz

    import graphviz

    import csv

    dataset = []

    reader = csv.reader(open("demo.csv"))

    for line in reader:

    if reader.line_num == 1:

    continue

    dataset.append(line)

    X = [x[0:4] for x in dataset]

    y = [x[4] for x in dataset]

    clf = DecisionTreeClassifier(criterion='entropy').fit(X, y)

    dot_data = export_graphviz(clf, out_file=None)

    graph = graphviz.Source(dot_data)

    graph.render("table");

    digraph Tree {

    node [shape=box] ;

    0 [label="X[0] <= 0.5\nentropy = 0.94\nsamples = 14\nvalue = [9, 5]"] ;

    1 [label="X[1] <= 1.5\nentropy = 0.985\nsamples = 7\nvalue = [3, 4]"] ;

    0 -> 1 [labeldistance=2.5, labelangle=45, headlabel="True"] ;

    2 [label="entropy = 0.0\nsamples = 3\nvalue = [0, 3]"] ;

    1 -> 2 ;

    3 [label="X[1] <= 2.5\nentropy = 0.811\nsamples = 4\nvalue = [3, 1]"] ;

    1 -> 3 ;

    4 [label="entropy = 0.0\nsamples = 2\nvalue = [2, 0]"] ;

    3 -> 4 ;

    5 [label="X[3] <= 0.5\nentropy = 1.0\nsamples = 2\nvalue = [1, 1]"] ;

    3 -> 5 ;

    6 [label="entropy = 0.0\nsamples = 1\nvalue = [1, 0]"] ;

    5 -> 6 ;

    7 [label="entropy = 0.0\nsamples = 1\nvalue = [0, 1]"] ;

    5 -> 7 ;

    8 [label="X[1] <= 2.5\nentropy = 0.592\nsamples = 7\nvalue = [6, 1]"] ;

    0 -> 8 [labeldistance=2.5, labelangle=-45, headlabel="False"] ;

    9 [label="entropy = 0.0\nsamples = 4\nvalue = [4, 0]"] ;

    8 -> 9 ;

    10 [label="X[3] <= 0.5\nentropy = 0.918\nsamples = 3\nvalue = [2, 1]"] ;

    8 -> 10 ;

    11 [label="entropy = 0.0\nsamples = 2\nvalue = [2, 0]"] ;

    10 -> 11 ;

    12 [label="entropy = 0.0\nsamples = 1\nvalue = [0, 1]"] ;

    10 -> 12 ;

    }

    数据分析结果

    程序运行结果在与该程序在同一目录下的 table.pdf 文件中,将每一个叶子结点转换成IF-THEN 规则。

    决策树分析结果

    IF-THEN分类规则

    (1)IF"不是公司员工" AND "年龄大于等于40", THEN "不买保险"。

    (2)IF"不是公司员工" AND "年龄小于40", THEN "买保险"。

    (3)IF"不是公司员工" AND "年龄大于50" AND "信用为良", THEN "不买保险"。

    (4)IF"不是公司员工" AND "年龄大于40" AND "信用为优", THEN "买保险"。

    (5)IF"是公司员工" AND "年龄小于50", THEN "不买保险"。

    (6)IF"是公司员工" AND "年龄小于50" AND "信用为优", THEN "买保险"。

    (7)IF"是公司员工" AND "年龄小于50" AND "信用为良", THEN "不买保险"。

    展开全文
  • 目录1. Numpy的优势2. 数组属性3....Python已经提供了很多丰富的内置包,我们为什么还要学习NumPy呢?先看一个例子,找寻学习 NumPy 的必要性和重要性。如下: 原创文章 37获赞 693访问量 3万+ 关注
  • 本人博客中数据挖掘与数据分析板块的Python数据可视化的例子的数据集 本人博客中数据挖掘与数据分析板块的Python数据可视化的例子的数据集 本人博客中数据挖掘与数据分析板块的Python数据可视化的例子的数据集 本人...
  • 书籍源码-《python数据挖掘
  • python 数据挖掘算法

    千次阅读 2022-02-19 17:05:33
    1、首先简述数据挖掘的过程 第一步:数据选择 可以通过业务原始数据、公开的数据集、也可通过爬虫的方式获取。 第二步: 数据预处理 数据极可能有噪音,不完整等缺陷,需要对数据进行数据标准化,方法有min-max ...

    1、首先简述数据挖掘的过程

    第一步:数据选择

            可以通过业务原始数据、公开的数据集、也可通过爬虫的方式获取。

    第二步: 数据预处理

            数据极可能有噪音,不完整等缺陷,需要对数据进行数据标准化,方法有min-max 标准化, z-score 标准化,修正的标准z-score。

    第三步:特征值数据转换

            将数据提取特征使这些数据符合特定数据挖掘算法的分析模型。数据模型有很多,等下详细讲解。

    第四步:模型训练

            选择好的数据挖掘算法对数据进行训练

    第五步:测试模型+效果评估

            有两种主流方法:

            十折交叉验证:将数据集随机分割成十个等份,每次用9份数据做训练集,1份数据做测试集,如此迭代10次。十折交叉验证的关键在于较平均地分为10份。

            N折交叉验证又称为留一法:用几乎所有的数据进行训练,然后留一个数据进行测试,并迭代每一数据测试。留一法的优点是:确定性。

    第六步:模型使用

            使用训练好的模型对数据进行预测。

    第七步:解释与评价

            对数据挖掘后的信息加以分析解释,并应用于实际的工作领域。

    2、主要的算法模型讲解 ——基于sklearn

    1)线性回归:希望所有点都落在直线上,所有点离直线的距离最近。首先假设好y=ax+b中a和b的值,然后计算每个数据点到这条直线上的距离总和,目的是要使这个总和最小!

    from sklearn.linear_model import LinearRegression
    # 定义线性回归模型
    model = LinearRegression(fit_intercept=True, normalize=False, 
        copy_X=True, n_jobs=1)
    """
    参数
    ---
        fit_intercept:是否计算截距。False-模型没有截距
        normalize: 当fit_intercept设置为False时,该参数将被忽略。 如果为真,则回归前的回归系数X将通过减去平均值并除以l2-范数而归一化。
         n_jobs:指定线程数
    """

    2)逻辑回归:二分算法,用于两分类问题。需要预测函数的“大概形式”, 比如是线性还是非线性的。

    上面有提到,该数据集需要一个线性的边界。 不同数据需要不同的边界。

    from sklearn.linear_model import LogisticRegression
    # 定义逻辑回归模型
    model = LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0, 
        fit_intercept=True, intercept_scaling=1, class_weight=None, 
        random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’, 
        verbose=0, warm_start=False, n_jobs=1)
    
    """参数
    ---
        penalty:使用指定正则化项(默认:l2)
        dual: n_samples > n_features取False(默认)
        C:正则化强度的反,值越小正则化强度越大
        n_jobs: 指定线程数
        random_state:随机数生成器
        fit_intercept: 是否需要常量
    """

    3)朴素贝叶斯算法NB:用于判断某件事的发生概率,我就曾用此算法做过舆情分类器。将一些语句变为01二维矩阵,计算词语的出现频率,从而判断语句的情感色彩是怎样的。

    效率很高,但存在一定的错误概率

    概率模型朴素贝叶斯 原理与优点_lipeitong333的博客-CSDN博客

    from sklearn import naive_bayes
    model = naive_bayes.GaussianNB() # 高斯贝叶斯
    model = naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
    model = naive_bayes.BernoulliNB(alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)
    """
    文本分类问题常用MultinomialNB
    参数
    ---
        alpha:平滑参数
        fit_prior:是否要学习类的先验概率;false-使用统一的先验概率
        class_prior: 是否指定类的先验概率;若指定则不能根据参数调整
        binarize: 二值化的阈值,若为None,则假设输入由二进制向量组成
    """

    4)决策树DT:类似流程图的树结构,它使用分支方法来说明决策的每个可能结果。树中的每个节点代表对特定变量的测试 - 每个分支都是该测试的结果。

    决策树 信息增益与信息增益比_lipeitong333的博客-CSDN博客

    from sklearn import tree 
    model = tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None, 
        min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, 
        max_features=None, random_state=None, max_leaf_nodes=None, 
        min_impurity_decrease=0.0, min_impurity_split=None,
         class_weight=None, presort=False)
    """参数
    ---
        criterion :特征选择准则gini/entropy
        max_depth:树的最大深度,None-尽量下分
        min_samples_split:分裂内部节点,所需要的最小样本树
        min_samples_leaf:叶子节点所需要的最小样本数
        max_features: 寻找最优分割点时的最大特征数
        max_leaf_nodes:优先增长到最大叶子节点数
        min_impurity_decrease:如果这种分离导致杂质的减少大于或等于这个值,则节点将被拆分。
    """

    5)支持向量机SVM:就是判断线性可分不可分,能不能用直线分割两类数据!理论可以推广到三维,甚至思维以上的特征空间。三维使用平面来分隔数据,四维和四维以上因为人类 无法直观的感知出来,所以画不出来,但是能分隔数据,存在这样的平面叫做超平面。

    SVC 二值分类器 工作原理_lipeitong333的博客-CSDN博客

    from sklearn.svm import SVC
    model = SVC(C=1.0, kernel=’rbf’, gamma=’auto’)
    """参数
    ---
        C:误差项的惩罚参数C
        gamma: 核相关系数。浮点数,If gamma is ‘auto’ then 1/n_features will be used instead.
    """

    6)k近邻算法KNN:采用测量不同特征值之间距离的方法对数据进行分类的一个算法。

    给定一个样本的集合,这里称为训练集,并且样本中每个数据都包含标签。对于新输入的一个不包含标签的数据,通过计算这个新的数据与每一个样本之间的距离,选取前k个,通常k小于20,以k个剧里最近的数据的标签中出现次数最多的标签作为该新加入的数据标签。 

    K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分类到这个类中。(这就类似于现实生活中少数服从多数的思想)根据这个说法,咱们来看下引自维基百科上的一幅图:

     

    • 如果K=3,绿色圆点的最邻近的3个点是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。
    • 如果K=5,绿色圆点的最邻近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。 
    from sklearn import neighbors
    #定义kNN分类模型
    model = neighbors.KNeighborsClassifier(n_neighbors=5, n_jobs=1) # 分类
    model = neighbors.KNeighborsRegressor(n_neighbors=5, n_jobs=1) # 回归
    """参数
    ---
        n_neighbors: 使用邻居的数目
        n_jobs:并行任务数
    """

    7)K-均值聚类(K-means)

    • 定义目标聚类数K,例如,k=3
    • 随机初始化的 k 个聚类中心(controids)
    • 计算每个数据点到K个聚类中心的Euclidean Distance,然后将数据点分到Euclidean Distance最小的对应类聚中心的那类
    • 针对每个类别,重新计算它的聚类中心;
    • 重复上面 3-4 两步操作,直到达到某个中止条件(迭代次数、最小误差变化等)

    import pandas as pd
    import matplotlib.pyplot as plt
    from sklearn.cluster import KMeans
    
    df = pd.DataFrame({"x": [25, 34, 22, 27, 33, 33, 31, 22, 35, 34, 67, 54, 57, 43, 50, 57, 59, 52, 65, 47, 49, 48, 35, 33, 44, 45, 38, 43, 51, 46],
                       "y": [79, 51, 53, 78, 59, 74, 73, 57, 69, 75, 51, 32, 40, 47, 53, 36, 35, 59, 59, 50, 25, 20, 14, 12, 20, 5,  29, 27, 8,  7]})
    
    kmeans = KMeans(n_clusters=3).fit(df)
    centroids = kmeans.cluster_centers_
    # 打印类聚中心
    print(type(centroids), centroids)
    
    # 可视化类聚结果
    fig, ax = plt.subplots()
    ax.scatter(df['x'],df['y'],c=kmeans.labels_.astype(float),s=50, alpha=0.5)
    ax.scatter(centroids[:, 0], centroids[:, 1], c='red', s=50)
    plt.show()
    

    和KNN所不同,K-均值聚类属于无监督学习。

    监督学习知道从对象(数据)中学习什么,而无监督学习无需知道所要搜寻的目标,它是根据算法得到数据的共同特征。比如用分类和聚类来说,分类事先就知道所要得到的类别,而聚类则不一样,只是以相似度为基础,将对象分得不同的簇。

    More:

    FP-Growth_lipeitong333的博客-CSDN博客

    Apriori关联分析算法 -尿布与啤酒的故事_lipeitong333的博客-CSDN博客

    ps):我们在机器学习中一直会遇到两种问题,一种是回归问题,一种是分类问题。我们从字面上理解,很容易知道分类问题其实是将我们现有的数据分成若干类,然后对于新的数据,我们根据所分得类而进行划分;而回归问题是将现有数据拟合成一条函数,根据所拟合的函数来预测新的数据。 这两者的区别就在于输出变量的类型。回归是定量输出,或者说是预测连续变量;分类问题书定量输出,预测离散变量。Po一张我在知乎上看到的一张图片,解释的很好:



     3、sklearn自带方法joblib来进行保存训练好的模型

    from sklearn.externals import joblib
    
    # 保存模型
    joblib.dump(model, 'model.pickle')
    
    #载入模型
    model = joblib.load('model.pickle')


    参考链接:https://juejin.cn/post/6844903682576760846、https://juejin.cn/post/6961934412518785054、
    https://juejin.cn/post/6844903513504530446、https://juejin.cn/post/6974596282694254606、机器学习神器:sklearn的快速使用 - 掘金 (juejin.cn)机器学习之逻辑回归(纯python实现) - 掘金 (juejin.cn)

    机器学习笔记5-支持向量机1 - 掘金 (juejin.cn)

    展开全文
  • python数据挖掘案例系列教程——python实现搜索引擎

    万次阅读 多人点赞 2018-01-07 20:32:07
    python数据挖掘系列教程 今天我们使用python实现一个网站搜索引擎。主要包含两个部分。网站数据库的生成、搜索引擎。其中搜索引擎部分我们使用单词频度算法、单词距离算法、外部回值算法、链接文本算法、pagerank...

    全栈工程师开发手册 (作者:栾鹏)

    python数据挖掘系列教程

    今天我们使用python实现一个网站搜索引擎。主要包含两个部分。网站数据库的生成、搜索引擎。其中搜索引擎部分我们使用单词频度算法、单词距离算法、外部回值算法、链接文本算法、pagerank算法和神经网络学习等6种算法来实现搜索排名。

    我们这里将http://blog.csdn.net/luanpeng825485697站点下的所有网站当做一个小型服务器。对该网站域名下的网页进行搜索引擎设计。

    由于需要获取博客文章的单词作为每篇博客的特征属性,并且我们的博客都是中文,所以在学习获取博客数据前,需要学习结巴中文分词库的使用。参考:
    http://blog.csdn.net/luanpeng825485697/article/details/78757563

    在我们的代码中,我们将模型固话在sqlite数据库中。所以在学习获取博客数据前,还需要学习sqlite3库的使用,参考:
    http://blog.csdn.net/luanpeng825485697/article/details/78361168

    由于我们会将所有的数据都存储在数据库中以便今后常用,所以代码中会有部分sqlite数据库的相关代码操作。

    调试环境python3.6

    gitup网址:https://github.com/626626cdllp/data-mining/tree/master/Search-Engines

    第一部分、爬取网站生成网站数据库

    这一部分,我们的目标是将域名下的所有网页的信息生成几个数据集。

    这里写图片描述

    sqlite数据库默认的主键索引名为rowid,mysql数据库默认的主键索引名为id。

    第一张表urllist、保存的是已经url列表,字段hascrawl表示该网页是否已经爬取过。
    第二张表wordlist、保存的是整个网站的单词列表,不包含重复单词。
    第三张表wordlocation、保存的是单词在文档中所处位置的列表。单词的位置为单词在该文档内容所形成的单词列表中的索引。
    第四张表link、保存了两个urlid,指明从一张表到另一张表的跳转关系。
    第五张表linkwords、则利用wordid和linkid记录链接的描述。

    下面我们就来爬取整个网站,生成这五张表,这里我们使用urllib获取响应,所以不能爬取js动态加载的网站。如果想爬取动态加载的网站,可以参考http://blog.csdn.net/luanpeng825485697/article/details/78436963

    将下面的代码存储成spyder.py

    # 根据连接爬取中文网站,获取标题、子连接、子连接数目、连接描述、中文分词列表,
    import urllib
    from bs4 import BeautifulSoup
    import bs4
    import sqlite3
    import os
    import jieba   #对中文进行分词
    import traceback
    
    # 分词时忽略下列词,即不为这些单词建立数据库
    biaodian = '[!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~]+ ,。?‘’“”!;:\r\n、()…'     #所有的标点符号
    ignorewords = list(set(biaodian))   #去重
    ignorewords.append('\r\n')   #另外添加一个忽略的项
    
    
    # 定义爬虫类。获取链接的标题、描述、分词、深度
    class crawler:
        def __init__(self,dbname):
            self.urls={}              #创建爬取列表
            self.con = sqlite3.connect(dbname)
            self.curs = self.con.cursor()
            try:
                self.createindextables()
            except:
                pass
    
        def __del__(self):  # 关闭数据库
            self.curs.close()
            self.con.close()
    
        def dbcommit(self):  # 保存数据库
            self.con.commit()
    
        # 创建数据库表
        def createindextables(self):
            self.curs.execute('create table urllist(url,hascrawl)')  # 创建url列表数据表
            self.curs.execute('create table wordlist(word)')  # 创建word列表数据表
            self.curs.execute('create table wordlocation(urlid,wordid,location)')  # 创建url-word-location数据表(每个链接下出现的所有单词和单词出现的位置)
            self.curs.execute('create table link(fromid integer,toid integer)')  # 创建url-url数据表(当前链接和目标链接对)
            self.curs.execute('create table linkwords(wordid,linkid)')  # 创建word-url数据表(链接描述)
            self.curs.execute('create index wordidx on wordlist(word)')  # 创建索引
            self.curs.execute('create index urlidx on urllist(url)')  # 创建索引
            self.curs.execute('create index wordurlidx on wordlocation(wordid)')  # 创建索引
            self.curs.execute('create index urltoidx on link(toid)')  # 创建索引
            self.curs.execute('create index urlfromidx on link(fromid)')  # 创建索引
            self.dbcommit()
    
    	#获取一个dom内的所有单词。soup为dom元素
        def getword(self,soup):
            # 获取每个单词
            text=self.gettextonly(soup)   #提取所有显示出来的文本
            allword=self.separatewords(text)  #使用分词器进行分词
            return allword
    
        # 根据一个dom元素提取文字(不带标签的)。由外至内获取文本元素。style和script内的文字忽略
        def gettextonly(self,soup):
            v=soup.string
            if v==None:
                c=soup.contents   # 直接子节点的列表,将<tag>所有儿子节点存入列表
                resulttext=''
                for t in c:
                    if t.name=='style' or t.name=='script':   #当元素为style和script和None时不获取内容
                        continue
                    subtext=self.gettextonly(t)
                    resulttext+=subtext+'\n'
                return resulttext.strip()
            else:
                if isinstance(v,bs4.element.Comment):   #代码中的注释不获取
                    return ''
                return v.strip()
    
        # 使用结巴分词,同时去除标点符号
        def separatewords(self,text):
            seg_list = jieba.cut(text, cut_all=False)  #使用结巴进行中文分词
            allword = []
            for word in seg_list:
                if word not in ignorewords:
                    allword.append(word)
                    # print(allword)
            return allword
    
        #爬虫主函数
        def crawl(self,url,host):
            if url in self.urls and self.urls[url]['hascrawl']:return  # 如果网址已经存在于爬取列表中,并且已经爬取过,则直接返回
            try:
                if url in self.urls:    
                    if self.urls[url]['hascrawl']:return
                    else: self.urls[url]['hascrawl']=True  # 如果网址已存在,但是并没有爬取过,就设置hascrawl为True
                else:
                    self.urls[url]={}
                    self.urls[url]['hascrawl']=True
                response=urllib.request.urlopen(url)   #获取响应流
                text = str(response.read(), encoding='utf-8')   #转化为utf-8编码的字符串
                soup = BeautifulSoup(text, 'html.parser')   #解析成dom树
    
                links = soup('a')  #获取所有链接
                for link in links:
                    if ('href' in dict(link.attrs)):   #如果链接元素存在href属性
                        newurl = urllib.parse.urljoin(url, link['href'])  #获取链接的绝对网址
                        if not host in newurl: continue  # 非服务范围网址不爬取,不记录
                        if newurl == url: continue  # 如果网址是当前网址,不爬取,不记录
                        if newurl.find("'") != -1: continue  # 包含'的链接不爬取,不记录
                        newurl = newurl.split('#')[0]  # 去掉#后的数据部分
                        if newurl[0:4] == 'http':  # 只处理http协议
                            if newurl not in self.urls:  # 将链接加入爬取列表
                                self.urls[newurl] = {}
                                self.urls[newurl]['hascrawl'] = False 
                            # 添加链接描述
                            linkText = self.gettextonly(link).strip()  # 获取链接的描述
                            self.addlinkref(url, newurl, linkText)  # 添加链接跳转对和链接描述
    
                self.addtoindex(url, soup.body)  # 创建链接列表库和链接-分词库
                self.dbcommit()    #保存
                return True
            except:
                traceback.print_exc()
                return False
                # print("Could not parse page %s" % url)
    
    
        # 添加链接列表库和链接-分词索引
        def addtoindex(self, url, soup):
            # 查询-增加网址获得urlid
            urlid = self.get_add_id('urllist', 'url', url)
            # 提取所有单词
            allword = self.getword(soup)  # 提取所有显示出来的文本
            print(allword)
            # 将每个单词与该url关联,写入到数据库
            index = 0
            for word in allword:
                index += 1
                # 查询-增加单词获得wordid 
                wordid = self.get_add_id('wordlist', 'word', word)
                self.curs.execute("insert into wordlocation(urlid,wordid,location) values (%d,%d,%d)" % (urlid, wordid, index))
    
        # 添加链接跳转对,和链接-描述文本。
        def addlinkref(self, urlFrom, urlTo, linkText):
            words = self.separatewords(linkText)
            fromid = self.get_add_id('urllist', 'url', urlFrom)   #参数:表名、列名、值
            toid = self.get_add_id('urllist', 'url', urlTo)   #参数:表名、列名、值
            if fromid == toid: return
            cur = self.curs.execute("insert into link(fromid,toid) values (%d,%d)" % (fromid, toid))
            linkid = cur.lastrowid
            for word in words:
                wordid = self.get_add_id('wordlist', 'word', word)   #参数:表名、列名、值
                self.curs.execute("insert into linkwords(linkid,wordid) values (%d,%d)" % (linkid, wordid))
    
        # 辅助函数,用于获取数据库中记录的id,并且如果记录不存在,就将其加入数据库中,再返回id
        def get_add_id(self, table, field, value):
            command = "select rowid from %s where %s='%s'" % (table, field, value)
            cur = self.curs.execute(command)
            res = cur.fetchall()
            if res == None or len(res) == 0:
                cur = self.curs.execute("insert into %s (%s) values ('%s')" % (table, field, value))
                return cur.lastrowid
            else:
                return res[0][0]   #返回第一行第一列
    
    

    上面就完成了一个基本的爬虫类,当然今天我们还会在这个类中添加一些功能,以适应更加丰富的搜索。

    下面我们就可以借用这个类来爬取一个网站了。

    # 爬取指定域名范围内的所有网页,beginurl为开始网址,host为根网址
    def crawlerhost(beginurl,host,dbname):
        mycrawler = crawler(dbname)      #定义爬虫对象
        mycrawler.crawl(beginurl,host)  #爬取主页
        for url in list(mycrawler.urls.keys()):
            print(url)
            mycrawler.crawl(url, host)  # 爬取子网页
           
        # 获取pageRank数据
        # mycrawler.calculatepagerank()
    

    爬取部分算是完成了。下面就可以来测试一下了。

    # 读取数据库信息,检验是否成功建立了搜索数据库
    def readdb(dbname):
        con = sqlite3.connect(dbname)
        curs = con.cursor()
        command = "select fromid,toid from link"   #'select * from link'
        cur = curs.execute(command)
        res = cur.fetchall()
        allurl=[]
        if res != None and len(res) > 0:
            for row in res:
                print(row)
                command = "select url from urllist where rowid=%d" % row[0]
                fromurl = curs.execute(command).fetchall()[0][0]
                command = "select url from urllist where rowid=%d" % row[1]
                tourl = curs.execute(command).fetchall()[0][0]
                # print(fromurl,tourl)
                if fromurl not in allurl:
                    allurl.append(fromurl)
                if tourl not in allurl:
                    allurl.append(tourl)
    
    
    
    
    
    if __name__ == '__main__':
        # 爬取服务器建立数据库
        url = 'http://blog.csdn.net/luanpeng825485697'
        # if os._exists('csdn.db'):
        #     os.remove('csdn.db')    #删除旧的数据库
        crawlerhost(url, url,'csdn.db')
    
        #读取数据库
        readdb('csdn.db')
    

    第二部分、搜索

    这一部分我们根据用户的输入,从数据库中获取相关的链接集。在下一部分链接集进行排序使用。

    我们为搜索引擎新建一个模块,命名为searchengine.py

    先引入一些必要的模块和变量

    # 搜索和排名
    import urllib
    from bs4 import BeautifulSoup
    import re
    import sqlite3
    import nn
    import os
    import spyder   #获取爬虫数据集
    import jieba
    
    # 分词时忽略下列词
    biaodian = '[!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~]+ ,。?‘’“”!;:\r\n、()…'     #所有的标点符号
    ignorewords = list(set(biaodian))   #去重
    ignorewords.append('\r\n')   #添加一个不忽略的项
    
    

    在模块中我们先建立一个搜索引擎类。

    
    # 定义搜索引擎类
    class searcher:
        def __init__(self,dbname):
            self.con=sqlite3.connect(dbname)  #链接数据库
            self.curs = self.con.cursor()
    
        def __del__(self):
            self.curs.close()
            self.con.close()
    

    搜索引擎类的一个任务就是能根据用户搜索的字符串分割成多个关键词,再查询到相关的网址。而只要文章中出现了每个关键词,就认为网页相关。这一部分代码比较难懂,建议读者边运行边学习。

    查询过程:

    1、对输入字符串进行分词获得多个关键词。例如我们查询“腾讯股票”,会分词成“腾讯”、“股票”
    2、查询每个关键词在单词库wordlist数据库中的索引。例如我们会查询到“腾讯”在单词库中的索引为126,“股票在单词库中的索引为127”
    3、利用这两个关键词索引把所有包含这两个关键词的链接以及这两个关键词在链接中出现的位置查询出来。形成以下的数据格式

    [
    	 (urlid1,wordlocation1_1,wordlocation2_1),  # 链接1中,单词1的位置1,单词2的位置1
    	 (urlid1,wordlocation1_1,wordlocation2_2),  # 链接1中,单词1的位置1,单词2的位置2
    	 (urlid1,wordlocation1_1,wordlocation2_3),  # 链接1中,单词1的位置1,单词2的位置3
    	 (urlid1,wordlocation1_2,wordlocation2_1),  # 链接1中,单词1的位置2,单词2的位置1
    	 (urlid1,wordlocation1_2,wordlocation2_2),  # 链接1中,单词1的位置2,单词2的位置2
    	 (urlid1,wordlocation1_2,wordlocation2_3),  # 链接1中,单词1的位置2,单词2的位置3
    	 ...
    	 (urlid2,wordlocation1_1,wordlocation2_1),  # 链接2中,单词1的位置1,单词2的位置1
    	 (urlid2,wordlocation1_1,wordlocation2_2),  # 链接2中,单词1的位置1,单词2的位置2
    	 ...
    ]
    

    在下面的语句中我们会用到一个数据库查询语句。
    例如我们查询了字符串中包含“腾讯”、“股票”两个关键词,在单词列表wordlist中的索引分别为126、和127。

    则我们使用下面的语法查询出数据集。

    select w0.urlid,w0.location,w1.location from wordlocation w0,wordlocation w1 where w0.wordid=126 and w0.urlid=w1.urlid and w1.wordid=127
    

    上面的 代码先看where后面的语句。w0表示一个数据表,w1表示另一个数据表。
    下面的语句表示满足条件:
    w0表的wordid字段为126的所有w0中的记录
    w1表的wordid字段为127的所有w1中的记录
    w0表的urlid字段与w1表中urlid字段存在相同值的所有w0中的记录和w1中的所有记录。
    where后的语句查询上述数据集的交集。

    where w0.wordid=126 and w0.urlid=w1.urlid and w1.wordid=127
    

    再来看from后面的语句。表示wordlocation表可以用w0这个名称代替,wordlocation这个表也可以用w1这个名称代替。

    from wordlocation w0,wordlocation w1 
    

    最后来看select后的语句。上面查询到的数据集既有w0中的又有w1中的,把w0中记录的urlid字段、w0中记录的location字段、w1中记录的location字段提取出来。

    select w0.urlid,w0.location,w1.location 
    

    最终形成了我们想要的数据集格式。

    [
    	 (urlid1,wordlocation1_1,wordlocation2_1),  # 链接1中,单词1的位置1,单词2的位置1
    	 (urlid1,wordlocation1_1,wordlocation2_2),  # 链接1中,单词1的位置1,单词2的位置2
    	 (urlid1,wordlocation1_1,wordlocation2_3),  # 链接1中,单词1的位置1,单词2的位置3
    	 (urlid1,wordlocation1_2,wordlocation2_1),  # 链接1中,单词1的位置2,单词2的位置1
    	 (urlid1,wordlocation1_2,wordlocation2_2),  # 链接1中,单词1的位置2,单词2的位置2
    	 (urlid1,wordlocation1_2,wordlocation2_3),  # 链接1中,单词1的位置2,单词2的位置3
    	 ...
    	 (urlid2,wordlocation1_1,wordlocation2_1),  # 链接2中,单词1的位置1,单词2的位置1
    	 (urlid2,wordlocation1_1,wordlocation2_2),  # 链接2中,单词1的位置1,单词2的位置2
    	 ...
    ]
    

    查询实现代码如下:

    # 使用结巴分词,去除标点符号
        def separatewords(self, text):
            seg_list = jieba.cut(text, cut_all=False)  # 使用结巴进行中文分词
            allword = []
            for word in seg_list:
                if word not in ignorewords:
                    allword.append(word)
            # print(allword)
            return allword
    
        # 根据搜索字符串分词后获取查询到的链接
        def getmatchrows(self,querystr):
            # 构造数据库的查询字符串(搜索字符串根据空格分割成查询字符串列表)
            fieldlist='w0.urlid'
            tablelist=''
            clauselist=''
            wordids=[]
    
            # words=querystr.strip().split(' ')   # 根据空格分割单词
            words = self.separatewords(querystr)  #使用结巴进行中文分词
            tablenumber=0
            for word in words:
                # 获取单词的id
                wordrow=self.curs.execute("select rowid from wordlist where word='%s'" % word).fetchall()
                if wordrow!=None and len(wordrow)> 0:
                    wordid=wordrow[0][0]  #获取单词id
                    wordids.append(wordid)
                    if tablenumber>0:
                        tablelist+=','
                        clauselist+=' and '
                        clauselist+='w%d.urlid=w%d.urlid and ' % (tablenumber-1,tablenumber)
                    fieldlist+=',w%d.location' % tablenumber
                    tablelist+='wordlocation w%d' % tablenumber
                    clauselist+='w%d.wordid=%d' % (tablenumber,wordid)
                    tablenumber+=1
    
            # 根据各个组分,建立查询。为列表中的每个单词,建立指向wordlocation表的引用,并根据对应的urlid将它们连接起来进行联合查询
            fullquery='select %s from %s where %s' % (fieldlist,tablelist,clauselist)
            # print(fullquery)
            cur=self.curs.execute(fullquery)
            rows=[row for row in cur.fetchall()]
    
            return rows,wordids
    

    经过上面的查询语句,返回的rows,wordids。其中
    wordids样式如[126, 127],表示每个查询关键词在单词库wordlist数据库中的索引。这个比较简单。

    而rows的样式比较复杂,但他是理解后续代码的关键。

    下面假设搜索字符串解析出了两个关键词。并且这两个关键词在某一个网页中可能都出现了很多次。
    rows的样式为

    [
    	 (urlid1,wordlocation1_1,wordlocation2_1),  # 链接1中,单词1的位置1,单词2的位置1
    	 (urlid1,wordlocation1_1,wordlocation2_2),  # 链接1中,单词1的位置1,单词2的位置2
    	 (urlid1,wordlocation1_1,wordlocation2_3),  # 链接1中,单词1的位置1,单词2的位置3
    	 (urlid1,wordlocation1_2,wordlocation2_1),  # 链接1中,单词1的位置2,单词2的位置1
    	 (urlid1,wordlocation1_2,wordlocation2_2),  # 链接1中,单词1的位置2,单词2的位置2
    	 (urlid1,wordlocation1_2,wordlocation2_3),  # 链接1中,单词1的位置2,单词2的位置3
    	 ...
    	 (urlid2,wordlocation1_1,wordlocation2_1),  # 链接2中,单词1的位置1,单词2的位置1
    	 (urlid2,wordlocation1_1,wordlocation2_2),  # 链接2中,单词1的位置1,单词2的位置2
    	 ...
    ]
    

    可以看出列表中的每个元组中,第一列代表是网址id,后面的列是每个关键词出现的位置的一种组合。

    第三部分、排名算法

    上面已经根据用户的输入获取到了相关的网址数据。
    获取到的数据中rows的形式如下
    [(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3…),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3…)]
    列表的每个元素是一个元组,每个元素的内容是urlid和每个关键词在该文档中的位置。

    wordids形式为[wordid1, wordid2, wordid3…],即每个关键词所对应的单词id

    我们将会介绍几种排名算法,所谓排名也就是根据各自的规则为每个链接评分,评分越好。并且最终我们会将几种排名算法综合利用起来,给出最终的排名。既然要综合利用,那么我们就要先实现每种算法。在综合利用时会遇到几个问题。

    1、每种排名算法评分机制不同,给出的评分尺度和含义也不尽相同
    2、如何综合利用,要考虑每种算法的效果。为效果好的给与较大的权重。

    我们先来考虑第一个问题,如何消除每种评分算法所给出的评分尺度和含义不相同的问题。
    第2个问题,等研究完所有的算法以后再来考虑。

    简单,使用归一化,将每个评分值缩放到0-1上,1代表最高,0代表最低。

    # 评价值归一化:因为不同的评价方法的返回值和含义不同。这里所有的评价值归一化到0-1,默认越大越好
        def normalizescores(self,scores,smallIsBetter=0):
            vsmall=0.00001 #避免被0整除
            if smallIsBetter:
                minscore=min(scores.values())
                return dict([(u,float(minscore)/max(vsmall,l)) for (u,l) in scores.items()])
            else:
                maxscore=max(scores.values())
                if maxscore==0: maxscore=vsmall
                return dict([(u,float(c)/maxscore) for (u,c) in scores.items()])
    

    下面我们来研究每一种算法。

    第1个排名算法:根据单词位置进行评分的函数

    我们可以认为对用户输入的多个关键词,在文档中,这些关键词出现的位置越靠前越好。比如我们往往习惯在文章的前面添加一些摘要性、概括性的描述。

        # 根据单词位置进行评分的函数.
        # rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
        def locationscore(self,rows):
            locations=dict([(row[0],1000000) for row in rows])
            for row in rows:
                loc=sum(row[1:]) #计算每个链接的单词位置总和,越小说明越靠前
                if loc<locations[row[0]]:  #记录每个链接最小的一种位置组合
    	            locations[row[0]]=loc
    
            return self.normalizescores(locations,smallIsBetter=1)
    

    第2个排名算法:根据单词频度进行评价的函数

    我们可以认为对用户输入的多个关键词,在文档中,这些关键词出现的次数越多越好。比如我们在指定主题的文章中会反复提到这个主题。

      # 根据单词频度进行评价的函数
        # rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
        def frequencyscore(self,rows):
            counts=dict([(row[0],0) for row in rows])
            for row in rows: 
    	        counts[row[0]]+=1   #统计每个链接出现的组合数目。 每个链接只要有一种位置组合就会保存一个元组。所以链接所拥有的组合数,能一定程度上表示单词出现的多少。
            return self.normalizescores(counts)
    

    第3个排名算法:根据单词距离进行评价的函数

    我们可以认为对用户输入的多个关键词,在文档中,这些关键词出现的越紧凑越好。这是因为我们更希望所有单词出现在一句话中,而不是不同的关键词出现在不同段落或语句中。

      # 根据单词距离进行评价的函数。
        # rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
        def distancescore(self,rows):
            # 如果仅查询了一个单词,则得分都一样
            if len(rows[0])<=2: return dict([(row[0],1.0) for row in rows])
    
            # 初始化字典,并填入一个很大的值
            mindistance=dict([(row[0],1000000) for row in rows])
    
            for row in rows:
                dist=sum([abs(row[i]-row[i-1]) for i in range(2,len(row))]) # 计算每种组合中每个单词之间的距离
                if dist<mindistance[row[0]]:  # 计算每个链接所有组合的距离。并为每个链接记录最小的距离
    	            mindistance[row[0]]=dist
            return self.normalizescores(mindistance,smallIsBetter=1)
    

    第4个排名算法:利用指向该链接的链接数目进行评价

    我们可以认为查询到的相关链接中,如果有较多的其他链接在文档中指向了当前链接,这该链接内容质量比较好。

      # 利用指向该链接的链接数目进行评价(仅计算回指数目)。
        # rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
        def inboundlinkscore(self,rows):
            uniqueurls=dict([(row[0],1) for row in rows])
            inboundcount=dict([(u,self.curs.execute('select count(*) from link where toid=%d' % u).fetchall()[0]) for u in uniqueurls])
            return self.normalizescores(inboundcount)
    

    第5个排名算法:pagerank算法

    互联网中的网页可以看出是一个有向图,其中网页是结点,如果网页A有链接到网页B,则存在一条有向边A->B,下面是一个简单的示例:

    这里写图片描述

    这个例子中只有四个网页,如果当前在A网页,那么悠闲的上网者将会各以1/3的概率跳转到B、C、D,这里的3表示A有3条出链,如果一个网页有k条出链,那么跳转任意一个出链上的概率是1/k,同理D到B、C的概率各为1/2,而B到C的概率为0。

    在跳转有向图中不考虑指向自己的链接

    由于上网者并不一定会点击网络中的链接跳转到新的网址,所以我们需要设置阻尼系数,代表用户点击链接进入新网址的概率。

    另外每一个网页本身的重要性也不同,被不同重要性的网址所引用自然也就代表了不同的重要性。比如网址D是一个非常重要的网址,在D中指向了网址B和C,则我们可以认为网址B和网址C也很重要。而网址的重要性又是通过pagerank所表示的,所以这是一个迭代收敛获取每个网址pagerank的过程。

    由于每个网址的链接情况是相对固定的,每个网址的pagerank我们可以在用户请求前就计算好,将每个网址的pagerank值保存到数据库中,待用户请求时,直接查询相关网址的pagerank值就可以了。

    第一步、提前迭代计算每个网址的pagerank的值。

    每个链接的pagerank=每个指向此链接的网页的pagerank/该网页中的链接总数*0.85+0.15,其中0.85表示阻尼因子,表示网页是否点击该网页中的链接。

    先初始化每个网页的pagerank的值为1,然后按照上面的方法迭代n次计算每个网页的pagerank。

    我们在spyder.py模块的crawler类中添加下面的函数

    # (每个链接的pagerank=指向此链接的网页的pagerank/网页中的链接总数*0.85+0.15,其中0.85表示阻尼因子,表示网页是否点击该网页中的链接)
        # pagerank算法,离线迭代计算,形成每个链接的稳定pagerank值。iterations为迭代计算的次数
        def calculatepagerank(self, iterations=20):
            # 清除您当前的pagerank表
            self.curs.execute('drop table if exists pagerank')
            self.curs.execute('create table pagerank(urlid primary key,score)')
    
            # 初始化每个url,令其pagerank的值为1
            for (urlid,) in self.curs.execute('select rowid from urllist').fetchall():
                self.curs.execute('insert into pagerank(urlid,score) values (%d,1.0)' % urlid)
            self.dbcommit()
    
            for i in range(iterations):
                print("Iteration %d" % (i))
                for (urlid,) in self.curs.execute('select rowid from urllist').fetchall():
                    pr = 0.15
                    # 循环遍历指向当前网页的所有其他网页
                    for (linker,) in self.curs.execute('select distinct fromid from link where toid=%d' % urlid).fetchall():
                        # 得到链接源对应网页的pagerank值
                        linkingpr = self.curs.execute('select score from pagerank where urlid=%d' % linker).fetchall()[0][0]
                        # 根据链接源求总的链接数
                        linkingcount = self.curs.execute('select count(*) from link where fromid=%d' % linker).fetchall()[0][0]
                        pr += 0.85 * (linkingpr / linkingcount)
                    self.curs.execute('update pagerank set score=%f where urlid=%d' % (pr, urlid))
                self.dbcommit()
    

    第二步、查询网址的pagerank的值为相关网址进行排名

    调用函数生成网址pagerank数据库以后,就可以通过pagerank对查询到的网址进行排名了。

    # 根据pagerank值进行评价的函数。(利用外部回值链接进行评价)。
    # rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
        def pagerankscore(self,rows):
            pageranks=dict([(row[0],self.curs.execute('select score from pagerank where urlid=%d' % row[0]).fetchall()[0][0]) for row in rows])
            maxrank=max(pageranks.values())   #求最大的pagerank值
            for urlid in pageranks:
                pageranks[urlid] /= maxrank   #归一化
            return pageranks   #返回归一化的url的pagerank
    

    第6个排名算法:利用链接文本进行评价的函数

    有时,相比于被链接的网址自身所提供的信息而言,我们从指向该网页的链接中所得到的信息会更有价值。因为针对其所指向的网页,网站的开发者会倾向于提供一些解释其内容的简短描述。

    # 利用链接文本进行评价的函数。
        # rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
        def linktextscore(self,rows,wordids):
            linkscores=dict([(row[0],0) for row in rows])
            for wordid in wordids:
                cur=self.curs.execute('select link.fromid,link.toid from linkwords,link where wordid=%d and linkwords.linkid=link.rowid' % wordid)
                for (fromid,toid) in cur.fetchall():
                    if toid in linkscores:
                        pr=self.curs.execute('select score from pagerank where urlid=%d' % fromid).fetchall()[0][0]
                        linkscores[toid]+=pr
            maxscore=max(linkscores.values())   #求最大的pagerank值
            for urlid in linkscores:
                linkscores[urlid] /= maxscore   #归一化
            return linkscores
    

    第五部分、综合利用各种评分算法,将查询到的网址进行评分排名

    # 对查询到的链接进行排名。参数:rows,wordids查询字符串id列表
        def getscoredlist(self,rows,wordids):
            totalscores=dict([(row[0],0) for row in rows])
            # 对链接进行评价的函数。(权重和评价值),使用了多种评价函数
            weights=[(1.0,self.locationscore(rows)),   #根据关键词出现的位置获取权重
                     (1.0,self.frequencyscore(rows)),  #根据关键词出现的频率获取权重
                     (1.0,self.pagerankscore(rows)),   #根据pagerank获取权重
                     (1.0,self.linktextscore(rows,wordids)), #根据链接描述获取权重
                     #(5.0,self.nnscore(rows,wordids))   #根据神经网络获取权重
                     ] 
            for (weight,scores) in weights:
                for urlid in totalscores:
                    totalscores[urlid]+=weight*scores[urlid]
    
            return totalscores  #返回每个链接的评价值
    

    现在我们已经能根据用户输入字符串,分词成多个关键词,查询相关网址,对网址进行评分。那只要按照分数进行排序,给出排名靠前的搜索引擎就完成了。

    
        #搜索函数:将上面的搜索、评价、排名合并在一起。querystr为用户输入字符串
        def query(self,querystr):
            rows,wordids=self.getmatchrows(querystr)  #rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
            # print(rows)
            rows = list(set(rows))   #去重,位置组合重复计算没有意义,虽然说,所有的都重复了不影响效果。但是计算量增大了。
            if rows==None or len(rows)==0:
                print('无法查询到,请使用空格分隔查询关键词')
                return
    
            scores=self.getscoredlist(rows,wordids)
            rankedscores=[(score,url) for (url,score) in scores.items()]
            rankedscores.sort()
            rankedscores.reverse()
            for (score,urlid) in rankedscores[0:10]:
                print('%f\t%d\t%s' % (score,urlid,self.geturlname(urlid)))
            return wordids,[r[1] for r in rankedscores[0:10]]
    
    
    #根据urlid查询url
        def geturlname(self,id):
            return self.curs.execute("select url from urllist where rowid=%d" % id).fetchall()[0][0]
    
    

    测试

    mynet=nn.searchnet('csdn.db')
    if __name__ == '__main__':
        mysearcher= searcher('csdn.db')
        searchkey = input("搜索关键词>")
        wordids,urlids=mysearcher.query(searchkey)
        print(wordids,urlids)
    

    我们输入“腾讯股票爬虫”

    返回的结果为

    3.421882	56	http://blog.csdn.net/luanpeng825485697/article/details/78451057
    3.026871	58	http://blog.csdn.net/luanpeng825485697/article/details/78442062
    1.472765	1	http://blog.csdn.net/luanpeng825485697
    1.386459	2	http://blog.csdn.net/luanpeng825485697?viewmode=contents
    1.220016	51	http://blog.csdn.net/luanpeng825485697/article/category/7225092
    1.220016	48	http://blog.csdn.net/luanpeng825485697/article/category/7083783
    1.167393	43	http://blog.csdn.net/luanpeng825485697/article/category/7060769
    1.167161	50	http://blog.csdn.net/luanpeng825485697/article/category/7190343
    1.152465	47	http://blog.csdn.net/luanpeng825485697/article/category/7145481
    1.105118	7	http://blog.csdn.net/luanpeng825485697/article/details/78154417
    
    

    搜索引擎设计成功。

    通过神经网络学习用户点击行为

    在上面的搜索引擎设计中我们实现了6种排名算法。下面我们要再介绍一种排名算法。由于这种算法的设计本身并不对文档内容进行解析,而只是对用户行为进行解析,内容较多,知识较难,所以我们单独来讲。

    下面要讲的是通过神经网络来实现搜索引擎。没有学习过深度学习的同学可以先不用看这一部分。

    神经网络设计搜索引擎,简单的说就是会记忆用户的选择行为。比如搜索引擎根据已有的算法为用户的搜索返回了一些网址。但是这些网址究竟好不好呢。网站并没有这样一个反馈机制。而搜索引擎就是为这样一个反馈机制存在的。当用户选择了一个推荐的网址,神经网络就会为这个网址添加一定的权重,下次搜索相同的内容,更加情愿优先推荐权重大的网址。

    将下面的代码存储成nn.py

    # 神经网络学习用户点击行为,实现搜索排名
    from math import tanh
    import sqlite3
    
    # 指定任何输出值的斜率
    def dtanh(y):
        return 1.0-y*y
    
    class searchnet:
        def __init__(self,dbname):
            self.con=sqlite3.connect(dbname)  #链接数据库
            self.curs = self.con.cursor()
            try:
                self.maketables()
            except:
                pass
    
        def __del__(self):
            self.curs.close()
            self.con.close()
    
        def dbcommit(self):  # 保存数据库
            self.con.commit()
    
        def maketables(self):
            self.curs.execute('create table hiddennode(create_key)')              #创建神经元节点
            self.curs.execute('create table wordhidden(fromid,toid,strength)')   #输入节点(单词)到神经元的权重,默认-0.2
            self.curs.execute('create table hiddenurl(fromid,toid,strength)')    #神经元到输出节点(链接)的权重,默认为0
            self.dbcommit()
    
            # 获取节点间权重。layer为0表示输入到神经元之间,为1表示神经元到输出之间
        def getstrength(self,fromid,toid,layer):
            if layer==0: table='wordhidden'
            else: table='hiddenurl'
            res=self.curs.execute('select strength from %s where fromid=%d and toid=%d' % (table,fromid,toid)).fetchall()
            if res==None or len(res)==0:
                if layer==0: return -0.2  # 输入到神经元之间默认为-0.2
                if layer==1: return 0   # 神经元到输出节点间默认为0
            return res[0][0]
    
        # 设置数据库中节点间权重。layer为0表示输入到神经元之间,为1表示神经元到输出之间
        def setstrength(self,fromid,toid,layer,strength):
            if layer==0: table='wordhidden'
            else: table='hiddenurl'
            res=self.curs.execute('select rowid from %s where fromid=%d and toid=%d' % (table,fromid,toid)).fetchall()
            if res==None or len(res)==0:
                self.curs.execute('insert into %s (fromid,toid,strength) values (%d,%d,%f)' % (table,fromid,toid,strength))
            else:
                rowid=res[0][0]
                self.curs.execute('update %s set strength=%f where rowid=%d' % (table,strength,rowid))
    
         # 根据已知正确的输入输出结果,创建神经元,建立输入与神经元间里连接,神经元与输出间连接。每一种输入组合都创建一个神经节点
        def generatehiddennode(self,wordids,urlids):
            # if len(wordids)>3: return None   #对于有3个输出单词的我们不做处理,太复杂
            # 检测我们是否已经为这组输入建好了一个节点
            sorted_words=[str(id) for id in wordids]
            sorted_words.sort()
            createkey='_'.join(sorted_words)
            res=self.curs.execute("select rowid from hiddennode where create_key='%s'" % createkey).fetchall()
    
            # 如果没有,就创建
            if res==None or len(res)==0:
                cur=self.curs.execute("insert into hiddennode (create_key) values ('%s')" % createkey)
                hiddenid=cur.lastrowid
                # 设置默认权重
                for wordid in wordids:
                    self.setstrength(wordid,hiddenid,0,1.0/len(wordids))   #设置输入节点到神经元间的权重为1/输入数量
                for urlid in urlids:
                    self.setstrength(hiddenid,urlid,1,0.1)   #设置神经元到输出节点间权重为0.1
                self.dbcommit()
    
        # 根据输入关键词id和相关的链接的id,获取数据库中神经元节点的id。(相关的链接也就是初步查询到的链接,只要链接的网页中出现过关键词就会被认为相关)
        def getallhiddenids(self,wordids,urlids):
            hiddenids=[]
            for wordid in wordids:
                cur=self.curs.execute('select toid from wordhidden where fromid=%d' % wordid).fetchall()
                for row in cur:
                    hiddenids.append(row[0])
            for urlid in urlids:
                cur=self.curs.execute('select fromid from hiddenurl where toid=%d' % urlid).fetchall()
                for row in cur:
                    hiddenids.append(row[0])
            return hiddenids  # 返回神经元节点
    
        # 构建一个神经网络
        def setupnetwork(self,wordids,urlids):
            # 值列表:输入:神经元、输出
            self.wordids=wordids
            self.hiddenids=self.getallhiddenids(wordids,urlids)
            self.urlids=urlids
    
            # 构建输入节点、神经元、输出节点。就是前面的输入、神经元、输出。这里用了一个更加普遍的名称
            self.ai = [1.0]*len(self.wordids)
            self.ah = [1.0]*len(self.hiddenids)
            self.ao = [1.0]*len(self.urlids)
    
            # 建立权重矩阵(线性组合系数矩阵):输入-神经元,  神经元-输出
            self.wi = [[self.getstrength(wordid,hiddenid,0)
                        for hiddenid in self.hiddenids]
                        for wordid in self.wordids]
            self.wo = [[self.getstrength(hiddenid,urlid,1)
                        for urlid in self.urlids]
                        for hiddenid in self.hiddenids]
    
        # 前馈算法:一列输入,进入神经网络,返回所有输出结果的活跃程度。越活跃也好。因为神经网络每向下传播一层就会衰弱一层。衰弱函数使用tanh这种0时陡峭,无限大或无限小时平稳的函数
        def feedforward(self):
            # 查询的单词是仅有的输入
            for i in range(len(self.wordids)):
                self.ai[i] = 1.0   #输入节点的活跃程度就设为1
    
            # 根据输入节点活跃程度,获取神经元节点的活跃程度
            for j in range(len(self.hiddenids)):
                sum = 0.0
                for i in range(len(self.wordids)):
                    sum = sum + self.ai[i] * self.wi[i][j]  # 线性组合
                self.ah[j] = tanh(sum)   #使用tanh表示神经元对输入的反应强度。(因为tanh是一个在0附近震荡强烈,在远离0时趋于稳定的函数)
    
            # 根据神经元节点活跃程度,获取输出节点的活跃程度
            for k in range(len(self.urlids)):
                sum = 0.0
                for j in range(len(self.hiddenids)):
                    sum = sum + self.ah[j] * self.wo[j][k]  # 线性组合
                self.ao[k] = tanh(sum)
    
            return self.ao[:]
    
    # =============================以上是公共实例函数=======================================
    
    #=======================getresult是应用神经网络进行搜索的函数==============================
    
        #  针对一组单词和url给出输出
        def getresult(self,wordids,urlids):
            self.setupnetwork(wordids,urlids)
            return self.feedforward()
    
    
    
    
    # ============================下面是使用反向传播法进行神经网络训练============================
    
    
     #前馈训练法:依据当前权重预测输出,计算误差,更正权重。用户每选择一次,进行一次训练
    
      #用户每选择一次链接,就调整一次权重。targets表示正确的输出结果。即用户选择的链接
        def backPropagate(self, targets, N=0.5):
            # 计算输出层误差
            output_deltas = [0.0] * len(self.urlids)
            for k in range(len(self.urlids)):
                error = targets[k]-self.ao[k]    #计算正确输出和预测输出之间的误差
                output_deltas[k] = dtanh(self.ao[k]) * error   #确定总输入需要如何改变
    
            # 计算神经元误差:
            hidden_deltas = [0.0] * len(self.hiddenids)
            for j in range(len(self.hiddenids)):
                error = 0.0
                for k in range(len(self.urlids)):
                    error = error + output_deltas[k]*self.wo[j][k]  #将每个神经元-输出间的权重值乘以输出节点的改变量,再累加求和,从而改变节点的输出结果
                hidden_deltas[j] = dtanh(self.ah[j]) * error  #确定节点的总输入所需的该变量
    
            # 更新神经元-输出间权重
            for j in range(len(self.hiddenids)):
                for k in range(len(self.urlids)):
                    change = output_deltas[k]*self.ah[j]
                    self.wo[j][k] = self.wo[j][k] + N*change
    
            # 更新输入-神经元间权重
            for i in range(len(self.wordids)):
                for j in range(len(self.hiddenids)):
                    change = hidden_deltas[j]*self.ai[i]
                    self.wi[i][j] = self.wi[i][j] + N*change
    
    
        # 更新数据库
        def updatedatabase(self):
            # 将值写入数据库
            for i in range(len(self.wordids)):
                for j in range(len(self.hiddenids)):
                    self.setstrength(self.wordids[i],self. hiddenids[j],0,self.wi[i][j])
            for j in range(len(self.hiddenids)):
                for k in range(len(self.urlids)):
                    self.setstrength(self.hiddenids[j],self.urlids[k],1,self.wo[j][k])
            self.dbcommit()
    
    
       # 对神经网络进行一次训练。wordids为查询关键词id,urlids为查找到相关的url的id,selectedurl为选中的url的id
        def trainquery(self,wordids,urlids,selectedurlid):
            # 第一次运行时,在数据库中创建表。以默认权重赋值
            self.generatehiddennode(wordids,urlids)
            # 创建神经网络类的属性。(输入、神经元、输出、两个权重)
            self.setupnetwork(wordids,urlids)
            self.feedforward()   #执行前馈算法,根据输入获取输出
            targets=[0.0]*len(urlids)
            targets[urlids.index(selectedurlid)]=1.0  #获取用户选择的正确链接
            error = self.backPropagate(targets)  #执行反向传播法修正网络
            self.updatedatabase()   #更新数据库
    
    
    if __name__ == '__main__':
        con = sqlite3.connect('csdn.db')
        curs = con.cursor()
        command = 'select * from hiddennode'  # "select fromid,toid from link"
        cur = curs.execute(command)
        res = cur.fetchall()
        if res != None and len(res) > 0:
            for row in res:
                print(row)
    

    根据长时间的用户行为,为新搜索相关的网址进行排名

    # 根据神经网络(用户点击行为学习)进行评价的函数。神经网络在nn.py中实现。
        # rows是[(urlid1,wordlocation1_1,wordlocation1_2,wordlocation1_3...),(urlid2,wordlocation2_1,wordlocation2_2,wordlocation2_3...)]
        def nnscore(self,rows,wordids):
            # 获得一个由唯一的url id构成的有序列表
            urlids=[urlid for urlid in dict([(row[0],1) for row in rows])]
            nnres=mynet.getresult(wordids,urlids)
            scores=dict([(urlids[i],nnres[i]) for i in range(len(urlids))])
            return self.normalizescores(scores)
    

    有了上面的排名算法,就可以添加到之前的综合评分函数中去了。

    展开全文
  • 产品评论大数据挖掘情感分析python版,带有python代码和数据。
  • Python数据分析与挖掘实战,实际例子,具体运用。
  • 数据挖掘导论.pdf 2.79M Python数据结构与算法(En).chm 3.34M 用Python进行自然语言处理.pdf 4.26M Python操作Mysql实例教程手册.pdf 277.04kb Python高级编程.pdf 72.29M 使用Python语言分析金融数据的研究....
  • 终于迎来了第一个数据挖掘例子,我们拿这个亲和性分析的示例来具体看下数据挖掘到底 是怎么回事。数据挖掘有个常见的应用场景,即顾客在购买一件商品时,商家可以趁机了解他们 还想买什么,以便把多数顾客愿意同时...
  • 这是频繁模式挖掘的一个经典例子——"啤酒和尿布"。简单来说,频繁模式就是当出现物品A时也经常出现物品B,比如在分析超市的购物清单时,发现买啤酒的人经常也买尿布。 购物篮分析(或是亲密性分析)是介绍...
  • 数据挖掘 | [关联规则] 利用apyori库的关联规则python代码实现 数据挖掘 | [有监督学习——分类] 朴素贝叶斯及python代码实现——利用sklearn 数据挖掘 | [无监督学习——聚类] K-means聚类及python代码实现——利用...
  • 数据挖掘建模过程及python处理实例研究.pdf数据挖掘建模过程及python处理实例研究.pdf数据挖掘建模过程及python处理实例研究.pdf数据挖掘建模过程及python处理实例研究.pdf数据挖掘建模过程及python处理实例研究.pdf...
  • 数据挖掘建模过程及python处理实例研究.docx数据挖掘建模过程及python处理实例研究.docx数据挖掘建模过程及python处理实例研究.docx数据挖掘建模过程及python处理实例研究.docx数据挖掘建模过程及python处理实例研究...
  • 作为一种解释型语言,Python的设计哲学强调代码的可读性和简洁的语法(尤其是使用空格缩进划分代码块,而非使用大括号或者关键词)。...数据挖掘工具包。1. PyBrain【PyBrain】是一个用于Python的模块化机器...
  • Python数据挖掘实例(实时更新)

    万次阅读 2017-08-15 12:29:41
    数据挖掘
  • <python数据挖掘概念方法与实践>z这本书的例子代码,但是该书由部分内容需要通过爬虫什么的,具体看书中章节缩写。
  • 推荐一本Python数据挖掘的好书

    千次阅读 2020-04-27 21:12:50
    Python语言在数据领域江湖老大的地位毋庸置疑,所以有了很多优秀...现在安顿下来了,在这里分享一本Python数据挖掘的好书给大家作为补偿,文末附有电子版的获取方式。当然,书还是要买纸质版的读来的过瘾。 ...
  • 刚拿到这个问题,大部分小伙伴一定会感觉到无所下手,数据挖掘内容那么多,要从哪个位置开始入手,于是小编,也去试了试,先给自己定了个大的框架,于是一步一步把这个过程走出来,接着就帮大家呈现以下内容,不知道...
  • python数据分析 数据集,包括源代码,实例源码和数据
  • python 数据挖掘篇四 小说数据挖掘实例Python 安装 python 学习 一 python 语法,及变量类型 python 学习 二 爬一个图片网站上 python 学习 二 02 爬一个图片网站,获得主链接网址,并保存 python 学习 二 03 爬一个...
  • 具体例题可参考《数据挖掘概念与技术》一书。 数据 数据来源于《数据挖掘概念与技术》书中。以下实现均基于这个数据。 RID age income student credit_rating Class: buys_computer 1 youth high no fair no 2 ...
  • 本文结合代码实例待你上手python数据挖掘和机器学习技术。本文包含了五个知识点:1.数据挖掘与机器学习技术简介2. Python数据预处理实战3.常见分类算法介绍4.对鸢尾花进行分类案例实战5.分类算法的选择思路与技巧一...
  • Python数据分析与挖掘

    2021-06-09 13:23:58
    围绕Python基础语法介绍、数据预处理、数据可视化以及数据分析与挖掘......这些核心技能模块展开,帮助你快速而全面的掌握和了解成为一个数据分析师的所有必修功法。 三、数据采集篇: 通过网络爬虫实战解决数据...
  • 通过 DCGAN网络来训练数据,从而产生人脸图像。 实验准备: 数据源的获取:根据人名随机地从网页图片上抓取包含人脸的图片。而人名的获取是从 Dbpedia上得到的,作为一个标准,他们都是出生在现代。这个数据集是来自1万...
  • 本文的数据来源是2009年UC1库中的 Wine Quality Data Set的数据,选取其中 Vinho Verde牌子的葡萄牙青酒数据作为分析探究,数据集共计1600个样本。在1600个样本数据中包含了11个表示该葡萄酒样本的物理及化学性质数据,...
  • 如何用Python编写一个简单的爬虫进行数据挖掘(基于Jupyter NoteBook) 引言: 该文章将会从极其简略的角度去说明如何搭建一个爬虫对目标数据,有效信息进行挖掘,并且将小编在自学中遇到的一些问题进行引出和附上解决...
  • 1.1简单例子 from sklearn import linear_model x=[[0,0],[1,1],[2,2]] y=[0,1,2] reg=linear_model.LinearRegression() reg.fit(x,y) print(reg.predict([[3,3]])) 1.2糖尿病数据集 import matplotlib.pyplot as...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,806
精华内容 15,122
关键字:

数据挖掘python实例