【问题标题】:Check if each value of one variable matches any value of another variable检查一个变量的每个值是否与另一个变量的任何值匹配
【发布时间】:2026-01-12 03:45:01
【问题描述】:

我想要egen newvar = anymatch(oldvar1), values(oldvar2) 之类的东西。这将创建一个指示变量,显示 oldvar2 中的特定值是否包含在 oldvar1 的任何位置。除了 anymatch 的 AFAIK,values 仅接受 integer numlist

这会有很多用途,但这是我的第一个示例:我有一个大型国家/地区对数据集。我有一个具有特定属性的 Country1 子集。我想识别与子集的任何成员匹配的 Country2。

让我们看看我是否可以制作一个玩具示例:

     +--------------------------------------------------+
     | pair   Country1   value_C1   Country2   valC1_g2 |
     |--------------------------------------------------|
  1. |   AB          A          1          B          0 |
  2. |   AC          A          2          C          0 |
  3. |   BA          B          3          A          1 |
  4. |   BC          B          4          C          1 |
  5. |   CA          C          5          A          1 |
     |--------------------------------------------------|
  6. |   CB          C          6          B          1 |
     +--------------------------------------------------+

value_C1 变量与 Country1 的属性相关。变量 valC1_g2 表示 value_C1 > 2。我想要一个变量来指示 Country2 中的每个特定变量是否在 Country1 if valC1_g2 列表中的某处匹配。

这似乎不是一个罕见的问题,但除了这个 researchgate 主题之外,我找不到任何直接解决它的东西。

这可以通过合并来完成:

preserve // saves current data
tempfile localdata // initialize a temporary new dataset
  keep Country1 valC1_g2 // subsetting allows re-ordering of just these variables
  rename (Country1 valC1_g2) (Country2 valC2_g2) // renaming to match the target
  sort Country2 // this just facilitates the 1:1 merge
  save `localdata'
restore // bring back original data

sort Country2 
merge  Country2 using `localdata' // this re-orders the subset to align with Country2 
  sort Country1 pair  // this resets the dataset to the original order

list, abbreviate(10) separator(0)

     +-------------------------------------------------------------+
     | pair   value_C1   Country1   Country2   valC1_g2   valC2_g2 |
     |-------------------------------------------------------------|
  1. |   AB          1          A          B          0          1 |
  2. |   AC          2          A          C          0          1 |
  3. |   BA          3          B          A          1          0 |
  4. |   BC          4          B          C          1          1 |
  5. |   CA          5          C          A          1          0 |
  6. |   CB          6          C          B          1          1 |
     +-------------------------------------------------------------+

我发现这种方法存在一些问题。

首先,您会看到我的 merge 语法使用旧语法,因为 Country2 不能唯一标识我的数据。 (我想这意味着我在新语法​​中使用 m:m 吗?merge 的文档说这是不行的。)pair 变量扮演这个角色,但我不能成对合并,否则我不会得到我需要的重新排序。可能是我担心太多了?

其次,我如何检查它是否有效?之后我想比较 Country1 和 Country2 中的国家 ID,看看它们是否具有相同的值集。 compare 不起作用,因为这些值没有按行排列。我唯一能想到的就是在再次使用合并重新排序后进行比较,但这实际上只是撤消了我刚刚所做的事情。

如果有任何更好的方法建议,我将不胜感激。

