如何在Python和.Net中使用ML解决旧问题


碰巧有些任务困扰了您很多年。 对我来说,将紧紧地塞住换行符和换行符的文本句子拼凑在一起成为了一项任务。 实际上,这是从PDF或使用OCR提取的文本。 通常,可以在在线图书馆的站点上,由DOS编辑器编辑过的旧文档的档案中找到这样的文本。 然后,这种格式会干扰后续的NLP处理的正确分解为句子(以及连字符为令牌)。 而且在搜索结果中显示这样的文档实在是太平庸了-这很丑陋。


我几次解决了这个问题-在Delphi中,C#。 然后这是一个艰苦的算法,例如,我用我的双手写下了文本的宽度,因此该文本被视为“以旧方式格式化”。 这并不总是完美的,但是总的来说就足够了。


目前,我正在使用Python进行一些ML项目的爬网。 在某一时刻,事实证明,下一个文档集由从科学文章的PDF版本提取的文本组成。 当然,该文本是用段落的结尾处的字符(带有连字符)以强行换行来提取的。 也就是说,不可能进一步正常处理此类文本。 Python具有吸引力,因为它几乎拥有一切! 但是几个小时的搜索却没有任何理智的结果(当然,这正是我想要的)。 然后,我再次决定为此类文档编写后处理器。 选择是从两个选项中进行的-使用C#移植过去的代码,或编写可以讲授的内容。 最后,第二种方法是由以下事实引起的:科学文本部分是从两栏文本中导出的,而部分是从单栏文本中导出的。 字体大小也不同。 这就导致了这样一个事实,即带有硬连线的允许边界的旧版本通常无法正常工作。 要再次手动坐下,请拿起选项-不会,很快就会出现奇异之处 ,我没有时间这样做! 因此,我们决定-我们正在使用机器学习编写一个库。


所有代码都可以在存储库中找到:



标记


机器学习的嗡嗡声和复杂性是什么-如果算法在某处失败,通常您不需要更改程序本身。 收集新数据就足够了(通常需要同时对它们进行批注),然后重新开始构建模型。 电脑将为您完成其余的工作。 当然,对于新数据,您可能必须提出新功能,更改体系结构,但事实证明,在大多数情况下,您只需要验证一切都可以正常工作即可。 这也是一个困难-收集和标记数据可能很困难。 还是很困难。 而且-非常无聊:-)


因此,最无聊的是标记。 corpus文件夹包含我刚刚从当时正在使用的Krapivin2009文档正文中获取的文档。 有10份文件对我来说似乎很典型。 我只标记了3个,因为在此基础上开始培训以来,就已经获得了足够质量的“粘合剂”。 如果将来发现一切都不是那么简单,那么带有标记的新文档将被放到该文件夹​​中,并且将重复学习过程。


在这种情况下,文件保留为文本对我来说似乎很方便,因此标记格式是在行的开头添加一个标志,表明该行应粘贴到前一个(``+''字符)或不粘贴(``*''字符)。 这是一个代码段(文件1005058.txt ):


*Introduction *Customers on the web are often overwhelmed with options and flooded with promotional messages for +products or services they neither need nor want. When users cannot find what they are searching for, the +e-commerce site struggles to maintain good customer relations. *Employing a recommender system as part of a site's Customer Relationship Management (CRM) activities +can overcome the problems associated with providing users with too little information, or too much of +the wrong information. Recommender systems are able to assist customers during catalog browsing and are +an effective way to cross-sell and improve customer loyalty. *In this paper, we will compare several recommender systems being used as an essential component of +CRM tools under development at Verizon. Our solutions are purposely for the current customers and current +products - recommendations for new customers and new products are out of the scope of this paper. 

准备了几个小时的繁琐工作和3个带有2300个示例(一行-一个示例)的文件。 对于许多简单的分类器(例如逻辑回归)而言,这已经足够了,然后再进行应用。


特色功能


分类器不能直接与文本数据一起使用。 具有功能的条目-数字或布尔符号(再次转换为数字0/1)表示是否存在某些功能。 通过良好的数据构建正确的功能是机器学习成功的关键。 我们案例的一个特点是我们的语料库是英文文本。 而且我希望至少获得最小的语言独立性。 至少在欧洲语言范围内。 因此,对于文本功能,我们使用了一些技巧。


通过_featurize_text_with_annotation帮助函数将文本转换为功能和标签的列表(是否与上一行粘合):


 x, y = pdf_lines_gluer._featurize_text_with_annotation(raw_text) 

