LibPostal是使用统计NLP和开放数据在世界范围内解析/归一化街道地址的C库。该项目的目的是了解各种语言的基于位置的字符串。有关LibPostal背后研究的更全面概述,请务必查看(冗长)介绍性博客文章:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
地址及其代表的位置对于任何处理地图的应用程序(位置搜索,运输,按需/送货服务,签到,评论)至关重要。然而,即使是最简单的地址也充满了当地惯例,缩写和上下文,因此很难用传统的全文搜索引擎有效地索引/查询。该库有助于将人类使用的自由形式地址转换为适合机器比较和全文索引的清洁归一化形式。尽管LibPostal本身并不是完整的地理编码器,但它可以用作预处理步骤,以使任何地理编码应用程序更聪明,更简单,更一致。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
核心库用纯C编写。语言绑定为Python,Ruby,Go,Java,PHP和Nodejs正式支持,并且很容易用其他语言编写绑定。
如果您的公司正在使用LibPostal,请考虑要求您的组织赞助该项目。解释人类在提到地点时的含义远非解决问题,并且赞助可以帮助我们在地理空间NLP中追求新的边界。作为赞助商,您的公司徽标将出现在GitHub回购页面上,以及指向您网站的链接。赞助信息
单个用户还可以通过每月捐款来帮助支持开放的GEO NLP研究:
在安装之前,请确保有以下先决条件:
在Ubuntu/Debian上
sudo apt-get install curl autoconf automake libtool pkg-config
在Centos/Rhel上
sudo yum install curl autoconf automake libtool pkgconfig
在Mac OSX上
brew install curl autoconf automake libtool pkg-config
然后安装C库:
如果您使用的是M1 Mac,则将--disable-sse2添加到./configure命令。这将导致性能较差,但构建将成功。
git clone https://github.com/openvenues/libpostal
cd libpostal
./bootstrap.sh
./configure --datadir=[...some dir with a few GB of space...]
make -j4
sudo make install
# On Linux it's probably a good idea to run
sudo ldconfig
LibPostal对PKG-Config有支持,因此您可以使用PKG-Config打印将您的程序链接到它的标志:
pkg-config --cflags libpostal # print compiler flags
pkg-config --libs libpostal # print linker flags
pkg-config --cflags --libs libpostal # print both
例如,如果您编写一个名为app.c的程序,则可以这样编译:
gcc app.c `pkg-config --cflags --libs libpostal`
msys2/mingw
对于Windows,构建过程当前需要MSYS2和MINGW。可以从http://msys2.org下载。请按照MSYS2网站上的说明进行安装。
请通过运行确保MSYS2是最新的:
pacman -Syu
安装以下先决条件:
pacman -S autoconf automake curl git make libtool gcc mingw-w64-x86_64-gcc
然后构建C库:
git clone https://github.com/openvenues/libpostal
cd libpostal
cp -rf windows/* ./
./bootstrap.sh
./configure --datadir=[...some dir with a few GB of space...]
make -j4
make install
注意:设置datadir时, C:驱动器将作为/c输入。 libpostal构建脚本会在路径末端自动添加libpostal ,因此'/c'将变成C:libpostal 。
编译的.dll将在src/.libs/ Directory中,应称为libpostal-1.dll 。
如果您需要.lib导入库将其链接到您的应用程序。您可以使用Visual Studio lib.exe工具和libpostal.def定义文件生成一个:
lib.exe /def:libpostal.def /out:libpostal.lib /machine:x64
可用于libpostal的替代数据模型。它是由Senzing Inc.创建的,用于改善对美国,英国和新加坡地址的解析,并改善了美国农村路线地址处理。要启用此添加MODEL=senzing :
./configure --datadir=[...some dir with a few GB of space...] MODEL=senzing
该模型的数据来自OpenAddress,OpenStreetMap和由客户反馈(几百个记录)生成的数据,总计约有230个国家 /地区的数据记录,使用100多种语言。来自OpenStreetMap和OpenAddress的数据很好,但不是完美的,因此通过过滤不良形成的地址来修改数据集,纠正错误分类的地址令牌和删除不属于地址的代币,每当遇到这些条件时。
Senzing创建了来自89个国家 /地区的12950个地址的数据集,用于测试和验证其模型的质量。数据集使用来自OSM的随机地址生成,每个国家 /地区最少50。从Senzing支持团队和客户以及LibPostal Github页面上获得了难以实现的地址,并将其添加到该集合中。使用此测试集,Senzing模型比默认模型获得了4.3%的解析结果。
该模型的大小约为2.2GB,默认模型为1.8GB,因此请记住,如果Storages空间很重要。
有关此数据模型的更多信息,请访问以下网址:https://github.com/senzing/libpostal-data,如果您遇到此模型的任何问题,无论它们是否与Parses,安装或任何其他问题有关
Libpostal的国际地址解析器使用机器学习(有条件的随机字段),并接受了地球上每个居住国家的10亿个地址的培训。我们将OpenStreetMap和OpenAddresses用作结构化地址的来源,以及OpenCage地址格式模板,网址为:https://github.com/opencagedata/addressata/address-formatting来构建培训数据,补充包含多边形的多边形,并产生了多边形组件,并产生了公寓/地面/地板/地板盒和PO盒。我们还添加了缩写,随机掉出组件等,以使解析器尽可能稳健,以使现实世界中的输入尽可能强。
这些示例解析结果取自Interactive address_parser程序,该程序在运行时用libpostal make 。请注意,解析器可以处理逗号与无逗号以及各种套管和组件的排列(如果输入是仅仅是城市或城市/邮政编码)。
解析器在持有数据方面达到了很高的精度,目前为99.45%的正确解析(这意味着分子中的1个以使每个令牌在地址中正确正确)。
这是使用Python绑定的解析器API的示例:
from postal . parser import parse_address
parse_address ( 'The Book Club 100-106 Leonard St Shoreditch London EC2A 4RH, United Kingdom' )以及C API的一个例子:
#include <stdio.h>
#include <stdlib.h>
#include <libpostal/libpostal.h>
int main ( int argc , char * * argv ) {
// Setup (only called once at the beginning of your program)
if (! libpostal_setup () || ! libpostal_setup_parser ()) {
exit ( EXIT_FAILURE );
}
libpostal_address_parser_options_t options = libpostal_get_address_parser_default_options ();
libpostal_address_parser_response_t * parsed = libpostal_parse_address ( "781 Franklin Ave Crown Heights Brooklyn NYC NY 11216 USA" , options );
for ( size_t i = 0 ; i < parsed -> num_components ; i ++ ) {
printf ( "%s: %sn" , parsed -> labels [ i ], parsed -> components [ i ]);
}
// Free parse result
libpostal_address_parser_response_destroy ( parsed );
// Teardown (only called once at the end of your program)
libpostal_teardown ();
libpostal_teardown_parser ();
}地址解析器可以从技术上使用培训数据中定义的任何字符串标签,但是根据Opencage的地址构造库中定义的字段,这些字符标签以及当前定义的标签,以及LibPostal添加的一些字段来处理特定模式:
Expand_Address API将混乱的现实世界地址转换为适合搜索索引,哈希等的归一化等效物。
这是使用Python绑定的交互式示例:
libpostal包含一个受OSM训练的语言分类器,以检测给定地址中使用了哪些语言,因此可以应用适当的正常化。唯一需要的输入是原始地址字符串。这是各种语言中一些较不直接的正常化的简短列表。
| 输入 | 输出(可能在libpostal中是多重的) |
|---|---|
| 一百二十E 96街 | 东96街120号 |
| c/ ocho,pi 4 | Calle 8Polígono工业4 |
| v xx settembre,20 | 通过20 settembre 20 |
| Quatre vingt duze R. del'église | 92 Rue de l eglise |
| 启,4,strimа | 当函 |
| 启,4,strimа | Ulitsa Karetnyy Ryad Dom 4 Stroyeniye 7 |
| Marktstraße14 | Markt Strasse 14 |
libpostal当前支持60多种语言的这些类型的正常化,您可以添加更多(而无需编写任何C)。
有关进一步的阅读和一些奇异的地址边缘案例,请参见:虚假的程序员相信地址。
这是使用Python绑定以简洁的示例(大多数高级语言绑定都是相似的):
from postal . expand import expand_address
expansions = expand_address ( 'Quatre-vingt-douze Ave des Champs-Élysées' )
assert '92 avenue des champs-elysees' in set ( expansions )c API等效是更多的行,但仍然相当简单:
#include <stdio.h>
#include <stdlib.h>
#include <libpostal/libpostal.h>
int main ( int argc , char * * argv ) {
// Setup (only called once at the beginning of your program)
if (! libpostal_setup () || ! libpostal_setup_language_classifier ()) {
exit ( EXIT_FAILURE );
}
size_t num_expansions ;
libpostal_normalize_options_t options = libpostal_get_default_options ();
char * * expansions = libpostal_expand_address ( "Quatre-vingt-douze Ave des Champs-Élysées" , options , & num_expansions );
for ( size_t i = 0 ; i < num_expansions ; i ++ ) {
printf ( "%sn" , expansions [ i ]);
}
// Free expansions
libpostal_expansion_array_destroy ( expansions , num_expansions );
// Teardown (only called once at the end of your program)
libpostal_teardown ();
libpostal_teardown_language_classifier ();
}构建Libpostal之后:
cd src/
./libpostal "Quatre vingt douze Ave des Champs-Élysées"
如果您有一个文本文件或流式的每行地址,则命令行接口还接受stdin的输入:
cat some_file | ./libpostal --json
构建Libpostal之后:
cd src/
./address_parser
address_parser是一个交互式外壳。只需键入地址,libpostal将解析它们并打印结果。
LibPostal设计为高级语言使用。如果您看不到自己选择的语言,或者您正在写一种语言绑定,请告诉我们!
正式支持的语言绑定
非正式语言绑定
数据库扩展
非正式的REST API
libpostal休息码头
Libpostal Zeromq Docker
Libpostal用于自动测试最大。要运行测试,请使用:
make check
即使您的C生锈/不存在,添加测试用例也很容易,我们也很喜欢贡献。我们主要使用功能测试来检查字符串输出的字符串输入。
Libpostal还会定期通过OSM(清洁)的数百万个地址以及生产地理编码器(不那么干净)的匿名查询进行战斗测试。在此过程中,我们使用Valgrind检查内存泄漏和其他错误。
LibPostal需要从S3下载一些数据文件。基本文件是执行扩展所需的数据结构的盘表示。对于地址解析,由于模型培训需要几天,因此我们将经过全面训练的模型发布到S3,并随着新地址被添加到OSM,OpenAddresses等,将自动更新它。语言分类器模型也是如此。
运行时,数据文件将自动下载。要检查并下载任何新数据文件,您可以make或运行:
libpostal_data download all $YOUR_DATA_DIR/libpostal
并将$ your_data_dir替换为您在安装过程中进行配置的任何内容。
libpostal包含许多影响扩展,语言分类器和解析器的每语言词典。要探索词典或用您的语言撰写缩写/短语,请参阅资源/词典。
在机器学习中,大量培训数据通常对于获得良好的结果至关重要。许多开源机器学习项目仅发布模型代码(当且仅当您是Google时才可重复的结果),或者在训练条件未知的情况下进行烘焙的模型。
libpostal有些不同,因为它经过了每个人都可以使用的开放数据培训,因此我们发布了整个培训管道(此存储库中的Geodata软件包),以及Internet存档上产生的培训数据本身。超过100GB解压缩。
培训数据存储在Archive.org上,到创建日期。此存储库的主目录中还存储了一个名为current_parser_training_set的文件,该文件存储了最近创建的培训集的日期。要始终指向最新数据,请尝试以下内容: latest=$(cat current_parser_training_set) ,然后使用该变量代替日期。
所有文件均可在https://archive.org/download/libpostal-parser-training-data-yyymmdd/quil as Gzip'd tab-separated值(TSV)文件(如: languagetcountrytaddress 。
如果解析器的性能不如您在特定类型的地址上所希望的,那么最好的追索方法是使用GREP/AWK查看培训数据,并尝试确定是否存在某些未捕获的模式/地址。
缩写扩展:例如扩展“ RD” =>“道路”,但几乎用于任何语言。 LibPostal支持> 50种语言,并且添加新语言或扩展当前字典很容易。意识形态语言(不被白色空格分开,例如中文),以及将通道类型串联到弦末端的日耳曼语言,并且可以选择分开,因此Rosenstraße和RosenStraße等效。
国际地址解析:有条件的随机场,将“ 123 Main Street New York New York”解析为{“ House_number”:123,“ Road”:“ Main Street”,“ City”,“ City”:“ New York”,“ State”,“ State”:“ New York”}。解析器适用于各种各样的国家和语言,而不仅仅是我们/英语。该模型经过超过10亿个地址和地址式字符串的培训,使用“ Opencage地址格式格式”存储库中的模板,为世界上每个居民的国家构建格式化的,标记为格式的,标记的传输示例。进行了许多类型的规范化,以使训练数据尽可能接近真正的混乱地理编码器输入。
语言分类:经过训练的多项式逻辑回归(使用ftrl-proximal方法来诱导稀疏性)在所有openstreetmap方法上,addr:* tag,toponyms和格式化地址。标签是使用OSM国家/地区的Point-in-Polygon测试来得出的,分别针对国家/地区和Admin 1边界来得出标签。因此,例如,西班牙语是西班牙的默认语言,但在不同地区,例如加泰罗尼亚,加利西亚,巴斯克地区,各自的区域语言是默认的。在区域语言是非默认的情况下,例如威尔士,布雷顿,Occitan的情况下,采用了基于字典的歧义。词典还用于缩写规范短语,例如“ calle” =>“ c/”(在语言分类器和地址分析器培训集上执行)
数字表达式解析(“二十一个” => 21st,“ quatre-wvingt-douze” => 92,再次使用CLDR中提供的数据)支持> 30种语言。处理具有串联表达式的语言,例如milleottocento => 1800。可选地将罗马数字归一化,无论语言如何(ix => 9),这些语言以许多君主,教皇和。
快速,准确的令牌化 / Lexing :以> 1M令牌 /秒为单位,以UTF8单词分割的形式实现TR-29规格,将East Asian语言以字符而不是在WhiteSpace上为单位。
UTF8归一化:可选地将UTF8分解为NFD归一化形式,条纹标记标记为a和/或应用拉丁语ASCII音译。
音译:例如μ=> ulica或ulitsa。使用所有CLDR变换,尽管LibPostal不需要拉动所有ICU(可能与您的系统版本冲突),但使用ICU使用的完全相同的源数据。注意:某些语言,尤其是希伯来语,阿拉伯语和泰语可能不包含元音,因此通常不符合人类所做的音译。可以为其中一些语言实施统计音译者。
脚本检测:检测给定字符串使用的脚本(可以是多个脚本,例如自由形式的香港或澳门地址可以在同一地址中同时使用Han和Latin脚本)。在音译中,我们可以为给定的Unicode脚本使用所有适用的音译器(例如,可以用希腊 - 拉丁,希腊 - 拉汀-BGN和希腊语 - 拉丁蛋白 - ungegn来译)。
LibPostal最初是作为开放式项目的一部分而创建的,以解决场地缩减问题。在OpenVenues中,我们有一个数据集的数据集,这些数据集源自来自Common Crawl的网页的trabytes。共同的爬网每月发表,因此即使合并了两个爬网的结果也会产生重要的重复。
辩论是一个相对良好的领域,对于诸如网页,学术论文等的文本文档。存在相当不错的近似相似性方法,例如Minhash。
但是,对于物理地址,经常使用常规缩写,例如Road == RD,California == CA或纽约市== NYC会使事情变得有些复杂。即使使用Minhash之类的技术,该技术非常适合大约匹配,并且相当于Jaccard两组的相似性,我们也必须使用非常简短的文本,通常情况下,两个等效的地址(一个缩写和一个完全指定)在N-gram集合中的非常紧密的匹配。在非拉丁文脚本中,说俄罗斯的地址及其相当的音译相当,可以想象的两个地址指的是同一地点,即使是一个角色也可能不匹配。
作为一个激励人物的例子,请考虑以下两种同等的方式,以不同的惯例和详细的详细说法来编写特定的曼哈顿街道地址:
显然,'30 W 26th st fl#7!= '30西二十六街7'从字符串比较意义上,但是人类可以抓住这两个地址指的是相同的物理位置。
LibPostal旨在创建分解为组件的归一化地理字符串,以便我们可以更有效地理解两个地址如何真正匹配并做出有关DUPES的自动化服务器端决策。
如果以上听起来很像地理编码,那是因为它在某种程度上,仅在OpenVenues情况下,我们必须在没有UI或用户的情况下进行地理位置,以在自动完整的下拉列表中选择正确的地址。给定一个源地址的数据库,例如OpenAddresses或OpenStreetMap(或以上所有内容),可以使用LibPostal在MapReduce或流中心处理等设置中实现地址删除和服务器端批次地理编码等内容。
现在,使用巨型同义词文件,脚本,自定义分析仪,象征器等,而不是试图将特定于地址的约定烘烤到传统文档搜索引擎中,而是看起来像这样:
这样,libpostal可以相对于数据集的大小执行恒定时间的模糊地址匹配。
libpostal用C撰写的三个原因(根据重要性顺序):
可移植性/无处不在:LibPostal的目标是人们实际使用的日常使用的高级语言:Python,Go,Ruby,Nodejs等。C的优点在于,几乎任何编程语言都可以绑定到它,并且C与其无处不在,因此,您可以在应用程序中直接使用libostal,而无需使用libpostal,而无需单独使用libostal。我们支持MAC/Linux(Windows不是优先事项,但乐于接受补丁),具有标准的自动工具构建和用于数据文件的Endian-nessness-grognostic文件格式。 Python绑定是作为此存储库的一部分维护的,因为它们需要构建培训数据。
内存效率:libpostal旨在在MAPREDUCE设置中运行,根据机器配置,我们可能仅限于每个过程的RAM <1GB。尽可能多地使用连续的数组,尝试(建立在连续数组),Bloom过滤器和压缩的稀疏矩阵来保持内存使用量较低。可以在移动设备上使用Libpostal,该设备具有在一个国家或少数国家 /地区接受培训的模型。
性能:这是列表中的最后一个原因。 LibPostal中的大多数优化用于内存使用而不是性能。考虑到它的工作量,Libpostal非常快。它可以在我们测试的平台上的单个线程 /过程中处理10-30k地址 /秒(这意味着在一个多小时内处理OSM Planet中的每个地址)。查看简单的基准计划,以测试您的环境和各种输入。在MAPREDUCE设置中,每核性能并不重要,因为一切都在并行完成,但是在Mapzen上有一些流式摄入应用程序,需要在其中运行进程。
Libpostal用现代,清晰的C99编写,并使用以下惯例:
LibPostal Repo中的Geodata Python软件包包含用于预处理各种GEO数据集和构建C模型使用的培训数据的管道。对于大多数用户而言,不需要此软件包,而是对于那些有兴趣生成新类型地址或改善Libpostal的培训数据的人,这是可以寻找的地方。
在持有的测试数据(这意味着模型以前从未见过的标签)时,地址解析器可实现99.45%的完整分析精度。
对于某些任务(例如命名实体识别),最好使用诸如F1分数或变体之类的东西,主要是因为存在类偏见问题(大多数单词是非实体,并且一个简单地预测每个标记的非实体的系统实际上在准确性方面都可以很好地做得很好)。地址解析并非如此。每个令牌都有一个标签,并且在培训数据中都有数百万个班级的示例,因此,准确性是可取的,因为它是一种干净,简单和直观的性能度量。
在这里,我们使用完整的解析精度,这意味着我们只会在分子中获得一个“点”,如果地址中的每个令牌都可以正确。这应该是一个更好的措施,而不是简单地看每个令牌是否正确。
尽管当前的解析器在大多数标准地址方面都可以很好地工作,但仍有改进的余地,尤其是在确保我们使用的培训数据尽可能接近地解决野外。地址解析器可以进一步改进两种主要方法(按困难顺序):
欢迎错误报告,问题和拉动请求。在提交问题,错误报告或提取请求之前,请阅读贡献指南。
提交问题:https://github.com/openvenues/libpostal/issues。
特别感谢 @benk10的初始Windows Build和@aeroxuk,将其无缝集成到项目中并设置Appveyor构建。
该软件可根据MIT许可条款作为开源。