罗兰在MATLAB的艺术

把想法变成MATLAB

请注意

罗兰在MATLAB的艺术已经存档,不会被更新。

网页抓取和采矿与MATLAB的非结构化数据

大量的信息在网络上共享,很多人利用它很感兴趣。它可以用来丰富现有的数据,例如。然而,信息埋葬在HTML标记,不容易提取有用的信息。今天的嘉宾博客古原竹内向我们展示他如何使用MATLAB网页抓取从网上获取有用的数据,然后使用模糊字符串匹配,丰富现有数据。

内容

少量的2015篇论文

网页抓取与MATLAB由于新的字符串实际上是很简单的因数introdiced R2016B。

我将作为一个例子中使用的相同的数据文本挖掘与MATLAB机器学习研究论文

如果你想继续,请下载

我在这里使用sqlite数据库工具箱从sqlite数据加载文件。如果你没有数据库工具箱,您可以试一试readtable读CSV文件。作者表只列出名字,但是我想与作者的丰富affilation看到组织活跃在这个学术会议。

db =“输出/ database.sqlite”;%数据库文件康涅狄格州= sqlite (db,“只读”);%建立连接作者=获取(康涅狄格州,“从作者的选择*);%与SQL命令获取数据论文=获取(康涅狄格州,“SELECT * FROM论文”);%与SQL命令获取数据PaperAuthors =获取(康涅狄格州,“SELECT * FROM PaperAuthors”);%与SQL命令获取数据关上(康涅狄格州)%紧密联系作者= cell2table(作者,“VariableNames”,{“ID”,“名字”});%转换为表论文= cell2table(论文,“VariableNames”,%转换为表{“ID”,“标题”,“EventType”,“PdfName”,“抽象”,“PaperText”});PaperAuthors = cell2table (PaperAuthors,“VariableNames”,%转换为表{“ID”,“PaperID”,“AuthorID”});(作者)
ans = 8×2表ID名称___ ______________________ 178”Yoshua Bengio”200“雅安·勒存205 Avrim勃鲁姆347乔纳森·d·科恩350年“Samy Bengio”521“Alon Orlitsky”549 Wulfram Gerstner 575年罗伯特·c·威廉姆森的

幸运的是,有一个HTML文件,列出每篇论文的作者和他们的信仰。每个列表项<我> < span class = "字体" >和结尾< / b > < br > < br >、标题和作者是分开的< / span > < / i > < br > < b >由分号,多种合著者,最后的名字和所属的逗号。

dbtype输出/ accepted_papers.html397:400
397 < div > < div > < h3 >捏2015接受论文< / h3 > < p > < br > 398 < / p > <我> < span class = "字体" >双重或无:乘法激励机制众包< / span > < / i > < br > < b > 399 Nihar沙*,加州大学伯克利分校;周Dengyong MSR < / b > < br > < br > <我> < span class = "字体" >学习与对称标签噪音:精神错乱的重要性< / span > < / i > < br > < b > 400·范·罗延NICTA;NICTA Aditya梅农*;罗伯特•威廉姆森NICTA < / b > < br > < br > <我> < span class = "字体" >算法稳定和统一的泛化< / span > < / i > < br > < b >

因为我有在本地html文件,我使用fileread加载文本。如果你想直接柱身网页,您将使用webread代替。文本转换为进口字符串利用内置的字符串函数,

