用于列表识别和解析的算法

时间:2009-11-04 13:26:43

标签: java python list parsing

我的数据在理论上是一个列表,但历史上已被用户输入为自由格式文本字段。现在我需要将列表中的每个项目分开,以便可以分析每个元素。

用户输入的数据的简化示例:

one, two, three, four, five 

one. two. three, four. five.

"I start with one, then do two, maybe three and four then five"

one  
two  
three  
four  
five.  

one, two. three four five

one two three four - five

"not even a list, no list-elements here! but list item separators may appear. grrr"

所以,这或多或少是数据的样子。实际上,列表项可能是几个字长。我需要处理这些列表(其中有数千个),这样我最终得到这样的数组:

array[0] = "one"  
array[1] = "two"  
array[n] = n  

我接受有时候我的算法完全无法解析列表,我不需要100%的成功率,75%会很好。假阳性对我来说是非常昂贵的,所以我宁愿完全拒绝一个列表而不是生成一个不包含真实数据的列表 - 假设一些用户输入无意义的乱码。

我有一些想法,试图找出正在使用哪些分隔符,以及如何定期将数据与内容的大小分开。

我更喜欢Java或Python,但欢迎任何解决方案: - )

9 个答案:

答案 0 :(得分:3)

解决这个问题的第一步是详细分析人类如何解决这个问题。我将问题分解为两部分。

  1. 人类如何区分列表和非列表?例如,是因为非列表是语法英语句子吗?如果是这种情况,您可以使用一种可用的自然语言处理工具包来区分列表和非列表。

  2. 人类如何识别列表中的分隔符和列表元素?例如,由于某些特定的领域知识,他们是否识别列表元素?或者他们只是认出一小组常见的分隔符?列表元素总是单个单词吗?如果不是,在什么情况下它们是多个单词?

  3. 我还要仔细研究几百个样本,看看是否有任何可以轻松识别和解析的COMMON模式。例如,如果30%的条目是简单的逗号分隔列表,那么正则表达式将简单地识别和解析它们。也许一小组正则表达式将解决你的语料库的很大一部分。

    最后,我假设目前数据不仅被人类输入和识别,而且还被人类消费。您是否有理由将项目分解为列表,以便可以将人员从循环中移除,或者只是为了让他们的工作更轻松?如果是后者,我建议为它们提供分解列表元素,并作为备份,提供原始输入的文本。换句话说,如果你弄错了,请对冲你的赌注。

答案 1 :(得分:2)

如果你不能定义你的数据(“这些单词可以是任何东西,我无法事先知道任何单个列表可以包含的字典。它们不仅仅是数字......它可能是一个任何事情的清单“)然后你有严重的问题。

具体而言,如果您无法定义数据,则无法解决您的问题。

您可以尝试使用nltk

您可以放弃“干扰词”(“,”,“。”,“我”,“开始”,“带”,“然后”,“做”等等。)剩下的可能是这个无法确定的“言语可以是任何东西”,这是遗留下来的。

在您可以更好地定义数据之前,您可能注定要付出很多努力。

答案 2 :(得分:1)

我不知道我是否理解你的问题。如果你想在python中从混乱的字符串中提取字母数字字符串,那就是:

>>> import re
>>> re.split('\W+','abaa, asodf ?. poasid - paosfi sec')
['abaa', 'asodf', 'poasid', 'paosfi', 'sec']

或者如果您了解分隔符:

>>> re.split('[,. -]+','abaa, asodf, poasid - paosfi sec')
['abaa', 'asodf', 'poasid', 'paosfi', 'sec']

答案 3 :(得分:1)

而不是关注代码,方法怎么样。根据swillden的说法建立一点......

如果您的列表被人类用户使用,您可以要求他们在您犯错时纠正您(此更正对于输入文本的人或查看文本的后来用户可见)。如果给定的输入看起来很像列表但不足以确定,则向它们显示列表和原始输入并让他们选择。

要自动将输入分类为列表或文本,您可以根据以下内容创建多个指标:

  • 鉴于分隔符(即[' ', '\t', ',', '.', 'and'])这个短语有多少使用?期待一两个。哪些?
  • 输入是否由片段组成(使用某种语法系统) - 片段往往表示列表。
  • 此输入字段(或输入中的上下文)是否具有列表项
  • 列表中的单词(有些单词可能总是表示您域中的句子或列表)

