【问题标题】:Smart way of counting sequences of 1s and 0s (Markov chain)计数 1 和 0 序列的智能方法(马尔可夫链)
【发布时间】:2021-09-24 08:38:53
【问题描述】:

假设一个 1 和 0 的序列 (np.array)。我需要构建二阶马尔可夫链。为此,我需要计算 T001,... T111 的比例,其中 T001 是序列出现 [0,0,1] 的次数。显然我可以做一个 for 循环,但我试图避免这种情况。理想情况下,该方法可以扩展到k-oder。

【问题讨论】:

    标签: python python-3.x numpy


    【解决方案1】:

    任务可以分为两个子任务:首先是创建所有长度为 3 的子序列,然后计算所有唯一的子序列。这两项任务都可以通过内置的numpy 方法完成:

    假设输入序列在a中存储为numpy数组,第一个点可以用

    windows = np.lib.stride_tricks.sliding_window_view(a, 3)
    

    然后我们可以使用计算不同的窗口

    unique_windows, counts = np.unique(windows, axis=0, return_counts=True)
    

    【讨论】:

      【解决方案2】:

      您可以使用more_itertools.windowedcollections.Counter 的组合:

      from more_itertools import windowed
      from collections import Counter
      import numpy as np
      
      np.random.seed(0)
      a = np.random.choice([0,1], size=100)
      
      Counter(windowed(a, n=3))
      

      输入:

      array([0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
             1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1,
             1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0,
             0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1,
             1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0])
      

      输出:

      Counter({(0, 1, 1): 14,
               (1, 1, 0): 14,
               (1, 0, 1): 15,
               (1, 1, 1): 16,
               (1, 0, 0): 10,
               (0, 0, 1): 10,
               (0, 1, 0): 12,
               (0, 0, 0): 7})
      

      使用自定义键:

      {'T'+''.join(map(str, k)): v for k,v in Counter(windowed(a, n=3)).items()}
      

      输出:

      {'T011': 14,
       'T110': 14,
       'T101': 15,
       'T111': 16,
       'T100': 10,
       'T001': 10,
       'T010': 12,
       'T000': 7}
      

      如何确保所有值都存在(即使计数为零):

      简单的解决方案:生成所有可能键的列表并使用它来迭代

      from itertools import product
      possible_keys = ['T'+''.join(map(str, k)) for k in product([0,1], repeat=3)]
      

      输出:

      ['T000', 'T001', 'T010', 'T011', 'T100', 'T101', 'T110', 'T111']
      

      你可以结合使用字典get方法:

      ## as comprehension
      {k: out.get(k, 0) for k in possible_keys}
      
      ## as classical loop
      for key in possible_keys:
          out.get(key, 0) # default value is 0
      
      完整示例:
      from itertools import product
      a = [0,1,1,0]
      out = {'T'+''.join(map(str, k)): v for k,v in Counter(windowed(a, n=3)).items()}
      possible_keys = ['T'+''.join(map(str, k)) for k in product([0,1], repeat=3)]
      out = {k: out.get(k, 0) for k in possible_keys}
      

      输出:

      {'T000': 0,
       'T001': 0,
       'T010': 0,
       'T011': 1,
       'T100': 0,
       'T101': 0,
       'T110': 1,
       'T111': 0}
      

      字典更新(python ≥3.9)

      from itertools import product
      default = {'T'+''.join(map(str, k)): 0 for k in product([0,1], repeat=3)}
      out = default | out # update default with the values in out
      

      【讨论】:

      • 如果 Txx 不在序列中,则不会输出 Txxx = 0。
      • @deblue 你可以使用默认字典:from collections import defaultdict ; out = defaultdict(int, {'T'+''.join(map(str, k)): v for k,v in Counter(windowed(a, n=3)).items()}) ; out['Txxx']
      • 如果你想要一个包含所有值的字典还有其他方法,让我知道你到底需要什么,我会更新答案
      • 嗨,谢谢,但这对我也没有用,因为我需要创建比例,例如:{'p'+''.join(map(str, k[1:])): v for k,v in zip(d.keys(), np.array(list(d.values())) / sum(list(d.values())))}。好吧,理想情况下,由于顺序是 2(意味着一个序列中出现 3 次),我需要一个带有 Txxx 的 4x4 矩阵,然后我可以除以总和并得到比例。
      • @deblue 我添加了一些示例以确保输出包含所有键,还有很多其他方法,让我知道这对你有用吗 ;)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 2013-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多