html =字符串(fileread (“输出/ accepted_papers.html”));%加载文本文件% = html字符串(webread (“https://nips.cc/Conferences/2015/AcceptedPapers”));

从一个网页抓取数据

通常从一个网页抓取数据或其他非结构化文本数据来源需要正则表达式和许多人发现它强大但很难使用。字符串函数在MATLABextractBetween,extractBefore,extractAfter,擦除,取代使它简单得可笑!

pattern1 =' < div > < h3 >捏2015接受论文< / h3 > < p > < br > < / p > ';%的列表pattern2 =“< / div > < !——div类= " col-xs-12 col-sm-9”- - >“;%的列表列表= extractBetween (html、pattern1, pattern2);%提取列表pattern1 =' <我> < span class = "字体" > ';%的列表项pattern2 =' < / b > < br > < br > ';%的列表项listitem = extractBetween(列表,pattern1, pattern2);%提取列表项pattern1 = [' < / span > < / i > < br > < b > '换行符);%的标题标题= extractBefore (listitem pattern1);%提取标题namesorgs = extractAfter (listitem pattern1);%提取组织名称namesorgs =擦掉(namesorgs,‘*’);%删除*namesorgs =擦掉(namesorgs,“””);%抹去”namesorgs =取代(namesorgs,' ',' ');%去除两倍行距disp([标题(1:2)namesorgs (1:2)))
“双或无:Multiplicati…”“Nihar Shah,加州大学伯克利分校;Dengyo…”“学习与对称标签N…”“布兰登·范·罗延NICTA;平硐…”

因为多个合作者仍然包含在一个字符串中,让我们单独成一个合作者及其affilation列表。当你把一个字符串,得到不同数量的子字符串取决于每一行。所以我们需要使用arrayfun解析| UniformOutput |选项设置把它行,行,修剪的结果strtrim细胞aray与vertcat让合作者的名单和他们的信仰。

namesorgs =取代(namesorgs,“,”,“&”);%恢复了&namesorgs =擦掉(namesorgs, char (194)' < / b > < span > < >强']);%去除多余的标签namesorgs =取代(namesorgs, (' < /强> < / span > < b > '%替代缺失的分号char (194)),“;”);coauth = arrayfun (@ (x) strtrim (split (x,“;”namesorgs)),%由分号分割“UniformOutput”、假);%和空白coauth = vertcat (coauth {:});% unnest运算单元阵列coauth (1:5)
ans = 5×1的字符串数组”Nihar Shah,加州大学伯克利分校”“周Dengyong MSR”“NICTA Brendan范·罗延”“Aditya Menon NICTA”“NICTA罗伯特•威廉森”

匹配刮数据到数据库表中

你现在看到与MATLAB web抓取是多么简单。

现在,我们已经联系的名单,我们只需要匹配作者表的名字,对吧?不幸的是,我们看到很多甚至缺失值因为名称不匹配包含部分匹配函数。

真正困难的部分现在是要做什么在你刮的数据网络。

作者= Authors.Name;%的作者的名字名称= strtrim (extractBefore (coauth,”、“));%提取和修剪的名字org =字符串(长度(作者),1);%初始化累加器2 = 1:长度(作者)每个名字在作者| | %res = coauth(包含(名称、作者(ii)));% | |中找到匹配名称如果isempty (res)%如果不匹配org (ii) =失踪;%标记失踪结束res = extractAfter (res,”、“);%提取后的逗号res = strtrim (res);%去除空格res =独特(res);%删除重复的res (strlength (res) = = 0) = [];%去除emptry字符串如果长度(res) = = 1%如果单一字符串org (ii) = res;%使用它elseif长度(res) > 1%如果多个字符串org (ii) =加入(res,“;”);%与分号加入他们其他的%,否则org (ii) =失踪;%标记失踪结束结束头(表(作者、机构、“VariableNames”,{“名字”,“Org”}))
ans = 8×2表名Org ______________________ _____________________________________”Yoshua Bengio”“美国蒙特利尔”的“雅安·勒存“纽约大学”“Avrim勃鲁姆”<失踪>乔纳森·d·科恩的<失踪>“Samy Bengio”“谷歌研究”“Alon Orlitsky”“加州大学圣地亚哥分校”“Wulfram Gerstner”“后续”罗伯特·c·威廉姆森的<失踪>

例如,部分匹配不工作如果中间缺失或昵称是用来代替全名。可以有其他违规行为。啊,我们正在处理非结构化数据!

[作者(4)coauth(包含姓名、“乔纳森·科恩”));作者(8)coauth(包含姓名、“罗伯特·威廉姆森”));作者(406)coauth(包含姓名、“Sanmi Koyejo”));作者(440)coauth(包含姓名、“达尼洛Rezende”));作者(743)coauth(包含姓名、“比尔玩弄”));作者(769)coauth(包含姓名、“朱利安Yarkony”)))
ans = 6×2字符串数组“乔纳森·d·科恩”“普林斯顿Unive乔纳森•科恩…”“罗伯特·c·威廉姆森”“NICTA罗伯特•威廉姆森”“Oluwasanmi o . Koyejo”“Sanmi Koyejo,斯坦福大学“Danilo吉梅内斯Rezende”“达尼洛Rezende,谷歌DeepMind”“威廉玩弄””斯坦福大学的比尔磨磨蹭蹭的,快…”“朱利安·e·Yarkony”“朱利安Yarkony,博士”

