20

我的问题在概念上类似于解决字谜,除了我不能只使用字典查找。我试图找到似是而非的词而不是真实的词。

我基于一堆文本中的字母创建了一个 N-gram 模型(目前,N=2)。现在,给定一个随机的字母序列,我想根据转换概率将它们排列成最可能的序列。当我开始这个时,我以为我需要维特比算法,但当我深入研究时,维特比算法会根据观察到的输出优化一系列隐藏的随机变量。我正在尝试优化输出序列。

有没有我可以阅读的著名算法?或者我是否在 Viterbi 的正确轨道上,我只是不知道如何应用它?

更新

我添加了一个赏金来要求更多地了解这个问题。(分析解释了为什么一种有效的方法是不可能的,除了模拟退火之外的其他启发式/近似等)

4

4 回答 4

5

将 K 个字母的集合视为图中的顶点。

添加有向边以表示从每个字母到所有其他字母的 2-gram,权重对应于它们的概率。

因此,“单词”是通过(完整的、有向的)图的路径。

您正在寻找使用所有字母(访问所有顶点)的最佳(最小或最大权重)“单词”(路径)。

这就是不对称的旅行商问题。它是NP完全的。如果您使用大于 N=2 的 N-gram,我认为这不会变得更容易,因此您不太可能找到有效的算法,但如果您这样做,请告诉我们

(模拟退火或类似的东西可能是要走的路)

于 2010-07-23T06:54:44.340 回答
5

作为练习,我在 MATLAB 中编写了马尔可夫链的简单实现。基本上它是一个基于字母的概率模型来生成单词。

function mc = MC(numStates)
    N = numStates;
    PI = ones(1,N)/N;
    TR = ones(N,N)/N;
    mc = struct('logprob',@logprob, 'train',@train, ...
                'sample',@sample, 'sampleFiltered',@sampleFiltered);

    function train(seqs)
        PI = 1 + histc(cellfun(@(c)c(1), seqs)', 1:N); %#'
        TR = ones(N,N);
        for i=1:numel(seqs)
            ind = sub2ind([N N], seqs{i}(1:end-1), seqs{i}(2:end));
            TR = TR + reshape(histc(ind,1:N*N), [N N]);
        end
        PI = bsxfun(@rdivide, PI, sum(PI,2)+(sum(PI,2)==0));
        TR = bsxfun(@rdivide, TR, sum(TR,2)+(sum(TR,2)==0));
    end

    function seq = sample(len)
        seq = zeros(1,len);
        seq(1) = randsample(1:N, 1, true, PI);
        for t=2:len
            seq(t) = randsample(1:N, 1, true, TR(seq(t-1),:));
        end
    end

    function seq = sampleFiltered(allowed)
        len = numel(allowed);
        seq = zeros(1,len);
        seq(1) = randsample(allowed, 1, true, PI(allowed));
        allowed( find(allowed==seq(1),1,'first') ) = [];
        for t=2:len-1
            seq(t) = randsample(allowed, 1, true, TR(seq(t-1),allowed));
            allowed( find(allowed==seq(t),1,'first') ) = [];
        end
        seq(t) = allowed;
        seq = seq(seq~=0);
    end

    function LL = logprob(seq)
        LL = log(PI(seq(1))) + ...
             sum( log(TR(sub2ind([N N],seq(1:end-1),seq(2:end)))) );
    end
end

我们需要一些文本来训练模型。我们使用古腾堡计划的“绿野仙踪”。

%# read the text document
str = lower( urlread('http://www.gutenberg.org/files/55/55.txt') );
SP = char(32);                        %# delimiter (space)
str( ~isstrprop(str, 'alpha') ) = SP; %# replace non-letters with spaces
str( findstr(str, [SP SP]) ) = [];    %# consecutive spaces as one
idx = ( str == SP );                  %# location of spaces
df = diff([1 idx 1]);
len = find(df > 0) - find(df < 0);    %# length of each word
[seqs gn] = grp2idx( str(~idx)' );    %#' map letters to numbers starting from 1
seqs = mat2cell(seqs', 1, len)';      %# put each word in a separate cell
N = length(gn);                       %# A to Z

最后,我们使用该模型随机抽取单词或从一组字母中抽取单词:

%# train Markov chain
mc = MC(N);
mc.train(seqs);

%# sample a random word
seq = mc.sample( randi([3 10]) );
fprintf('word = %s , logP(word)=%f\n', [gn{seq}], mc.logprob(seq))

%# sample a word from a set of letters
letters = lower('markovchains');
lettersIdx = cellfun(@(c) find(strcmp(c,gn)), cellstr(letters'));   %#'
seq = mc.sampleFiltered(lettersIdx);
fprintf('word = %s , logP(word)=%f\n', [gn{seq}], mc.logprob(seq))

这是从字母“markovchains”生成的一堆示例,以及给定模型的单词的对数概率:

word = mivorancask , logP(word)=-29.610819
word = arknoamshiv , logP(word)=-32.496090
word = ancoramshik , logP(word)=-29.299897
word = orchisankav , logP(word)=-29.987204
word = avinchasorm , logP(word)=-27.178507
word = aronchaskim , logP(word)=-25.651964

您可以看到,尽管没有一个是正确的单词,但它们仍然比随机的字母序列要好。显然只使用前一个字符来生成下一个字符是不够的,它仍然可以很容易地扩展到更复杂的情况(N-gram)。

这种方法的好处是它不限于一种语言,并且可以通过简单地从您选择的语言中提供文档来适应任何其他语言。

于 2010-07-27T05:57:09.987 回答
3

如果我正确理解您的问题,那么您正在搜索一个单词中所有字母的排列,以寻找具有 2 克概率乘积最低的字母。

如果您的话太长而无法简单地强制所有组合,我发现随机优化算法会在短时间内产生良好的结果。我(具有数学背景)对“模拟退火”算法做了一些工作,我认为这很适合您的问题。而且它很容易实现。

于 2010-04-16T06:26:33.133 回答
0

您也可以使用马尔可夫链随机进行。对于初学者,请确保您的 N-gram 表包含“单词开头”符号;然后从该状态中找到可用的转换,并对其进行过滤,使它们仅包含您的池中可用的字母,并使用加权概率在其中随机选择。然后从下一个状态找到转换,过滤到仍然可用的字母,并在池中没有更多字母时结束(或者,如果您达到无法转换出来的状态,请返回开始并重试)。

实际上,您可能会发现这比其他一些可用选项更随机是很有用的,如果它随机,您可以选择按摩概率,或者简单地生成一些n(比如 100)的随机词,将它们排序他们的“可能性”,然后从前m个(可能是 10 个)中随机选择,这样您就可以相对精细地控制从任何字母袋中生成的单词是更一致还是更随机。

于 2010-07-25T08:48:44.873 回答