作为我正在开展的大型个人项目的一部分,我试图将内联日期与各种文本来源分开。
例如,我有一个很大的字符串列表(通常采用英语句子或语句的形式),有多种形式:
中央设计委员会会议周二10/22下午6:30
Th 9/19 LAB:串行编码(第2.2节)
对于那些今天无法成功的人,将在12月15日再举行一次。
练习册3(最低工资):截止于9月18日星期三下午11:59
他将于9月15日飞行。
虽然这些日期与自然文本一致,但它们都不是特定的自然语言形式(例如,没有"会议将从明天开始两周后#34; -it& #39;全部明确)。
作为一个对这种处理没有太多经验的人,最好的开始是什么?我已经查看了dateutil.parser
模块和parsedatetime之类的内容,但之后已经隔离了日期。
因此,有没有什么好方法可以提取日期和无关文本
input: Th 9/19 LAB: Serial encoding (Section 2.2)
output: ['Th 9/19', 'LAB: Serial encoding (Section 2.2)']
或类似的东西?看起来这种处理是由Gmail和Apple Mail等应用程序完成的,但是可以用Python实现吗?
答案 0 :(得分:22)
我也在寻找解决方案而且找不到任何解决方案,所以我和朋友建立了一个工具来做到这一点。我以为我会回来分享其他人认为它有用。
答案 1 :(得分:7)
如果您可以识别实际包含日期信息的段,则使用parsedatetime解析它们可能相当简单。有一些事情需要考虑,即你的日期没有多年,你应该选择一个地区。
>>> import parsedatetime
>>> p = parsedatetime.Calendar()
>>> p.parse("December 15th")
((2013, 12, 15, 0, 13, 30, 4, 319, 0), 1)
>>> p.parse("9/18 11:59 pm")
((2014, 9, 18, 23, 59, 0, 4, 319, 0), 3)
>>> # It chooses 2014 since that's the *next* occurence of 9/18
当你有无关的文字时,它并不总是完美无缺。
>>> p.parse("9/19 LAB: Serial encoding")
((2014, 9, 19, 0, 15, 30, 4, 319, 0), 1)
>>> p.parse("9/19 LAB: Serial encoding (Section 2.2)")
((2014, 2, 2, 0, 15, 32, 4, 319, 0), 1)
老实说,这似乎是一种简单到足以解析特定格式并从每个句子中挑出最可能的问题。除此之外,这将是一个体面的机器学习问题。
答案 2 :(得分:2)
令我惊讶的是,没有提到SUTime和dateparser's search_dates方法。
from sutime import SUTime
import os
import json
from dateparser.search import search_dates
str1 = "Let's meet sometime next Thursday"
# You'll get more information about these jar files from SUTime's github page
jar_files = os.path.join(os.path.dirname(__file__), 'jars')
sutime = SUTime(jars=jar_files, mark_time_ranges=True)
print(json.dumps(sutime.parse(str1), sort_keys=True, indent=4))
"""output:
[
{
"end": 33,
"start": 20,
"text": "next Thursday",
"type": "DATE",
"value": "2018-10-11"
}
]
"""
print(search_dates(str1))
#output:
#[('Thursday', datetime.datetime(2018, 9, 27, 0, 0))]
尽管我尝试了其他模块,如dateutil,datefinder和natty(无法让小鸭使用python),但这两个模块似乎给出了最有希望的结果。
SUTime的结果更可靠,从上面的代码片段可以清楚地看出。但是,SUTime在某些基本情况下会失败,例如解析文本
“我要等到9/19才能上班”
或
“在9月18日至9月20日之间,我将没有空。
第一个文本不给出结果,第二个文本仅给出月份和年份。 但是,在search_dates方法中可以很好地处理此问题。 search_dates方法更具攻击性,将提供与输入文本中任何单词相关的所有可能日期。
我还没有找到一种方法来严格按照search_methods中的日期来解析文本。如果我能找到解决方法,那将是我在SUTime上的第一选择,并且如果找到它,我还将确保更新此答案。
答案 3 :(得分:1)
嗨,我不确定下面的方法是机器学习,但你可以尝试一下:
使用分隔符空格提取所有标记,并且应该得到如下内容:
['Th','Wednesday','9:34pm','7:34','pm','am','9/18','9/','/18', '19','12']
使用规则集来处理它们,例如从工作日和/或构成时间的组件的变体中存在并标记它们,例如'%d:%dpm','%d am','%d /%d','%d /%d'等可能意味着时间。 注意它可以具有例如组合物。 “12/31”是3格('12','/','31')应该是一个感兴趣的标记“12/31”。
“看”标记代码周围有什么标记,如“9:45 pm”,例如('Th','9/19','9:45 pm')是由“有趣”标记组成的3gram并应用规则关于它可能决定意义。
用于更具体分析的过程,例如,如果具有31/12,则31> 12表示d / m,或反之,但如果有12/12 m,d仅在文本和/或外部的上下文构建中可用。
干杯
答案 4 :(得分:1)
import datefinder
string_with_dates = """
entries are due by January 4th, 2017 at 8:00pm
created 01/15/2005 by ACME Inc. and associates.
"""
matches = datefinder.find_dates(string_with_dates)
for match in matches:
print match
答案 5 :(得分:1)
您可以将dateutil module的parse
方法与fuzzy
选项一起使用。
>>> from dateutil.parser import parse
>>> parse("Central design committee session Tuesday 10/22 6:30 pm", fuzzy=True)
datetime.datetime(2018, 10, 22, 18, 30)
>>> parse("There will be another one on December 15th for those who are unable to make it today.", fuzzy=True)
datetime.datetime(2018, 12, 15, 0, 0)
>>> parse("Workbook 3 (Minimum Wage): due Wednesday 9/18 11:59pm", fuzzy=True)
datetime.datetime(2018, 3, 9, 23, 59)
>>> parse("He will be flying in Sept. 15th.", fuzzy=True)
datetime.datetime(2018, 9, 15, 0, 0)
>>> parse("Th 9/19 LAB: Serial encoding (Section 2.2)", fuzzy=True)
datetime.datetime(2002, 9, 19, 0, 0)
答案 6 :(得分:0)
parsedatetime
lib的较新版本提供搜索功能。
示例
from dateparser.search import search_dates
dates = search_dates('Central design committee session Tuesday 10/22 6:30 pm')
答案 7 :(得分:0)
没有任何完美的解决方案。 IT 完全取决于您想使用哪种类型的数据。通过手动浏览某些数据集来快速查看和分析数据,并准备正则表达式模式并测试它是否有效。
预定义的所有包在一定程度上解决了日期提取问题,并且是有限的。如果通过查看数据大致找出模式,则用户可以准备正则表达式。这将帮助他们防止对包中编写的所有规则进行迭代和循环。