模糊字符串匹配

我们能做什么当精确匹配方法不工作吗?也许我们可以想出各种规则使用正则表达式来匹配字符串,但这是非常耗时。让我们回顾一下40岁的算法,得不到提高来解决这个问题。我创建了一个新的自定义函数levenshtein对于这个示例。它计算编辑距离测量所需的最低数量的编辑操作将一个字符串转换成另一个,来量化相似或相异的。本算法的更多细节,请查看上面的博客链接

周六周日需要转换3编辑操作。

levenshtein (“星期天”,“星期六”)
ans = 3

也许是更容易理解如果我展示他们有多相似匹配率而不是数量的编辑操作?

levenshtein (“星期天”,“星期六”,“比”)
ans = 0.78571

现在我们可以找到“乔纳森·科恩”在前3场比赛,”乔纳森·d·科恩”。

fhandle = @ (s) levenshtein(作者(4),,“比”);%函数处理比率= arrayfun (fhandle extractBefore (coauth,”、“));%得到匹配率[~,idx] =排序(比率,“下”);%等级匹配率[repmat(作者(4),(3,1))coauth (idx(1:3))比率(idx (1:3)))
ans = 3×3的字符串数组“乔纳森·d·科恩”“乔纳森•科恩公关…”“0.90323”“乔纳森·d·科恩”“乔纳森•Bassen年代…”“0.8125”“乔纳森·d·科恩”“乔纳森•Vacher U…”“0.8125”

验证模糊匹配结果

让,试试这个方法失踪前10名ignoreCase选择启用。看起来我们可以相当有信心的结果,只要最大匹配率是0.8或更高版本。

org (org = =“博士”。)=失踪;%去除称呼missing_ids =找到(ismissing (org));%获得失踪的身份证=匹配字符串(1、3);%初始化累加器2 = 1:10%为每个失踪的idcid = missing_ids (ii);%当前idfhandle = @ (s) levenshtein(作者(cid),,“比”,“ingoreCase”);比率= arrayfun (fhandle、名称);%得到匹配率[~,idx] = max(比率);%得到最大价值的指标匹配(ii):) =(作者(cid) coauth (idx)比率(idx)];%更新累加器结束匹配
匹配= 10×3字符串数组”Avrim布卢姆”“曼努埃尔•布卢姆Unive…”“0.71429”“乔纳森·d·科恩”“乔纳森•科恩公关…”“0.90323”“罗伯特·c·威廉姆森”“罗伯特·威廉姆森…””的“Juergen。施密德胡贝尔表示“0.91892 J ?”,的rgen。施密德胡贝尔表示“0.94595”“沃尔夫冈马斯河”“沃尔夫冈•马斯河”“1”“罗伯特·e·Schapire”“罗伯特•Schapire M…”“0.90909”“著名生田斗真Lozano-PA©著名托马兹”“Lozano-PA©r…”“1”“Dit-Yan Yeung说燕Yeung,科大”“0.96154”“杰弗里·j·戈登”“杰夫•戈登CMU”“0.8”“布兰登·j·弗雷”“布兰登·弗雷,美国T…”“0.88889”

更新缺失值和模糊匹配的结果

现在我们可以应用这种方法来更新缺失值。现在89.3%的缺失值确定!

