如何为任何重叠的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
答案 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;