难题:如何为具有交集(SAS)的并集创建新ID

难题:如何为具有交集(SAS)的并集创建新ID,sas,Sas,如何为任何重叠的ID1/ID2列创建ID3列?(不仅仅是交叉点,而是联合集 例如,ID2是一个在线账号,ID2是一个个人用来登录的IP地址。我想指定,只要它是相同的IP地址或登录ID,就为行分配相同的ID3 我正在使用SAS编码 有 想要 Year ID3 ID2 ID3 2010 101 1 201 2010 101 1 202 2010 102 2 203 2011 101 3

如何为任何重叠的
ID1/ID2
列创建
ID3
列?(不仅仅是交叉点,而是联合集

例如,
ID2
是一个在线账号,
ID2
是一个个人用来登录的IP地址。我想指定,只要它是相同的IP地址或登录ID,就为行分配相同的
ID3

我正在使用SAS编码

想要

Year    ID3     ID2     ID3
2010    101     1       201
2010    101     1       202
2010    102     2       203
2011    101     3       202
2011    102     4       203
2011    105     5       204

这是一个通常被认为已解决的问题,但不同的问题有不同的更有效的解决方案,这取决于多重链接的可能性

一个例子(相当笨拙,不是特别有效,但希望能解释一般解决方案)基本上,您需要遍历数据并将链接存储在单独的结构中(数组或哈希表是最常见的),然后在最后输出链接的结果。然后您可以将其合并回主数据集(未提供)

在这种情况下,我要做的是对每条记录使用
将其与数组匹配。如果是完全不匹配,则为新ID;创建新ID。如果是完全匹配,则继续。如果是单侧匹配(找到id1,但id2是新的),在添加id2的位置创建一个新行,其中包含id1和以前分配给id1的id3


以上事实上并不完美;稍后在id1和id2上交叉会导致额外的ID存在,但这是基本概念的一个例子。很容易找到关于这个主题的论文,它们太长了,无法给出正确的答案;例如,(Glenn Wright,WUSS 2010)是使用哈希表解决问题的一个很好的例子。

以下是一个我认为适用于所有情况的答案,尽管我不知道它的效率有多高:

我从一个数据集开始,其中添加了一些观察结果,以展示代码如何处理更困难的情况

data have;
input year id2 id1;
datalines;
2010    1       201 
2010    1       202 
2010    2       203 
2011    3       202 
2011    4       203 
2011    5       204 
2011    6       205
2011    6       203
2011    7       206
;
run;
首先,我创建一个名为“links”的字符变量,其中包含id1和id2

data links;
    length links $ 20;
    set have;
    id2t = compress("id2_"||put(id2, 5.));
    id1t = compress("id1_"||put(id1, 7.));
    links = id2t||" "||id1t;
run;
然后,我将“links”的每个值分配给临时数组“agroup”中的一个元素。接下来,我获取agroup中的每个元素,该元素已从“links”中分配了一个值并将其与agroup的每个后续值进行比较。如果这些值有任何共同的ID1或ID2,则我将它们连接在一起,或者,如果某个值与任何其他值不匹配,则将其作为bgroup的下一个值。然后我返回agroup的下一个值,并执行相同的操作,重复该过程,直到完成所有值。最后,每个组有一个bgroup值,每个值都有来自所有成员的ID1和ids2。最后,我将这些组与原始数据集匹配,以获得组号

data final;
    array agroup[100] $200. _temporary_;
    array bgroup[100] $200. _temporary_;
    do until (eof);
        set links end=eof;
        a+1;
        agroup[a] = links;
    end;
    do k = 1 to a;
        found = 0;
        do i = k+1 to a until (found=1);
            do j = 1 to countw(agroup[k]) until (found = 1);
                if find(agroup[i], scan(agroup[k], j)) > 0 then do;
                    found = 1;
                    agroup[i] = strip(strip(agroup[k])||' '||strip(agroup[i]));
                end;
            end;
        end;
        if found = 0 then do;
            b+1;
            bgroup[b] = agroup[k];
        end;
    end;
    do until (eof2);
        set links end=eof2;
        do i = 1 to b;
            if find(bgroup[i], id2t)+find(bgroup[i], id1t) > 0 then id3 = i;
        end;
        output;
    end;
    keep year id2 id1 id3;
run;

当您考虑嵌套时:例如,如果代码< > 3 202 在代码> 3×204 /代码>上有另一个命中,那么您有<代码> 1“202 < /代码>,<代码> 3 202 < /代码>匹配,含义<代码> 1 201 < /代码>,<代码> 1 202 > /代码>,<代码>是的,这是正确的。所以只要他们有任何重叠,我想考虑他们有相同的ID3。任何想法“乔?埃莉卡,我相信你有一个“连接的组成部分”。在图论中研究的问题。乔,我还没有机会运行它,但我会在运行后对它进行评论!非常感谢你,一如既往,我要强调的是,我上面的代码在现实生活中并不有用-这是一个概念的例子。它不能充分处理多个嵌套,也不是很有效。在这个问题上有很多很好的解决方案e网。
data links;
    length links $ 20;
    set have;
    id2t = compress("id2_"||put(id2, 5.));
    id1t = compress("id1_"||put(id1, 7.));
    links = id2t||" "||id1t;
run;
data final;
    array agroup[100] $200. _temporary_;
    array bgroup[100] $200. _temporary_;
    do until (eof);
        set links end=eof;
        a+1;
        agroup[a] = links;
    end;
    do k = 1 to a;
        found = 0;
        do i = k+1 to a until (found=1);
            do j = 1 to countw(agroup[k]) until (found = 1);
                if find(agroup[i], scan(agroup[k], j)) > 0 then do;
                    found = 1;
                    agroup[i] = strip(strip(agroup[k])||' '||strip(agroup[i]));
                end;
            end;
        end;
        if found = 0 then do;
            b+1;
            bgroup[b] = agroup[k];
        end;
    end;
    do until (eof2);
        set links end=eof2;
        do i = 1 to b;
            if find(bgroup[i], id2t)+find(bgroup[i], id1t) > 0 then id3 = i;
        end;
        output;
    end;
    keep year id2 id1 id3;
run;