2 = 1:长度(missing_ids)%为每个失踪的idcid = missing_ids (ii);%当前idfhandle = @ (s) levenshtein(作者(cid),,“比”,“ignoreCase”);比率= arrayfun (fhandle、名称);%得到匹配率[~,idx] = max(比率);%得到最大价值的指标如果比率(idx) > = 0.8%如果最大是0.8res = extractAfter (coauth (idx),”、“);%组织名字res = strtrim (res);%修剪空白如果strlength (res) = = 0%如果空字符串org (cid) =“UNK”;%未知其他的%,否则org (cid) = res;%更新组织结束结束结束流(“失踪减少% .1f % % \ n '(1 - sum (ismissing (org)) /长度(missing_ids)) * 100)
缺失降低了89.3%

回顾无与伦比的

当你回顾一下不匹配,你可以看到,他们没有好的比赛除了“约翰·w·费舍尔三世”,“Oluwasanmi o . Koyejo”或“Danielo Jimenz Rezende”。匹配率要低得多,没有减少,但是我们不一定缓解截止。有另一个吗?

missing_ids =找到(ismissing (org));%获得失踪的身份证=匹配字符串(1、3);%初始化累加器2 = 1:10%对每个id通过10日失踪cid = missing_ids (ii);%当前idfhandle = @ (s) levenshtein(作者(cid),,“比”,“ignoreCase”);比率= arrayfun (fhandle、名称);%得到匹配率[~,idx] = max(比率);%得到最大价值的指标匹配(ii):) =(作者(cid) coauth (idx)比率(idx)];%更新累加器结束匹配
匹配= 10×3字符串数组”Avrim布卢姆”“曼努埃尔•布卢姆Unive…”“0.7619”“约翰·w·费舍尔三世”“约翰·费舍尔,麻省理工学院”“0.75862”“A-zgA¼r ažimaÿek”“Ozgur希姆塞克马克斯…”“0.71429”“约瑟夫·j·Lim”“约瑟夫鲑鱼、电话…”“0.76923”“帕斯卡Fua”“帕斯卡文森特,U。…”“0.70833”“FranA§ois小花”“马提亚•弗雷U…”“0.71875”“Oluwasanmi o . Koyejo”“Sanmi Koyejo,斯坦…”“0.75”“萨梅特Oymak”“詹姆斯•郭香港K…”“0.71429”“达尼洛吉梅内斯雷兹…”“达尼洛Rezende,去…”“0.77778”“Kafui Dzirasa”“拉胡尔Krishnan, Ne…”“0.66667”

子串匹配

而不是试图匹配整个字符串,我们可以重新排序,找到最相似的子串的长字符串基于短字符串使用忽略命令部分选项:

  • ignoreOrder字符串分解成令牌,重新排序通过寻找联盟和十字路口的令牌,令牌和计算编辑距离。
  • 部分找到子字符串在长字符串,是最接近短字符串。

这显然给更高的匹配率在一些特定的情况下。“约翰·w·费舍尔三世”可以被重新排序,“约翰·费舍尔三世w”和令牌(一个字符串)的头两场比赛“约翰·费雪”,这使得它100%的比赛。

=匹配字符串(1、3);%初始化累加器2 = 1:10%对每个id通过10日失踪cid = missing_ids (ii);%当前idfhandle = @ (s) levenshtein(作者(cid),,“比”,“ingoreCase”,“ignoreOrder”,“部分”);比率= arrayfun (fhandle、名称);%得到匹配率[~,idx] = max(比率);%得到最大价值的指标匹配(ii):) =(作者(cid) coauth (idx)比率(idx)];%更新累加器结束匹配
匹配= 10×3字符串数组”Avrim布卢姆”“曼努埃尔•布卢姆Unive…”“0.75”“约翰·w·费舍尔三世”“约翰·费舍尔,麻省理工学院”“1”“A-zgA¼r ažimaÿek”“Ozgur希姆塞克马克斯…”“0.66667”“约瑟夫·j·Lim”“约瑟夫•王”“0.81818”“帕斯卡Fua”“帕斯卡文森特,U。…”“0.85”“FranA§ois小花”“添添,Tsinghu…”“0.75”“Oluwasanmi o . Koyejo”“Sanmi Koyejo,斯坦…”“0.79167”“萨梅特Oymak”“詹姆斯•Hensman了…”“0.77273”“达尼洛吉梅内斯雷兹…”“达尼洛Rezende,去…”“1”“Kafui Dzirasa”“凯迷,杜克大学…”“0.71429”

