非英语文本中的单词频率:如何合并单数和复数形式等?

非英语文本中的单词频率:如何合并单数和复数形式等?

我正在排序法语一些文本文件中的语言单词根据频率重点关注洞察力而不是统计显着性。挑战在于保留重音字符并处理文章形式在塑造单词标记以进行排序的上下文中,位于元音 ( l', )前面。d'

主题为最频繁的文件中的单词有多种形状(1|2|3|4)。所以我使用这个函数组合在一起GNU公用事业:

compt1 () {
for i in *.txt; do
    echo "File: $i"
    sed -e 's/ /\
/g' <"$i" | sed -e 's/^[[:alpha:]][[:punct:]]\(.*\)/\1/' | sed -e 's/\(.*\)/\L\1/' | grep -hEo "[[:alnum:]_'-]+" | grep -Fvwf /path_to_stop_words_file | sort | uniq -c | sort -rn 
done
}

...用空间换行;修剪行首的一个字符,后跟标点符号;然后将所有内容转换为小写;使用这种紧凑的grep结构来匹配单词组成字符来创建标记;然后去掉停用词,最后就是通常的排序。这停止文件包含一个带有单独字符的片段,因此你必须小心使用它,但提供的关于如何创建不同语言的单词真的很有趣!

grep -c现在,当我将重要单词的频率与直接在文件上的输出进行比较时,我认为它在一定误差范围内足够接近。


问题:

  • 我如何修改它以合并复数形式与其单数形式的频率,即共享公共前缀和不同的 1 个字符后缀的单词?
  • 我正在尝试评估该grep部分是否会工作与正在发生的事情操作系统X

1.我无法提供源数据,但我可以提供文件为例。的话时间幼儿文中提供了一个例子。前者在文本中出现两次,其中一次为“l'heure”,有助于验证该命令是否有效。后者以单数和复数形式出现(幼儿/幼儿)并会因合并于此而受益。

答案1

您确实无法通过简单的sed脚本来完成此操作。我假设您希望简化为“引文形式”,将所有词形变化折叠为基本形式。

这意味着像这样的形容词门徒、门徒、门徒、门徒全部算作同一件事,基本形容词/分词门徒。同样,动词的所有变形保护者- 喜欢protège, protégeons, protégeais, protégeasse, protégeâmes, protégeront, protégeraient等等——都会简化为基本动词。

这意味着您需要了解语言的屈折形态。更糟糕的是,您需要了解一些有关语言实际语法的知识,包括词形变化和区分同形异义词。

我已经做好了非常至少使用 Perl 实现第一部分的简单方法。这确实是一件很蛋疼的事情。以下是我用于为伊比利亚半岛上的城镇生成排序键的代码示例:

       # 第 1 条领先文章
          s/^L'//; # 加泰罗尼亚语
          s{ ^
            (?:
        # 卡斯蒂利亚语
                埃尔
              |洛斯
              |拉
              |拉斯

        # 加泰罗尼亚语
              |埃尔斯
              |莱斯         
              |萨
              |埃斯

        # 加勒戈
              |氧       
              |操作系统
              | A
              |作为      
            \s+
          }{}X;
        # 第二条内部颗粒
          s/\b[dl]'//g; # 加泰罗尼亚语
          s{
            \b
            (?:
                埃尔 |洛斯 |拉|拉斯|德|删除 |是的
              |埃尔斯 |莱斯 |我|萨| es |删除#CA
              |哦|操作系统 |一个 |作为 |做|达|操作系统 |达斯#GAL
            \b
        }{}gx;

这会剥离物品和颗粒,这样它们就不会被计入分类目的。但你必须处理类似的表格奥特尔带有所谓的弯引号,实际上是 U+2019 右单引号,是撇号的首选形式。我首先将它们标准化为直接的s/’/'/g

哦,您还必须处理编码问题:MacRoman 与 UTF-8 或 ISO-8859-1 不同 — 相差甚远。

老实说,您可能想使用 Snowball 词干算法之类的算法,指定法语为语言。当然 Perl 的Lingua::Stem::Snowball模块知道如何做到这一点。您可以使用以下命令搜索与法语语言学有关的 Perl 模块这个查询

但词干只能带你到目前为止。除非应用形态句法分析,否则你不会真正做好工作——这意味着你必须生成句子的解析并将词性分配给其中的每个元素。

这需要做更多的工作。好消息是,有专门的工具可以实现这一点,其中一些确实适用于法语。但这确实很重要,因为现在你已经涉足了自然语言处理和计算语言学领域。这里没有解决此类问题的好地方,但在 Linguistics.SE 上可能会得到更好的答案;我不知道。

答案2

自然语言处理很复杂。用正则表达式来做是就像用正则表达式解析 HTML,只会更糟。读基督的出色回答了解如何使用解决您的问题的一些见解。我将简要回答有关使用 UNIX 文本处理工具的可移植性的部分。

所有现代类 UNIX 系统的共同点是POSIX规范。最有用的资源是开放组规范第 6 期又名单一 Unix 规范版本 3(OGS 问题 7 = SUS 版本 4 在许多系统上未完全实现),它包括并扩展了 POSIX,并且有用的是,可以在线获取和下载(例如,在德班)。如果您只对非嵌入式 Linux(和 Cygwin)和 OSX 的可移植性感兴趣,请检查GNU 手册OSX 手册页

您正在使用多个非 POSIX 选项grep,但所有这些选项在 GNU 和 OSX 中都可用(OSX 使用 FreeBSD 中的 grep,它旨在模拟大多数 GNU 结构)。如果您想要 POSIX,则需要避免一些选项:

  • grep -h抑制文件名:grep一次调用一个文件,或将文件传递给cat第一个。
  • grep -o仅输出匹配的部分:使用sed或者awk相反。
  • grep -w仅匹配整个单词:搜索类似 的模式(^|[^[:alnum:]])needle($|[^[:alnum:]])

您在 sed 中使用一种仅适用于 GNU 的构造:\L在命令中将替换项小写的指令s。其他 sed 实现中没有类似的情况。一般来说,您可以使用 awk 来代替:分解输入以隔离要替换和调用的字符串tolower。要小写整个输入,请调用tr '[:upper:]' '[:lower:]'.

答案3

选定的答案确实很好地介绍了该领域的挑战自然语言处理计算语言学并且肯定还有更多信息专用SE资产。我想提供一个补充,强调这些挑战,并为我提供一个临时的“解决方案”。


我认为在某些情况下我可以修剪最后一个s达到sed相当安全但有趣的结果:

s/\(.*[bcdefghjklmnpqrtvwxyzéëêàâûùôö]\)s$/\1/

这压缩了一些50行在与原始函数一起使用时提供的示例中。

所以我尝试了sed以下方法,两者都是不完整的没有按预期工作- 但展示了困难,并且在我看来有助于理解答案的解释:

sed '

h;
s/^\(par\|col\|tap.*\)/\1/
t RVv

h;
s/^\(par\|col\|tap.*\)/\1/
t RVc

h;
s/^\([aeiouyâàëéêèïîôûù][aeiouyâàëéêèïîôûù]..*\)$/\1/
t RVnotpctv_v

h;
s/^\(.*.[aeiouyâàëéêèïîôûù]....*\)/\1/
t RVnotpctother
b

:RVv
s/^\(par\|col\|tap[bcdfghjklmnpqrstvwxz][aeiouyâàëéêèïîôûù].*\)/\1/
t R1

:RVc
s/^\(par\|col\|tap[aeiouyâàëéêèïîôûù][bcdfghjklmnpqrstvwxz].*\)/\1/
t R1

:RVnotpctv_v
s/^\([aeiouyâàëéêèïîôûù][aeiouyâàëéêèïîôûù].[aeiouyâàëéêèïîôûù][bcdfghjklmnpqrstvwxz].*\)$/\1/
t R1

:RVnotpctother
s/^\(.*[aeiouyâàëéêèïîôûù][bcdfghjklmnpqrstvwxz].*\)/\1/
t R1

:R1        
s/ement$\|ements$\|ité$\|ités$\|if$\|ive$\|ifs$\|ives$\|euse$\|euses$//
s/é$\|ée$\|ées$\|és$\|èrent$\|er$\|era$\|erai$\|eraIent$\|erais$\|erait$\|eras$\|erez$\|eriez$\|erions$\|erons$\|eront$\|ez$\|iez$\|ions$\|eons$//
s/eâmes$\|eât$\|eâtes$\|ea$\|eai$\|eaIent$\|eais$\|eait$\|eant$\|eante$\|eantes$\|eants$\|eas$\|easse$\|eassent$\|easses$\|eassiez$\|eassions$//
s/âmes$\|ât$\|âtes$\|a$\|ai$\|aIent$\|ais$\|ait$\|ant$\|ante$\|antes$\|ants$\|as$\|asse$\|assent$\|asses$\|assiez$\|assions$//
s/[bcdfghjklmnpqrstvwxz]îmes$\|ît$\|îtes$\|i$\|ie$\|ies$\|ir$\|ira$\|irai$\|iraIent$\|irais$\|irait$\|iras$\|irent$\|irez$\|iriez$\|irions$\|irons$\|iront$\|is$\|issaIent$\|issais$\|issait$\|issant$\|issante$\|issantes$\|issants$\|isse$\|issent$\|isses$\|issez$\|issiez$\|issions$\|issons$\|it$//
s/Y/i/
s/ç/c/
t R2

:R2
s/ance$\|iqUe$\|isme$\|able$\|iste$\|eux$\|ances$\|iqUes$\|ismes$\|ables$\|istes$//
s/atrice$\|ateur$\|ation$\|atrices$\|ateurs$\|ations$//
s/logie$\|logies$/log/
s/usion$\|ution$\|usions$\|utions$/u/
t Res

:Res
##Residual
s/ier$\|ière$\|Ier$\|Ière$/i/
s/\(.*[bcdefghjklmnpqrtvwxyzéëêàâûùôö]\)s$/\1/
##Undouble
s/\(en\)n$/\1/
s/\(on\)n$/\1/
s/\(et\)t$/\1/
s/\(el\)l$/\1/
s/\(eil\)l$/\1/
##Unaccent
s/\(.*\)\(é\)\([bcdefghjklmnpqrtvwxyzéëêàâûùôö]*\)$/\1e\3/
s/\(.*\)\(è\)\([bcdefghjklmnpqrtvwxyzéëêàâûùôö]*\)$/\1e\3/
s/\(.*\)e$/\1/
t
'

在某些情况下,它成功地将单词剥离到某个词干,但有一个非常有意识的选择,以避免处理仅包含几个字符的单词,因为它只实现一些小功能(而不是R2例如),而且在这方面做得很糟糕。但它会压缩样本中的另外 50-60 行,因为它包含先前的sed表达式。2为了进一步了解,我将研究语言学


1.这都是基于我对伪代码的“理解”/描述滚雪球法国算法。

2. 在很多情况下它是错误的,但是在线交互地运行它为我提供了在查看诸如此类的单词时所寻找的见解帕隆斯糖果。我意识到这两个词没有任何内在的东西决定了为什么第一个(动词)必须被剥夺,ons而另一个(名词)只能被剥夺s。是关于解析词性正如所解释的...

相关内容