注意-这里以及主要是python go中的代码片段,您可以在笔记本电脑中完全看到它们。


使用的功能:


  • 'this_len'-当前行的长度(以字符为单位)。
  • 'mean_len'--5 ... + 5行范围内的平均行长。
  • 'prev_len'-前一行的长度,以字符为单位。
  • 'first_chars'-这是我们的棘手功能。 字符串的前2个字符位于此处。 但同时,所有小写字母(任何字母)都将替换为英文字符“ a”,大写字母将替换为“ A”,数字将替换为“ 0”。 这可以大大减少可能的信号的数量,同时对其进行汇总。 发生的情况的示例:“ Aa”,“ aa”,“ AA”,“ 0”,“ a-” ...
  • 'isalpha'-字母是否为前一行的最后一个字符。
  • 'isdigit'-数字是否为前一行的最后一个字符。
  • 'islower'-小写字母是否为前一行的最后一个字符。
  • 'punct'-以前一行结尾的标点符号,或其他字符的空格。

一行的一组功能的示例:


 {'this_len': 12, 'mean_len': 75.0, 'prev_len': 0, 'first_chars': 'Aa', 'isalpha': False, 'isdigit': False, 'islower': False, 'punct': ' '} 

为了使sklearn包中的分类器能够与它们一起使用,我们使用DictVectorizer类,借助该类,字符串特征(我们拥有“ first_chars”)被转换为多个标题为(名称可以通过get_feature_names()获得)的列,其形式为first_chars = Aa','first_chars = 0。 布尔特征变为零和一,而数值仍为数字-字段名称不变。 从外部看,该方法返回近似此类型的numpy.array(仅显示一行):


 [[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 39.1 30. 0. 1. 36. ]] 

分类器培训


以浮点数数组的形式接收到一组功能之后,我们现在就可以开始学习过程了。 为此,我们使用逻辑回归作为分类器。 类是不平衡的,因此我们设置class_weight ='balanced'选项,我们在案例的测试部分检查结果:


 from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report clf = LogisticRegression(random_state=1974, solver='liblinear', max_iter=2000, class_weight='balanced') clf.fit(x_train, y_train) y_pred = clf.predict(x_test) print(classification_report(y_true=y_test, y_pred=y_pred)) 

我们得到这样的质量指标:


  precision recall f1-score support False 0.82 0.92 0.86 207 True 0.96 0.91 0.94 483 accuracy 0.91 690 macro avg 0.89 0.91 0.90 690 weighted avg 0.92 0.91 0.91 690 

如您所见,在大约1/10的情况下,我们会遇到各种错误。 但是实际上,一切并不那么可怕。 事实是,即使使用眼睛标记,也不总是很清楚段落的结尾在哪里,句子的结尾在哪里。 因此,即使标记本身也可能包含此类错误。 但是,最严重的错误不是在提案边界上发生的错误,而是提案仍然被撕毁的地方。 实际上,这种错误很少。


恢复文字


是时候恢复从PDF中提取损坏的文本了。 我们已经可以确定是否将线与上一行粘合,但是还有一点-连字。 这里的一切都非常简单,因此我对这一部分进行了艰苦的编码(我允许自己使用伪代码):


      :         :       :      :        \n 

有了这样的策略,我们恢复了英文文本(原始文本中存在诸如“ ff”和“ fi”之类的错误-只是从Krapivin2009案例中复制而来):