更新缺失值和字符串匹配的结果

字符串匹配是一个棘手的选择——它可以产生更多的假阳性。让我们为截止使用匹配率0.9或以上。使用这种方法,失踪的价值观进一步减少了35.5%。

2 = 1:长度(missing_ids)%为每个失踪的idcid = missing_ids (ii);%当前idfhandle = @ (s) levenshtein(作者(cid),,“比”,“ingoreCase”,“ignoreOrder”,“部分”);比率= arrayfun (fhandle、名称);%得到匹配率[~,idx] = max(比率);%得到最大价值的指标如果比率(idx) > = 0.9%如果最大是0.9res = extractAfter (coauth (idx),”、“);%组织名字res = strtrim (res);%修剪空白如果strlength (res) = = 0%如果空字符串org (cid) =“UNK”;%未知其他的%,否则org (cid) = res;%更新组织结束结束结束流(“失踪减少% .1f % % \ n '(1 - sum (ismissing (org)) /长度(missing_ids)) * 100)
缺失降低了35.5%

可视化的论文作者联系

现在我们可以使用匹配的数据可视化由论文作者联系。PaperAuthor表可以被视为边缘列表,论文和作者代表节点的图,每一行代表一个优势。我们只需要更换作者和他们的关系,以便每个节点代表一个纸或作者的从属关系的,和边代表论文的作者。

  • 一篇论文有多个传入边缘如果由学者从多个组织,
  • 和这些文件也连接到其他节点如果他们的合作者也有助于其他论文。
  • 论文作者在同一组织将孤立的,它是简化visualzation从图中删除。
  • 结果图代表了最大连接组件的整体图。
  • 节点大小和颜色反映出度——有多少论文是由一个给定的组织的成员

这个可视化显示,我们有更多的工作要做——例如,“德克萨斯大学奥斯汀”和“标准以内的”是相同的组织,但我们有两个独立节点因为organizatoin名字不是标准化的,这意味着一些组织可能是under-reprsented。你能改进这个visualzation吗?

房颤=表(Authors.ID、组织、“VariableNames”,{“AuthorID”,“Org”});%归属房颤(Af。Org = =“UNK”:| ismissing (Af.Org)) = [];%去除UNK &失踪T = innerjoin (PaperAuthors: 2:3) (Af);%加入PaperAuthorsT = innerjoin (T,论文(:[1,2]),“钥匙”1);%与论文[T ~ idx] =独特(T (:, (3、4)),“行”);%去除重复的行w = accumarray (idx, 1);%计算重复s = cellstr (T.Org);%转换为cellstrt = cellstr (T.Title);%转换为cellstrG =有向图(s t w);%建立有向图垃圾箱= conncomp (G,“类型”,“弱”,“OutputForm”,“细胞”);%上网比较[~,idx] = max (cellfun (@length垃圾箱));%找到最大的排版G =子图(G,垃圾箱{idx});%最大子图比较%的新人物colormap很酷的%使用酷colormapmsize = 10 *(出度(G) + 3)。/ max(出度(G));%标记大小ncol =出度(G) + 3;%节点颜色名叫=出度(G) > 7;%节点标签h =情节(G,“MarkerSize”msize,“NodeCData”,ncol);%绘制图布局(h,“force3”,“迭代”,30)布局变化百分比labelnode (h,发现(命名),G.Nodes.Name(命名));%添加节点标签标题(“少量的2015篇论文,作者Affilation图”)%添加标题%设置轴集(gca),“剪裁”,“关闭”)%关掉剪裁变焦(1.3)%放大

总结

Web抓取可以是一种非常有用的技巧从网上收集信息,和MATLAB就能很容易地从网页中提取信息。产生的数据往往是结构化的,但是您可以使用模糊字符串匹配技术处理它。

我希望这个例子给你很多新的想法。试一试,让我们知道你的经验在这里!




发表与MATLAB®R2017a


评论

留下你的评论,请点击在这里MathWorks账户登录或创建一个新的。