2011-01-12 8 views
4

この質問をCode Review -areaに移動してください。私は以下のコードが迷惑であることを知っており、重要なフィードバックを書き換えを完了させたいからです。私は車輪をかなり改革しています。より良い構造のfor-if messesを簡略化しますか?

# Description: you are given a bitwise pattern and a string 
# you need to find the number of times the pattern matches in the string. 
# The pattern is determined by markov chain. 
# For simplicity, suppose the ones and zeros as unbiased coin flipping 
# that stops as it hits the pattern, below. 
# 
# Any one liner or simple pythonic solution? 

import random 

def matchIt(yourString, yourPattern): 
     """find the number of times yourPattern occurs in yourString""" 

     count = 0 
     matchTimes = 0 

     # How can you simplify the for-if structures? 
     # THIS IS AN EXAMPLE HOW NOT TO DO IT, hence Code-Smell-label 
     # please, read clarifications in [Update] 

     for coin in yourString: 
      #return to base 
      if count == len(pattern): 
        matchTimes = matchTimes + 1 
        count = 0 

      #special case to return to 2, there could be more this type of conditions 
      #so this type of if-conditionals are screaming for a havoc 
      if count == 2 and pattern[count] == 1: 
        count = count - 1 

      #the work horse 
      #it could be simpler by breaking the intial string of lenght 'l' 
      #to blocks of pattern-length, the number of them is 'l - len(pattern)-1' 
      if coin == pattern[count]: 
        count=count+1 

     average = len(yourString)/matchTimes 

     return [average, matchTimes] 



# Generates the list 
myString =[] 
for x in range(10000): 
    myString= myString + [int(random.random()*2)] 

pattern = [1,0,0] 
result = matchIt(myString, pattern) 

print("The sample had "+str(result[1])+" matches and its size was "+str(len(myString))+".\n" + 
     "So it took "+str(result[0])+" steps in average.\n" + 
     "RESULT: "+str([a for a in "FAILURE" if result[0] != 8])) 


# Sample Output 
# 
# The sample had 1656 matches and its size was 10000. 
# So it took 6 steps in average. 
# RESULT: ['F', 'A', 'I', 'L', 'U', 'R', 'E'] 

[更新]

私は多分、問題はその方法を簡略化することができ、ここでの理論について少し説明します。上記のコードは、下記の遷移行列Aでマルコフ連鎖を構築しようとしています。あなたがコインフリッピングとして想像できるパターン100はそれに対応しています。当該

>>> Q=numpy.matrix('0.5 0.5 0; 0 0.5 0.5; 0 0.5 0')  
>>> I=numpy.identity(3) 
>>> I 
array([[ 1., 0., 0.], 
     [ 0., 1., 0.], 
     [ 0., 0., 1.]]) 
>>> Q 
matrix([[ 0.5, 0.5, 0. ], 
     [ 0. , 0.5, 0.5], 
     [ 0. , 0.5, 0. ]]) 
>>> A=numpy.matrix('0.5 0.5 0 0; 0 0.5 0.5 0; 0 0.5 0 0.5; 0 0 0 1') 
>>> A 
matrix([[ 0.5, 0.5, 0. , 0. ], 
     [ 0. , 0.5, 0.5, 0. ], 
     [ 0. , 0.5, 0. , 0.5], 
     [ 0. , 0. , 0. , 1. ]]) 

average8マトリックス上記QN=(I-Q)^-1内の最初の行に値の和となります。

>>> (I-Q)**-1 
matrix([[ 2., 4., 2.], 
     [ 0., 4., 2.], 
     [ 0., 2., 2.]]) 
>>> numpy.sum(((I-Q)**-1)[0]) 
8.0 

ここで、この見かけ上のみのパターンマッチング問題がマルコフチェーンになることがわかります。あなたは乱雑なfor-if-if条件を行列や行列に似たものに置き換えることができなかった理由はわかりません。私はそれらを実装する方法はわかりませんが、繰り返しを行う必要がある州が増えれば、イテレータは研究の道を開くことができます。

しかし、Numpyに問題が発生しました。-InfNaNは何ですか?上の数値が(I-Q)**-1の行列から収束する値を確認します。 NN=I+Q+Q^2+Q^3+...=\frac{I-Q^{n}}{I-Q}です。

>>> (I-Q**99)/(I-Q) 
matrix([[ 2.00000000e+00, 1.80853571e-09,    -Inf], 
     [    NaN, 2.00000000e+00, 6.90799171e-10], 
     [    NaN, 6.90799171e-10, 1.00000000e+00]]) 
>>> (I-Q**10)/(I-Q) 
matrix([[ 1.99804688, 0.27929688,  -Inf], 
     [  NaN, 1.82617188, 0.10742188], 
     [  NaN, 0.10742188, 0.96679688]]) 
+2

これは宿題か面接の割り当てですか?その場合は、宿題としてタグ付けしてください。 – gotgenes

+1

また、三重引用符で囲まれた文字列をコメントとして使用することは残念です。本当のコメントでなければなりません(プレフィックス '#')。 – gotgenes