原始英文文本
 text = """The rapid expansion of wireless services such as cellular voice, PCS (Personal Communications Services), mobile data and wireless LANs in recent years is an indication that signicant value is placed on accessibility and portability as key features of telecommunication (Salkintzis and Mathiopoulos (Guest Ed.), 2000). devices have maximum utility when they can be used any- where at anytime". One of the greatest limitations to that goal, how- ever, is nite power supplies. Since batteries provide limited power, a general constraint of wireless communication is the short continuous operation time of mobile terminals. Therefore, power management is y Corresponding Author: Dr. Krishna Sivalingam. Part of the research was supported by Air Force Oce of Scientic Research grants F-49620-97-1- 0471 and F-49620-99-1-0125; by Telcordia Technologies and by Intel. Part of the work was done while the rst author was at Washington State Univer- sity. The authors' can be reached at cej@bbn.com, krishna@eecs.wsu.edu, pagrawal@research.telcordia.com, jcchen@research.telcordia.com c 2001 Kluwer Academic Publishers. Printed in the Netherlands. Jones, Sivalingam, Agrawal and Chen one of the most challenging problems in wireless communication, and recent research has addressed this topic (Bambos, 1998). Examples include a collection of papers available in (Zorzi (Guest Ed.), 1998) and a recent conference tutorial (Srivastava, 2000), both devoted to energy ecient design of wireless networks. Studies show that the signicant consumers of power in a typical laptop are the microprocessor (CPU), liquid crystal display (LCD), hard disk, system memory (DRAM), keyboard/mouse, CDROM drive, oppy drive, I/O subsystem, and the wireless network interface card (Udani and Smith, 1996, Stemm and Katz, 1997). A typical example from a Toshiba 410 CDT mobile computer demonstrates that nearly 36% of power consumed is by the display, 21% by the CPU/memory, 18% by the wireless interface, and 18% by the hard drive. Consequently, energy conservation has been largely considered in the hardware design of the mobile terminal (Chandrakasan and Brodersen, 1995) and in components such as CPU, disks, displays, etc. Signicant additional power savings may result by incorporating low-power strategies into the design of network protocols used for data communication. This paper addresses the incorporation of energy conservation at all layers of the protocol stack for wireless networks. The remainder of this paper is organized as follows. Section 2 introduces the network architectures and wireless protocol stack considered in this paper. Low-power design within the physical layer is brie y discussed in Section 2.3. Sources of power consumption within mobile terminals and general guidelines for reducing the power consumed are presented in Section 3. Section 4 describes work dealing with energy ecient protocols within the MAC layer of wireless networks, and power conserving protocols within the LLC layer are addressed in Section 5. Section 6 discusses power aware protocols within the network layer. Opportunities for saving battery power within the transport layer are discussed in Section 7. Section 8 presents techniques at the OS/middleware and application layers for energy ecient operation. Finally, Section 9 summarizes and concludes the paper. 2. Background This section describes the wireless network architectures considered in this paper. Also, a discussion of the wireless protocol stack is included along with a brief description of each individual protocol layer. The physical layer is further discussed. """ corrected = pdf_lines_gluer._preprocess_pdf(text, clf, v) print(corrected) 

恢复后,我们得到:


恢复英文文本

近年来,无线服务(如蜂窝语音,PCS(个人通信服务),移动数据和无线局域网)的迅速扩展表明,作为电信的主要特征(Salkintzis和Mathiopoulos(来宾Ed),可访问性和可移植性具有重要价值。 。,2000)。 设备可以随时随地使用时具有最大的实用性。“然而,目标的最大局限性在于电源的限制。由于电池提供的功率有限,因此无线通信的普遍限制是移动设备的短连续运行时间因此,电源管理是必要的作者:Krishna Sivalingam博士。这项研究的一部分得到了空军科学研究院Oce的支持,分别获得F-49620-97-10471和F-49620-99-1-0125; Telcordia技术和英特尔共同完成。部分工作是在第一作者在华盛顿州立大学期间完成的,可以通过cej @ bbn.com,krishna @ eecs.wsu.edu,pagrawal @ research.telcordia.com与作者联系。 jcchen@research.telcordia.com c
2001年Kluwer学术出版社。 在荷兰印刷。
Jones,Sivalingam,Agrawal和Chen是无线通信中最具挑战性的问题之一,最近的研究已经解决了这个问题(Bambos,1998年)。 示例包括(Zorzi(Guest Ed。),1998年)中的可用论文集和最近的会议教程(Srivastava,2000年),它们都致力于无线网络的节能设计。
研究表明,典型笔记本电脑中功耗的主要消耗者是微处理器(CPU),液晶显示器(LCD),硬盘,系统内存(DRAM),键盘/鼠标,CDROM驱动器,oppy驱动器,I / O子系统,无线网络接口卡(Udani和Smith,1996; Stemm和Katz,1997)。 Toshiba 410 CDT移动计算机的一个典型示例表明,显示器消耗的功率接近36%,CPU /内存消耗的功率为21%,
无线接口占18%,硬盘驱动器占18%。 因此,在移动终端的硬件设计(Chandrakasan和Brodersen,1995)以及诸如CPU,磁盘,显示器等组件中,已经大量考虑了节能。 通过将低功耗策略纳入用于数据通信的网络协议的设计中,可以显着节省更多功率。 本文探讨了在无线网络协议栈的所有层中纳入节能措施的问题。
本文的其余部分安排如下。 第2节介绍了本文考虑的网络体系结构和无线协议栈。 物理层内的低功耗设计简捷
在第2.3节中讨论。 第3节介绍了移动终端的功耗来源以及降低功耗的一般准则。第4节描述了处理无线网络MAC层内的节能协议的工作,而LLC层内的节能协议则在第3节中介绍。
5.第6节讨论了网络层内的功率感知协议。 在第7节中讨论了在传输层中节省电池电量的机会。第8节介绍了OS /中间件和应用程序层中的技术,以实现节能运行。
最后,第9节总结并总结了本文。
2.背景
本节描述了本文考虑的无线网络架构。 另外,还包括对无线协议栈的讨论以及对每个单独协议层的简要描述。 物理层将进一步讨论。