然后,您将此信息传递到贝叶斯过滤器并使用您的用户建议进行训练。我提到的大多数项目会在您将项目传递到过滤器之前将其标记为特殊的“关键字”。如果过滤器有任何一种明确的答案,请将其视为列表或字符串。如果过滤器不确定,请询问用户并使用他们的答案训练过滤器。

修改

您可以通过首先使用现有脚本对列表进行分类然后手动检查来手动训练系统(即不将系统暴露给用户)。获取500个输入的列表,运行过滤器查找或其他简单列表,并将它们分类为列表。训练贝叶斯过滤器(其他所有其他非列表),然后手动检查所有500的输出进一步训练。

每天都有人可以收到当天所有边缘案例的电子邮件,如果有必要,可以通过电子邮件中的链接来纠正系统。

作为一个侧面问题(与OP评论有关),一般来说,贝叶斯过滤器比神经网络更容易实现,调试,测试,分析和扩展。

答案 4 :(得分:0)

在java中,字符串标记生成器会执行此操作(即StringTokenizer(inputString,delimiterList))

StringTokenizer st = new StringTokenizer( "A B|C-D", " |-" );
while ( st.hasMoreTokens() ) {
    System.out.println( st.nextToken() );
}

打印

A

C

d

答案 5 :(得分:0)

以下内容将您的输入字符串“解析”为由非单词字符分隔的“单词”字符序列。

String input = ...
String[] parts = input.split("[^\w]*");

我不知道你如何将名单与胡言乱语区分开来。我想你需要更多地解释一下你的问题域......

编辑:如果你不能定义你(作为一个人)用来区分列表和乱码的规则,那么这个问题基本上是无法解决的。计算机不能做你知道的魔法......

也许您应该只使用该程序来处理“绝对”列表的子集,并手动对其他列表进行分类。

答案 6 :(得分:0)

要么您知道单词词典,要么您有列表分隔符的优先顺序。否则,问题太严重,无法为计算机处理。

我认为你的优先顺序可以是逗号,圆点,连字符,空格。因此,这意味着您可以使用逗号分割,而不是按点分割等等。

或者你可以继续按每个连续的分隔符进行分割,直到你达到一个不在文本中的分隔符。

答案 7 :(得分:0)

我不确定最佳答案是什么,但是如果你需要很少的误报,那么你应该做的是定义一些很可能是列表的模式,并严格拒绝其他所有数据。

patterns = [
    re.compile(r'^\s*(\w+)(\s*,\s*(\w+))*\s*$'), 
    re.compile(r'^\s*(\w+)(\s*\.\s*(\w+))*\s*$'), 
    re.compile(r'^\s*(\w+)(\s*,\s*(\w+))*\s+and\s+(\w+)\s*^$')
]
acceptSet = [ line for line in candidateSet if 
              any(pattern.match(line) for pattern in patterns)] 

答案 8 :(得分:0)

从谷壳中筛出小麦的p p刺戳......

rawdata = """\
one, two, three, four, five
one. two. three, four. five.
"I start with one, then do two, maybe three and four then five"
one  
two  
three  
four  
five.  
one, two. three four five
one two three four - five
"not even a list, no list-elements here! but list item separators may appear. grrr"
a dog with a bone is a beautiful twosome""".splitlines()

from pyparsing import oneOf, WordStart, CharsNotIn, alphas, LineEnd
options = (WordStart() + oneOf("one two three four five") + (CharsNotIn(alphas)|LineEnd()))

for userinput in rawdata:
    print userinput
    print [opt[0] for opt in options.searchString(userinput)]
    print

打印(注意添加的行隐藏的“一个”和“两个”子串,这是不可取的):

one, two, three, four, five
['one', 'two', 'three', 'four', 'five']

one. two. three, four. five.
['one', 'two', 'three', 'four', 'five']

"I start with one, then do two, maybe three and four then five"
['one', 'two', 'three', 'four', 'five']

one  
['one']

two  
['two']

three  
['three']

four  
['four']

five.  
['five']

one, two. three four five
['one', 'two', 'three', 'four', 'five']

one two three four - five
['one', 'two', 'three', 'four', 'five']

"not even a list, no list-elements here! but list item separators may appear. grrr"
[]

a dog with a bone is a beautiful twosome
[]