本文介绍了Stata:计算预定义长度的连续出现的次数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的数据集中的观察数据包含每个球员的移动历史。我想计算一下在游戏的上半场和下半场,连续几步棋的长度(2步、3步和3步以上)。序列不能重叠,即序列1111应视为长度为4的序列,而不是长度为2的2个序列。也就是说,对于这样的观察:

+-------+-------+-------+-------+-------+-------+-------+-------+
| Move1 | Move2 | Move3 | Move4 | Move5 | Move6 | Move7 | Move8 |
+-------+-------+-------+-------+-------+-------+-------+-------+
|     1 |     1 |     1 |     1 | .     | .     |     1 |     1 |
+-------+-------+-------+-------+-------+-------+-------+-------+

…应生成以下变量:

Number of sequences of 2 in the first half =0 
Number of sequences of 2 in the second half =1
Number of sequences of 3 in the first half =0
Number of sequences of 3 in the second half =0
Number of sequences of >3 in the first half =1 
Number of sequences of >3 in the second half = 0

关于如何继续此任务,我有两种可能的选择,但这两种选择都不会导致最终解决方案:

选项1:详细说明Nick使用字符串的策略建议(Stata: Maximum number of consecutive occurrences of the same value across variables),我连接了所有"Move*"变量,并尝试确定子字符串的起始位置:

选项1有几个问题:(1)它不考虑序列重叠的情况("1111"被认为是2的2个序列)(2)它缩短了生成的字符串test2,因此X的位置不再对应于test1中的起始位置(3)如果我需要检查长度大于3的序列,则不考虑可变长度的子串。

选项2:创建一个辅助变量集,以标识某个固定预定义长度的1的连续集合的起始位置。在前面的示例的基础上,为了计算长度为2的序列,我尝试获得的是一个辅助变量集,如果序列在给定的移动时开始,则等于1,否则等于0:

+-------+-------+-------+-------+-------+-------+-------+-------+
| Move1 | Move2 | Move3 | Move4 | Move5 | Move6 | Move7 | Move8 |
+-------+-------+-------+-------+-------+-------+-------+-------+
|     0 |     0 |     0 |     0 |     0 |     0 |     1 |     0 |
+-------+-------+-------+-------+-------+-------+-------+-------+

我的代码如下所示,但当我尝试重新开始计算连续出现的事件时,它崩溃了:

quietly forval i = 1/42 {
gen temprow`i' =.
egen rowsum = rownonmiss(seq1-seq`i') //count number of occurrences
replace temprow`i'=rowsum 
mvdecode seq1-seq`i',mv(1) if rowsum==2 
drop rowsum
}

有人知道解决这项任务的方法吗?

推荐答案

假设连接所有移动的字符串变量all(名称test1很难让人联想到)。

第一次尝试:按字面意思理解您的示例

从您的8步棋的例子来看,游戏的上半场是1-4步,下半场是5-8步。因此,对于每一半来说,只有一种方法有>3步,即有4步。在这种情况下,每个子字符串将"1111",并且计数减少到测试一种可能性:

gen count_1_4 = substr(all, 1, 4) == "1111"
gen count_2_4 = substr(all, 5, 4) == "1111" 

扩展此方法,只有两种方法可以按顺序进行3个动作:

gen count_1_3 = inlist(substr(all, 1, 4), "111.", ".111")  
gen count_2_3 = inlist(substr(all, 5, 4), "111.", ".111")  
在类似的风格中,不能在游戏的每一半中有两个连续的2个移动的实例,因为这将符合4个移动的资格。因此,每半部分最多有一个2步连续移动的实例。该实例必须匹配"11."".11"这两个模式中的任何一个。".11."是允许的,因此两者都包括。正如刚刚提到的,我们还必须排除任何与3个动作序列相匹配的错误。

gen count_1_2 = (strpos(substr(all, 1, 4), "11.") | strpos(substr(all, 1, 4), ".11") ) & !count_1_3 
gen count_2_2 = (strpos(substr(all, 5, 4), "11.") | strpos(substr(all, 5, 4), ".11") ) & !count_2_3 
如果找到匹配项,则每个strpos()评估的结果将为正,如果任一参数为正,则(arg1|arg2)将为真(1)。(对于Stata,非零在逻辑计算中为真。)

这在很大程度上是针对您的特定问题量身定做的,但也不会因此而变得更糟。

附注:我没有努力理解您的代码。您似乎混淆了subinstr()strpos()。如果你想知道位置,subinstr()无能为力。

第二次尝试

您的最后一段代码暗示您的示例具有很大的误导性:如果可以有42个移动,则上面的方法无法毫无困难地扩展。你需要一种不同的方法。

假设字符串变量all可以是42个字符。我将搁置上半场和下半场之间的区别,这可以通过修改这种方法来解决。简单来说,只需将历史分为两个变量,一个用于前半部分,另一个用于后半部分,然后重复两次这种方法。

您可以通过以下方式克隆历史记录

  clonevar work = all 
  gen length1 = . 
  gen length2 = . 

并设置count变量。这里count_4将包含4个或更多的计数。

  gen count_4 = 0 
  gen count_3 = 0 
  gen count_2 = 0 
首先,我们寻找长度为42,...,2的移动序列。每次我们找到一个移动序列,我们就把它清空并增加计数。

  qui forval j = 42(-1)2 { 
       replace length1 = length(work) 
       local pattern : di _dup(`j') "1" 
       replace work = subinstr(work, "`pattern'", "", .) 
       replace length2 = length(work) 
       if `j' >= 4 {
            replace count4 = count4 + (length1 - length2) / `j' 
       }
       else if `j' == 3 { 
            replace count3 = count3 + (length1 - length2) / 3
       }
       else if `j' == 2 { 
            replace count2 = count2 + (length1 - length2) / 2 
       }
  }

这里的重要细节是

  1. 如果我们删除一个模式(重复的实例)并测量长度的变化,我们就删除了该模式的(长度变化)/(模式的长度)实例。所以,如果我查找"11",发现长度减少了4,我只找到了两个实例。

  2. 向下工作,删除我们发现的内容,确保我们不会发现误报,例如,如果删除"1111111",我们就不会发现后面包含的"111111"、"11111"、……、"11"。

  3. 删除意味着我们应该在克隆上工作,以便不破坏感兴趣的内容。

这篇关于Stata:计算预定义长度的连续出现的次数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-01 08:09