1

我的数据集中的观察结果包含每个玩家的移动历史。我想计算游戏上半场和下半场中某些预定义长度(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:变量中相同值的最大连续出现次数),我连接了所有“move*”变量并尝试识别子字符串的起始位置:

egen test1 = concat(move*)
gen test2 = subinstr(test1,"11","X",.) // find all consecutive series of length 2

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

选项 2:创建一个辅助变量集,以识别具有某些固定预定义长度的 1 的连续集(集)的起始位置。在前面的示例的基础上,为了计算长度为 2 的序列,我想要得到的是一组辅助变量,如果序列在给定移动开始时将等于 1,否则为零:

+-------+-------+-------+-------+-------+-------+-------+-------+
| 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
}

有谁知道解决任务的方法?

4

1 回答 1

1

假设一个字符串变量连接所有动作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,非零在逻辑评估中为真。)

这非常适合您的特定问题,但也不会更糟。

PS我没有努力理解你的代码。你似乎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. 删除意味着我们应该在克隆上工作,以免破坏感兴趣的内容。

于 2013-10-08T08:48:46.953 回答