+0

gotgenes:いいえ、私は数学以外の何かをしています。この問題は、より良い構造で殺される可能性があります。 – hhh

答えて

1

OK - 標準(-ish)文字列検索:

def matchIt(needle, haystack): 
    """ 
    @param needle: string, text to seek 
    @param haystack: string, text to search in 

    Return number of times needle is found in haystack, 
     allowing overlapping instances. 

    Example: matchIt('abab','ababababab') -> 4 
    """ 
    lastSeenAt = -1 
    timesSeen = 0 
    while True: 
     nextSeen = haystack.find(needle, lastSeenAt+1) 
     if nextSeen==-1: 
      return timesSeen 
     else: 
      lastSeenAt = nextSeen 
      timesSeen += 1 

いますが、アルにこれをしたいです数字のist?問題ない;その後、例が

matchIt([1,2,1,2], FindableList([1,2,1,2,1,2,1,2,1,2])) -> 4 

のように見え、あなたのコードになる

import itertools 
class FindableList(list): 
    def find(self, sub, start=None, end=None): 
     """ 
     @param sub: list, pattern to look for in self 

     @param start: int, first possible start-of-list 
      If not specified, start at first item 

     @param: end: int, last+1 possible start-of-list 
      If not specified, end such that entire self is searched 

     Returns; 
      Starting offset if a match is found, else -1 
     """ 
     if start is None or start < 0: 
      start = 0 

     # N.B. If end is allowed to be too high, 
     # zip() will silently truncate the list comparison 
     # and you will probably get extra spurious matches. 
     lastEnd = len(self) - len(sub) + 1 
     if end is None or end > lastEnd: 
      end = lastEnd 

     rng = xrange if xrange else range 
     iz = itertools.izip 
     isl = itertools.islice 

     for pos in rng(start, end): 
      if all(a==b for a,b in iz(sub, isl(self, pos, end))): 
       return pos 

     # no match found 
     return -1 

# Generate a list 
randIn = lambda x: int(x*random.random()) 
myString =[randIn(2) for i in range(10000)] 

pattern = [1,0,0] 
result = matchIt(pattern, myString) 

print("The sample had {0} matches and its size was {1}.\n".format(result, len(myString))) 
2
def matchIt(yourString, yourPattern): 
     """find the number of times yourPattern occurs in yourString""" 

次を使用することはできますか?あなたのケースでは

yourString.count(yourPattern) 

あなたは文字列としても10000の文字とpatternの実際の文字列としてmyStringを作成し、簡単な神託の方法で発生を数えることができます。

EDIT

あなたに(文字列またはリストのいずれかになります)textpatternの(重複する)出現箇所の数を与えるワンライナーは、次のようになります。

nbOccurences = sum(1 for i in xrange(len(text)-len(pattern)) if text[i:i+len(pattern)] == pattern) 
+0

N.B.つまり、 "abababcd" .count( "abab")は1を与えます。それはポスターが何であるかということではないかもしれませんが、本当に難しいです。 –

+0

M.C.重複しているオカレンスを推測するので、重複するオカレンスも必要です。 – hhh

+0

@HH - 私は重複した発生を含むように私の答えを編集しました... – eumiro

0

私たちはそうのようにfind()メソッドでリストクラスを作成する必要がありますこれは準備ができていません。

同様の質問が、グラフライブラリhereと同様の問題が、C#で、多分便利に主な焦点。この質問に関連している

ファイルは、あなたが車輪の再発明するかどうかわからない./networkx/generators/degree_seq.py(与えられた数列でgrapsの生成について997行)と./networkx/algorithms/mixing.py (line 20, function degree_assortativity(G) about probability based graphs)であり、またそのソースコードが92の参考文献を参照することに注意してください。 igraphについては、重み付きエッジについてファイルconvert.cの835行目を読んでください。 Networkx hereのソースとigraph hereのソースを取得できます。前者はGNU(GPL)の下でigraphを実行し、Pythonで実行していることに注意してください。

Networkxを始めるには、だからあなたのマルコフ連鎖を作成するための

def create_weighted(self, G): 
    g = cycle_graph(4) 
    e = g.edges() 
    source = [u for u,v in e] 
    dest = [v for u,v in e] 
    weight = [s+10 for s in source] 
    ex = zip(source, dest, weight) 
    G.add_weighted_edges_from(ex) 
    return G 

、有向重み付きグラフhereについて助け、おそらくこのような何か:

>>> DG=nx.DiGraph() 
>>> DG.add_weighted_edges_from([(0,0,0.5),(1,1,0.5),(3,3,1),(0,1,0.5),(1,2,0.5),(2,3,0.5), (2,1,0.5)]) 

または何らかのOTのためにそこにあるとして、おそらくいくつかの準備ができてマルコフ連鎖生成ツールがあります彼女の確率論的過程、more herealgorithmが例外値を持つグラフを分析したり、例のように異なるセットで試行したりすることはありません。おそらく存在しない可能性があります。また、他のレプリケーターのソリューションに固執する必要があります。

関連する問題