监控大量信息体中的案例处理过程[]

13

我目前正在处理一份非常大的文本数据(一个文件中有约290MB的纯文本数据)。在将其导入Mathematica 8后,我目前开始对其进行操作,将其分解为小写单词等,以便开始文本分析。

问题是这些过程需要很长时间。是否有一种方法可以通过Mathematica监控这些操作?对于具有变量的操作,我使用了ProgressIndicator等。但这是不同的。我在文档和StackOverflow上的搜索没有找到类似的内容。

接下来,我想监视Cases[]命令的处理过程:

input=Import["/users/USER/alltext.txt"];
wordList=Cases[StringSplit[ToLowerCase[input],Except[WordCharacter]],Except[""]];

我想知道你的问题是关于监控Cases[]进度还是优化你的代码。它们是两个完全不同的问题。 - Dr. belisarius
@belisarius 差不多,但并非完全如此。我从回复中了解到,我需要/请求监视Cases[]源于代码中一些较慢的选择。另外,也许没有明显的方法来监视这样的进展... - canadian_scholar
4个回答

11

类似StringCases[ToLowerCase[input], WordCharacter..]这样的方法似乎会更快一些。 我可能会使用DeleteCases[expr, ""]而不是Cases[expr, Except[""]]


10

通过将“counter”操作注入到正在匹配的模式中,可以查看StringSplitCases操作的进度。以下代码临时显示两个进度条:第一个进度条显示StringSplit处理的字符数,第二个进度条显示Cases处理的单词数:

input = ExampleData[{"Text", "PrideAndPrejudice"}];

wordList =
  Module[{charCount = 0, wordCount = 0, allWords}
  , PrintTemporary[
      Row[
        { "Characters: "
        , ProgressIndicator[Dynamic[charCount], {0, StringLength@input}]
        }]]

  ; allWords = StringSplit[
        ToLowerCase[input]
      , (_ /; (++charCount; False)) | Except[WordCharacter]
      ]

  ; PrintTemporary[
      Row[
        { "Words:      "
        , ProgressIndicator[Dynamic[wordCount], {0, Length@allWords}]
        }]]

  ; Cases[allWords, (_ /; (++wordCount; False)) | Except[""]]

  ]

这种技术的关键在于,在两种情况下使用的模式都与通配符_匹配。然而,该通配符受到一个条件的保护,该条件总是失败的,但在副作用下递增一个计数器。然后会处理“真正”的匹配条件作为备选项。


1
+1 只要注意,在我的机器上,这比相同的未监视代码慢7倍。 - Dr. belisarius
非常聪明!+1。你可以简单地使用Except[WordCharacter]/;(++charCount;True)Except[""] /; (++wordCount; True)代替(_ /; (++charCount; False)) | Except[WordCharacter](_ /; (++wordCount; False)) | Except[""],并且具有相同的成功率但更高的效率。正如Joshua Martell所指出的那样,在处理大量信息时,使用DeleteCases而不是Cases可能会带来更多的加速。 - Alexey Popkov
1
@Alexey 那是我一开始尝试的方法,但它没有计算所有字符和单词 - 只有与模式匹配的那些。 - WReach
附加说明:使用 /; NumberQ[++charCount]/; NumberQ[++wordCount] 可以使代码更短,速度更快。 - Alexey Popkov
@WReach 现在我明白你的意思了。有趣。 - Alexey Popkov
太棒了 - 我也来试试看。这是一种非常有趣的方法,具有广泛的应用。 - canadian_scholar

5

这要根据您的文本格式而定,但您可以尝试将文本拆分为若干块进行迭代。然后,您可以使用Monitor 监控迭代器以查看进度。例如,如果您的文本由以换行符结尾的文本行组成,则可以像这样操作:

Module[{list, t = 0},
 list = ReadList["/users/USER/alltext.txt", "String"];
 Monitor[wordlist = 
   Flatten@Table[
     StringCases[ToLowerCase[list[[t]]], WordCharacter ..], 
      {t, Length[list]}], 
  Labeled[ProgressIndicator[t/Length[list]], N@t/Length[list], Right]];
 Print["Ready"]] 

在一个大小约为3 MB的文件上,这比Joshua的建议略微耗费了更多时间。


另一种有广泛应用的有趣方法。我也会实现它并监测其相对速度。 - canadian_scholar

4
我不知道如何使用Cases,但是List处理可能会耗费时间,特别是如果它在生成List时。由于处理表达式中存在未知数量的项,因此Cases可能正在执行该操作。因此,我建议尝试稍微不同的方法:将""替换为Sequence[]。例如,这个List
{"5", "6", "7", Sequence[]}

变成

{"5", "6", "7"}.

所以,请尝试。
bigList /. "" -> Sequence[]

由于不需要从零开始构建一个大的List,因此它应该更快地运行。


这是一个非常好的建议,我会尝试实现它。代码效率是根本问题! - canadian_scholar
3
不用担心Cases中的内部列表生成。它肯定经过了优化以进行列表生成,并且不会出现“AppendTo”综合症(二次方列表生成复杂度)。实际上,它比使用“Sequence”方法更加高效。 - Leonid Shifrin
1
@Leonid,我以前在使用内置函数时遇到过问题,通常涉及列表生成。(不幸的是,我没有具体的例子。)而且,我承认,我没有测试过这个。我只是提供了一个可能的替代方案。 - rcollyer
1
@ian.milligan 真正的效率提升可能在于尽可能避免使用Mathematica的文本操作模式,而是使用字符串模式、正则表达式等。请记住,许多字符串处理函数(如StringCases)也适用于字符串列表,并且非常快速。 - Leonid Shifrin
@rcollyer 当然,多种选择总是好的。我只是想指出Cases并不会受到这种特定缺陷的影响。 - Leonid Shifrin
@Leonid,没问题。我很少使用Cases,我最后一个大数据集是通过SparseArray(80^3数组中大多数为0)缩小的。 - rcollyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接