这里有一个有争议的地方,但是总的来说,句子已被恢复,这样的文本已经可以作为整个句子处理了。


但是我们正计划做出一种与语言无关的选项。 而这正是我们的一组功能所针对的。 让我们签入俄语文本(也是PDF文本的一部分):


俄文原文
 ru_text = """       -       (. 1.10),    ,   - .       ,      , -   .       ,       .          : 1.        ,       -  (   ,   . 1.10,    ). 2.    ( )           ,     .      ,     .""" corrected = pdf_lines_gluer._preprocess_pdf(ru_text, clf, v) print(corrected) 

收到:


恢复俄语文本

支持向量法旨在通过搜索将两个属于不同类别的点集分开的良好决策边界(图1.10)来解决分类问题。 决定性边界可以是将训练数据的样本分为两个类别的空间的线或面。 要对新点进行分类,仅检查它们在边界的哪一侧就足够了。
搜索向量方法分两个阶段搜索此类边界:
1.数据映射到一个更高维度的新空间,在该空间中边界可以表示为一个超平面(如果数据是二维的,如图1.10所示,该超平面会退化为一条线)。
2.通过最大化从超平面到每个类别的最近点的距离来计算一个好的决策边界(划分超平面),此步骤称为最大化间隙。 这使我们能够归纳不属于训练数据集的新样本的分类。


这里的一切都很完美。


使用方法(代码生成)


最初,我有一个计划来制作可以使用PIP交付的软件包,但是后来我想到了一种更简单的方法(对我来说)。 事实证明,这组功能不是很大,逻辑回归本身和DictVectorizer具有简单的结构:


  • 对于DictVectorizer,保存特征名称和vocabulary_字段就足够了
  • LogisticRegression具有coef ,类 ,intercept_

因此,代码生成产生了另一个选择(在笔记本电脑中,它位于“序列化为代码”部分):


  1. 我们阅读了pdf_lines_gluer.py文件,其中包含用于使用训练有素的分类器矢量化和还原文本的辅助代码。
  2. 在源代码中指定为“#inject code here#”的位置,我们插入在训练后进入笔记本电脑的状态下初始化DictVectorizer和LogisticRegression的代码。 我们还在这里注入唯一的公共(对于Python尽可能)preprocess_pdf函数:
     def preprocess_pdf(text: str) -> str: return _preprocess_pdf(text, _clf, _v) 
  3. 生成的代码被写入pdf_preprocessor.py文件

正是这个生成的pdf_preprocessor.py文件包含了我们所需的一切。 要使用它,只需将这个文件放到您的项目中即可。 用法:


 from pdf_preprocessor import preprocess_pdf ... print(preprocess_pdf(text)) 

如果您对某些文本有任何疑问,则需要执行以下操作:


  1. 将您的文本放在语料库文件夹中,为它们添加注释。
  2. 启动您的笔记本电脑https://github.com/serge-sotnyk/pdf-lines-gluer/blob/master/pdf_gluer.ipynb-在当前文本上,我花了不到5秒的时间。
  3. 获取并测试pdf_preprocessor.py文件的新版本

也许会出问题并且质量不能令您满意。 然后,情况会有些复杂-您将需要添加新功能,直到找到正确的组合。


C#和ML.NET


在我们公司中,大多数后端代码都基于.Net。 当然,在这里与Python交互会增加不便。 我想在C#中有一个类似的解决方案。 我一直在关注ML.NET框架的开发。 去年,我做了一些小尝试,但由于对不同案例的报道不足,文档量少以及API不稳定,它们令我感到失望。 从今年春天开始,该框架已切换到发布状态,我决定再次尝试。 而且,关于车身布局的最繁琐的工作已经完成。


