拼图:如何为具有交集(SAS)的联合集创建新ID

时间:2014-07-29 19:45:47

标签: sas

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

例如,ID2是在线帐号,ID2是用户登录时的IP地址。我想指定只要它是相同的IP地址或登录ID,就会为行分配相同的ID3。

我正在使用SAS进行编码。

HAVE

Year    ID2     ID1 
2010    1       201 
2010    1       202 
2010    2       203 
2011    3       202 
2011    4       203 
2011    5       204 

想要

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

2 个答案:

答案 0 :(得分:2)

这是一个通常被认为已解决的问题,但根据多重联系的可能性,不同的问题会有不同的更有效的解决方案。

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

data have;
input Year    ID2     ID1 ;
datalines;
2010    1       201 
2010    1       202 
2010    2       203 
2011    3       202 
2011    3       204
2011    4       203 
2011    5       204
2011    6       203
2011    7       205
;;;;
run;

data want;
set have end=eof;

array new_id[1000] _temporary_;
array new_id1_C[1000] _temporary_;
array new_id2_C[1000] _temporary_;

_i1 = whichn(id1,of new_id1_c[*]);
  _i2 = whichn(id2,of new_id2_c[*]);
  if not (_i1+_i2) then do;
    _eiter+1;
    _id3+1;
    put _i1= _i2= id1= id2= _eiter= _id3=;
    new_id[_eiter]=_id3;
    new_id1_c[_eiter] = id1;
    new_id2_c[_eiter] = id2;
  end;
  else do;
    if _i1 and _i2 then ;
    else do;
        _eiter+1;
       new_id1_c[_eiter] = id1;
       new_id2_c[_eiter] = id2;
       new_id[_eiter] = new_id[_i1+_i2]; *only one will be a value;
    end;
  end;

if eof then do;
  do _t = 1 to _eiter;
    id1 = new_id1_c[_t];
    id2 = new_id2_c[_t];
    id3 = new_id[_t];
    output;
  end;
end;
keep id1 id2 id3;
run;

在这里,我所做的是为每条记录,使用whichn将其匹配到数组。如果它是完全不匹配,那么它是一个新的ID;创建一个新的ID。如果这是一场完整的比赛,请继续前进。如果它是单面匹配(找到id1但id2是新的),则创建一个新行,其中添加了id2,id1和之前分配给id1的id3。

以上实际上并不完美;后来在id1和id2上的交叉将导致存在额外的ID,但它是基本概念的一个示例。有一些关于这个主题的论文容易获得,这些论文对于答案来说太长了;例如,Transitive Record Linkage(Glenn Wright,WUSS 2010)是使用哈希表来解决问题的一个很好的例子。

答案 1 :(得分:0)

这是一个我认为适用于所有案例的答案,虽然我不知道它的效率如何:

我从一个数据集开始,添加了一些更多的观察,以显示代码如何处理更多困难的案例。

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中的每个元素从“链接”中赋值,并将其与每个后续的agroup值进行比较。如果值具有任何共同的id1或id2,那么我将两者连接在一起,或者,如果值与任何其他值不匹配,则将其作为bgroup的下一个值。然后我回到agroup的下一个值并执行相同的操作,重复该过程,直到我完成所有值。最后,每个组都有一个bgroup值,每个值都有来自所有成员的id1s和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;