【问题标题】:Is there a simple way of extract the N first words from a local macro which is comma or space+comma separated in Stata?有没有一种简单的方法从在Stata中以逗号或空格+逗号分隔的局部宏中提取N个第一个单词?
【发布时间】:2021-03-24 15:57:17
【问题描述】:

给定一个本地宏,其中包含由逗号 (",") 或 逗号加空格(“,”)甚至只有空格(“”),有没有简单的方法可以提取第一个N 这个本地宏的级别(或单词)?

字符串看起来像"12, 123, 1321, 41""12,123,1321,41""12 123 1321 41"

基本上我会对 Macro Function word # of string 的一个版本感到满意 或多或少会像word 1/N of string 一样工作。 (参见“用于解析的宏函数” pg 12 in Macro definition and manipulation)

有关更多上下文,我正在使用levelsof, local() sep() 的输出。所以 我可以选择更容易使用的分隔符。我想要 将结果级别作为参数传递给inlist() 函数。以下 通常有效,但inlist() 最多只需要 250 个参数。这就是为什么我会 喜欢从levelsof()的结果中提取250个单词的块

sysuse auto, clear
levelsof mpg if trunk > 20, local(levels) sep(", ")
list if inlist(mpg, `levels')

到目前为止的“解决方案”

我想出了一个不简单的方法来实现这一点,但它看起来并不好,而且 我想知道是否有一种简单的内置方法可以做到这一点。

sysuse auto, clear

levelsof mpg if trunk > 20, local(levels) sep(", ")
scalar number_of_words = 3
forvalues i = 1 (1) `=number_of_words' {
        local word_i = `i'
        local this_level : word `word_i' of `levels'
        local list_of_levels = "`list_of_levels'`this_level'" 
        
        di as text "loop: `i'"
        di as text "this level: `this_level'"
        di as text "list of levels so far: `list_of_levels'"
    }

di "`list_of_levels'"

// trim trailing comma
local trimmed_list_of_levels = substr( "`list_of_levels'" , 1 , strlen( "`list_of_levels'" )-1) 

di "`trimmed_list_of_levels'"
list make mpg price trunk if inlist(mpg, `trimmed_list_of_levels')

输出

. sysuse auto, clear
(1978 Automobile Data)

. 
. levelsof mpg if trunk > 20, local(levels) sep(", ")
12, 15, 17, 18

. scalar number_of_words = 3

. forvalues i = 1 (1) `=number_of_words' {
  2.         local word_i = `i'
  3.         local this_level : word `word_i' of `levels'
  4.         local list_of_levels = "`list_of_levels'`this_level'" 
  5.         
.         di as text "loop: `i'"
  6.         di as text "this level: `this_level'"
  7.         di as text "list of levels so far: `list_of_levels'"
  8.     }
loop: 1
this level: 12,
list of levels so far: 12,
loop: 2
this level: 15,
list of levels so far: 12,15,
loop: 3
this level: 17,
list of levels so far: 12,15,17,

. 
. di "`list_of_levels'"
12,15,17,

. 
. // trim trailing comma
. local trimmed_list_of_levels = substr( "`list_of_levels'" , 1 , strlen( "`list_of_levels'" )-1) 

. 
. di "`trimmed_list_of_levels'"
12,15,17

. list make mpg price trunk if inlist(mpg, `trimmed_list_of_levels')

     +------------------------------------------+
     | make                mpg    price   trunk |
     |------------------------------------------|
  2. | AMC Pacer            17    4,749      11 |
  5. | Buick Electra        15    7,827      20 |
 23. | Dodge St. Regis      17    6,342      21 |
 26. | Linc. Continental    12   11,497      22 |
 27. | Linc. Mark V         12   13,594      18 |
     |------------------------------------------|
 31. | Merc. Marquis        15    6,165      23 |
 53. | Audi 5000            17    9,690      15 |
 74. | Volvo 260            17   11,995      14 |
     +------------------------------------------+

与 cmets 相关的编辑。

编辑 01)

例如,以下内容不起作用。它返回错误130 expression too long

clear 

set obs 1000
gen id = _n 
gen x1 = rnormal()

sum * 
levelsof id if x1>0, local(levels) sep(", ")
sum * if inlist(id, `levels')

这种构造(levelsof + inlist)似乎是必要的示例

clear 

set obs 5000
gen id = round(_n/5)
gen x1 = rnormal()

sum * 
levelsof id if x1>2, local(levels) sep(", ")
sum * if x1>2 // if threshold is small enough, there will be too many values for inlist()
sum * if inlist(id, `levels')

【问题讨论】:

  • 您可以在循环中使用word 命令,其中word 将返回列表中的第n 个单词(请参阅help word)。您能否详细说明您对inlist 的最终计划是什么?可能有更简单的方法。
  • 感谢您的快速回复。请参阅问题中的编辑 1。如果有超过(大约)250 个级别,函数 inlist 返回error 130``expression too long 。当少于那个时,它工作正常。 word 函数只从字符串中检索一个单词。如果有一个用于检索n 第一个单词s 的内置函数可以避免使用我在问题中写的那个循环,我就在徘徊。但是,如果没有内置或更简单的方法,则循环确实有效。
  • 快速解答:将本地推入 Mata 并使用tokens() 的结果。
  • 尼克的回答最适合您的要求。从我的角度来看,很难看到与您的编辑 1 相关的sum * if x1>0 的最终目标。
  • 没错,我将添加一个示例,说明走这条路会有所不同。想象一下,我对相同的id 进行了多次观察,但不一定与相同的x1 相同。如果我想提取至少有一次x1 大于阈值的ids 的所有观察结果(以前和过去),那么据我所知,我需要求助于@987654350 @+ inlist 建设。

标签: string stata local-variables stata-macros


【解决方案1】:

使用您的附加示例作为基础,您可以使用egen max 为整个id 创建一个标志,该标志具有任何情况,其中x1 值高于某个阈值.例如:

clear 
set seed 2021
set obs 5000
gen id = round(_n/5)
gen x1 = rnormal()

sum * 
levelsof id if x1>2, local(levels) sep(", ")
sum * if x1>2 // if threshold is small enough, there will be too many values for inlist()
sum * if inlist(id, `levels')

//This will do the same thing
gen over_threshold = x1>2 
egen id_over_thresh = max(over_threshold), by(id)

sum * if id_over_thresh

【讨论】:

  • 为了将来的使用,您可以将其缩短为egen id_over_thresh = max(x1>2), by(id)
  • 非常有趣的想法!我将看看这是否适用于我的实际用例,这些用例稍微复杂一些,if 语句基于多个变量和条件......(包括数字和分类数据......)。无论如何,虽然这甚至可以解决我的问题,但它并不能直接解决问题......
  • 请注意这里的x1 将>2,如果它丢失。
  • 是的,尼克在失踪方面做得很好。我同意这并不能直接回答您的问题,推送到mata 是我能想到的最佳捷径。无论条件的复杂性或by 组中的任何数量的识别变量如何,上面的答案都应该很好地概括。
  • 谢谢JR96。它确实适用于我的实际数据,您的解决方案非常灵活。非常简单但优雅的解决我的问题...
猜你喜欢
  • 1970-01-01
  • 2019-08-10
  • 2015-12-25
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多