乍一看,该框架增加了便利。 我开始更多地找到必要的文档(尽管与sklearn的质量和数量相距甚远)。 但最重要的是-一年前,我仍然不了解sklearn。 现在,我开始看到ML.NET中的许多事情都试图在图像和相似性上做(鉴于平台的不同,尽可能做到)。 这些类比使得在实践中更容易学习ML.NET的原理。


可以在https://github.com/serge-sotnyk/pdf-postprocess.cs上查看此平台上的工作项目。


一般原则保持不变-在语料库文件夹中放置带注释(但并非如此)的文档。 启动ModelCreator项目之后,在corpus文件夹旁边,我们将看到models文件夹,其中将放置经过训练的模型的档案。 这仍然是具有相同功能的相同逻辑回归。


但是在这里,我不再涉猎代码生成了。 要使用经过训练的模型,请采用PdfPostprocessor项目(在内部将PdfPostprocessModel.zip模型编译为资源)。 之后,可以使用模型,如最小示例所示: https : //github.com/serge-sotnyk/pdf-postprocess.cs/blob/master/MinimalUsageExample/Program.cs


 using PdfPostprocessor; ... static void Main(string[] args) { var postprocessor = new Postprocessor(); Console.WriteLine(); Console.WriteLine("Restored paragraphs in the English text:"); Console.WriteLine(postprocessor.RestoreText(EnText)); Console.WriteLine(); Console.WriteLine("Restored paragraphs in the Russian text:"); Console.WriteLine(postprocessor.RestoreText(RuText)); } 

将模型从models文件夹复制到PdfPostprocessor项目时,是手动执行的-对我来说,更好地控制将哪个模型放入最终项目更加方便。


有nuget软件包-PdfPostprocessor。 要使用您训练的包和模型,请使用重载的Postprocessor构造函数。


比较Python和C#中的选项


尽管从两个平台上的开发经验中脱颖而出,但简短地讲述一下它们可能是有意义的。 我长期以来一直不是特定平台的好战支持者,并且同情各种信仰的信徒的感受。 您还需要了解,我一生中大部分时间仍在使用静态类型的语言,因此它们离我有点近。


切换到C#时我不喜欢的东西


  • 详细。 不过,Python代码更加紧凑。 这是缺少运算符括号,以及if,for之后的括号。 缺乏无尽的新事物。 主动使用字段,因为如果需要,它们很容易变成属性。 即使使用Python的隐私(实际上在标识符的开头用下划线表示)这一事实,您也已经习惯了,实际上,与其他语言中的一堆隐私修饰符相比,它确实非常方便,方便。 结构的简洁性加快了开发速度,并简化了代码的读取。
  • 在大多数情况下,Python代码看起来更简洁,更优雅(这只是主观的)。 这使得它更易于阅读和维护。
  • 对于Python,几乎所有东西都在某种程序包中包含某种函数或装饰器,但在C#中必须添加很多。 这进一步使代码具有各种辅助函数,类。 而且还需要更多时间。
  • C#及其框架的文档化程度明显低于Python生态系统。
  • 与杂食性sklearn相比,ML.NET的键入更为严格,这也迫使我们花一些时间寻找正确的转换,而上一段对解决这个问题没有帮助。

切换到C#时您喜欢什么


  • 可靠的感觉。 杂食性Python并非经常出现,但经常出现,这使我遇到了难以捉摸的问题。 现在,将代码移植到C#时,出现了一个错误,使某些功能无法使用。 校正后,准确性提高了几个百分点。
  • 速度 在Python代码中,我不得不放弃与先前报价中做出胶粘决策相关的功能-如果您一次向分类器提交提案,则总体速度将低于基板。 为了使Python中的数据处理速度更快,有必要对向量进行尽可能的矢量化处理,有时它使我们放弃潜在的有用选项,或者使它们变得非常困难。
  • Linq。 它们比Python中的列表理解(LC)方便得多。 即使是一个带有for的LC,也迫使我先写完之后的内容,然后回到开头并追加,然后才在LC的开头编写一个表达式。 我认为,仅仅是这样-记录的来源,项目以及要转换的内容。 LINQ ( "" ) . LC ( for) . , , .
  • Lambda. , . , C# .

— . , .Net , . - — REST C#.


C# . — , - . Microsoft Kotlin — .Net , . Python- — , Julia . .


结论


:


  • , — , , - . , , - .
  • . , ML.NET - . .
  • , Python- .Net. , .

Source: https://habr.com/ru/post/zh-CN457072/


All Articles