【问题讨论】:

    标签: merge stata


    【解决方案1】:

    一个变量,指示 Country2 是否在 Country1 if valC1_g2 的列表中

    你的这个描述不是很清楚,可能会导致不同的理解:

    • 有些人可以将其解释为 Country1 在相应的观察(对)中具有 valC1_g2=1(如 Pearly Spencer 的代码,优雅且“令人愉快”,如果您可能熟悉mata)。

    • 同时,其他人可能会认为 相关观察(对)中的 Country2 与某处的 Country1 相同,并且 Country1 有其(最大)valC1_g2=1 。请注意,这里提到了 (max),因为对于您的小样本,假设任何 Country1 在任何观察中都应该具有相同的 valC1_g2,因此无法确定。

    对我来说,您尝试的代码意味着第二种理解。如果是这种情况,在您的代码中再添加 1 行可以帮助您。实际上,还有其他一些(并且可能更优雅)的方法,但这种方法可能会节省您跟进的时间。

    preserve
    tempfile localdata
    keep Country1 valC1_g2
    
    *(Addedline)
    collapse (max) valC1_g2 if valC1_g2, by(Country1)
    
    rename (Country1 valC1_g2) (Country2 valC2_g2)
    save `localdata'
    restore
    sort Country2
    
    * (It is better to use the new merge syntax, despite your old one might work)
    merge m:1 Country2 using `localdata', keep(master match) nogen
    

    编辑。您的编辑版本确认了第二个理解,使它更清晰了一点。另一个提高透明度的建议是,“Afterward part”(比较 2 个国家 ID)不应与 “Second part” 放在同一行(检查第一部分的代码逻辑)。它们是两个不同的问题。

    以下代码仍然使用 -merge- 作为主要工具,预计可以解决您的问题,作者:

    1. 创建一个变量 (C2inListC1) 来检查 Country2 是否在 国家/地区列表

    2. 如果 Country2 在 Country1 的列表中,则其 valC2_g2 将具有对应 Country1 的 valC1_g2 的(最大值)值。之所以提到 (max),是因为如上所述,到目前为止,还不能确定每个 Country1 应该具有相同的 valC1_g2。

    3. 创建一个变量 (C1inListC2) 来检查 Country1 是否在 Country2 的列表中。然后您可以使用 C2inListC1 和 C1inListC2 的信息来检查 Country1 和 Country2 是否具有相同的值集。仅当 “所有 Country2 都在 Country1 列表中” 并且 “所有 Country1 都在 Country2 列表中”时,两者才相同

    请注意,虽然还有其他一些方法(可能在编码上更简洁或更优雅,尤其是创建 C2inListC1 时),但 -merge- 提供了非常清晰和直接的逻辑,并且似乎是收集 valC1_g2 信息的最佳工具。它应该工作,仅在正确的逻辑上。编码只是将逻辑本身翻译成编码语言。

    tempfile ListC1 ListC2
    
    preserve
    collapse (max) valC1_g2, by(Country1)
    rename (Country1 valC1_g2) (Country2 valC2_g2)
    save `ListC1', replace
    restore
    
    preserve
    contract Country2
    ren Country2 Country1
    save `ListC2', replace
    restore
    
    merge m:1 Country2 using `ListC1', keep(master match) gen(C2inListC1)
    merge m:1 Country1 using `ListC2', keep(master match) gen(C1inListC2) keepusing(Country1)
    
    recode C2inListC1 C1inListC2 (3=1) (else=0)
    label values C2inListC1 C1inListC2 none
    
    count if C2inListC1==0 | C1inListC2==0
    if r(N) == 0{
    di "Country1 and Country2 have the same values set"
    }
    else {
    di in red "Country1 and Country2 do NOT have the same values set"
    }
    

    【讨论】:

    • 编辑问题以澄清。
    • 感谢@Romalpa Akzo!我可以问 2 个后续 Q 以确保我理解了吗?首先,如果每个 Country1 只有一个 valC1_g2 值(因为它们派生自 Country1 的属性),代码将如何变化?我想你可以collapse (first) 而不是(max)。这就是全部?二、“keepusing(Country1)”的意义何在?它是在 Country1 上的 merges 和 keep(master match),所以最后一点似乎没有必要。我错过了什么吗?再次感谢!
    • (1) 是的。在这种情况下,collapse (first)(firstnm) 甚至 (mean) 都会起作用。无论如何,对于这个问题,(max) 似乎“更安全”。 (2) keepusing(Country1) 只是用来忽略 _freq 变量,它是由 -contract- 命令创建的。您可以省略 keepusing(Country1) 以查看差异。
    最近更新 更多