SAS中文论坛

标题: 如何分组? [打印本页]

作者: shiyiming    时间: 2010-6-25 11:05
标题: 如何分组?
data a;
input id $ mod $ date;
cards;
a1 tc 3
a1 td 4
a1 td 7
a1 tc 25
a1 td 27
a2 td 1
a2 tc 17
a2 tc 18
a2 td 21
a2 td 24
a3 tc 7
a3 td 16
a3 tc 18
a3 td 24
...
;
run;
现在,我想把每个ID里的tc和td以date间隔最近的分在一组,然后再在组内求tc和td的时间差,比如在ID=a1里:
id $ mod $ date group diff
a1 tc 3  1  1
a1 td 4  1  1
a1 td 7  .  2
a1 tc 2 25 3
a1 td 2 27 3
问题:请问如何分组?
谢谢!
作者: shiyiming    时间: 2010-6-25 17:00
标题: Re: 如何分组?
可以先按照id先拆成数个数据集。。

然后针对每个数据集这样处理:

proc fastclus data=a1 out=b maxc=3;
        var date;
run;

proc sort data=b;
        by cluster;
run;

proc means data=b nway noprint;
        by cluster;
        class mod;
        output out=c range=range;
run;
作者: shiyiming    时间: 2010-6-25 21:14
标题: Re: 如何分组?
上面叙述有点错误,最后形成的dataset应该如下:
现在,我想把每个ID里的tc和td以date间隔最近的分在一组,然后再在组内求tc和td的时间差,比如在ID=a1里:
id $ mod $ date group diff
a1 tc 3  1  1
a1 td 4  1  1
a1 td 7  2  .
a1 tc 25 3  2
a1 td 27 3  2
问题:请问如何分组?
sorry and thanks again.
作者: shiyiming    时间: 2010-6-26 20:53
标题: Re: 如何分组?
就是简单的聚类分析
作者: shiyiming    时间: 2010-6-27 02:38
标题: Re: 如何分组?
可否帮忙写下程序,多谢了!!!
作者: shiyiming    时间: 2010-7-10 07:04
标题: Re: 如何分组?
我写了一个code,但是有个问题,那就是一旦mod有重复值(如第2,3行的4,4),那么,我的程序就必须重新再次把剩下的record再运行一遍,否则就不完整。
所以抛砖引玉,希望有高手对我的code进行修改,或全新的code. 谢谢!!!
[code:2p8uzi98]data a0;
input mod $ bdos;
cards;
tc 1
26 4
26 4
tc 6
tc 7
tc 12
26 13
26 14
tc 17
26 19
tc 22
tc 25
26 28
tc 29
26 30
;
run;
/*add pk unid*/
data a;set a0;
pk=_n_;
unid=catx('_',mod,bdos,pk);
run;
/*split data into 2 datasets by mod*/
data a1 a2; set a;
select (mod);
when ('tc') output a1;
when ('26') output a2;
end;
run;
/*grab min(diff)*/
proc sql;
create table diff1 as
  select d1.*,abs(bdos_26-bdos_tc) as diff, catx('_',pk_tc,pk_26) as unid2,
         d2.*,(calculated diff=min(calculated diff)) as min_d
    from a1(rename=(mod=mod_tc bdos=bdos_tc pk=pk_tc)) d1,
         a2(drop=unid rename=(mod=mod_26 bdos=bdos_26 pk=pk_26)) d2
        group by unid
   having min_d^=0
    order by d1.pk_tc,unid;
quit;
proc sql;
create table diff2 as
  select d2.*,abs(bdos_26-bdos_tc) as diff,catx('_',pk_tc,pk_26) as unid2,
         d1.*,(calculated diff=min(calculated diff)) as min_d
    from a1(drop=unid rename=(mod=mod_tc bdos=bdos_tc pk=pk_tc)) d1,
         a2 (rename=(mod=mod_26 bdos=bdos_26 pk=pk_26)) d2
        group by unid
   having min_d^=0
    order by d2.pk_26,unid;
quit;
/*remove 1 record VS mulit, keep 1:1*/
proc sort data=diff1 out=diff10 nodupkey;
  by unid;
run;
proc sort data=diff2 out=diff20 nodupkey;
  by unid;
run;
/*grab 2 records with the same min(diff)*/
proc sql;
create table diff_1 as
  select d1.*
    from diff10 d1,diff20 d2
   where d1.unid2=d2.unid2;
quit;

/*add group id: g*/
data b0;
set diff_1;
g=_n_;
run;
/*separate data*/
data b1(rename=(mod_tc=mod bdos_tc=bdos) keep=mod_tc bdos_tc diff unid2 g)
     b2(rename=(mod_26=mod bdos_26=bdos) keep=mod_26 bdos_26 diff unid2 g);
  set b0;
run;

/*merge again*/
data final;
set b1 b2;
run;
/*sort dataset*/
proc sort data=final;
by g;
run;
[/code:2p8uzi98]
作者: shiyiming    时间: 2010-7-10 10:20
标题: Re: 如何分组?
不明白你到底想怎么分?为什么7单独一组,为什么。。。说白了,你到底想干什么?如果类似于聚类,显然光data step是不够了。
作者: shiyiming    时间: 2010-7-10 10:55
标题: Re: 如何分组?
也许之前我叙述的有些含糊,以现在的论述为准:假设一组数据如下(obs为序列号,不是变量,变量只有x和y):
obs x   y
1 a  1
2 b  1
3 a  5
4 b  8
5 a  6
6 a  7
想找出a和b间,y值差距最小的一对对。
比如:第一行a和第二行b,他们对应的y值之差(绝对值)(1-1=0)最小,除此以外,第一行a和任何其他b间的y值之差总大于0,任何第二行b和其他任何a间的差大于0,那么,
obs x   y
1  a  1
2  b  1
就是距离最近的一对。
同样,第四行b和第六行a间的距离最近,(8-7=1)为最小,第四行b和任何其他a间的y值之差总大于1,任何第六行a和其他任何b间的差大于0,那么,
obs  x   y
4  b  8
6  a  7
就是距离最近的一对。
最后想得到的结果就是:
obs x   y  pair
1  a  1   1
2  b  1   1
4  b  8   2
6  a  7   2
这样叙述,不知道还有没有疑义。
thanks.
作者: shiyiming    时间: 2010-7-11 00:23
标题: Re: 如何分组?
解决不了。对不起
作者: shiyiming    时间: 2010-7-11 09:46
标题: Re: 如何分组?
没关系。
其实我已经写好了一个code(见6楼),自己感觉还不错,但有一个情况下却很麻烦,那就是x或y的值一旦出现重复,那么我的code就必须重新run一遍,否则就有遗漏。所以,我就在想,如果在code里嵌入without replacement的程序,把已经出现最小值的一对x,y去除后再进行下一次的运行,这样就可以避免重复值(x或y)对取最小值的影响了。
所以,就想有人在我的code上做修改(嵌入实现without replacement的程序),或全新的code.
单纯的实现without replacement的程序,我用data step也实现了,但我的code主要是sql,所以,不知道如何嵌进去。
拜托各位高手。
作者: shiyiming    时间: 2010-7-11 11:42
标题: Re: 如何分组?
[code:2h6470s1]data raw;
        input @3 x $ y;
datalines;
1 a 1
2 b 1
3 a 5
4 b 8
5 a 6
6 a 7
2 b 1
;
data a;
        set raw(where=(x='a'));
        id=_n_;
        rename y=a_y;
run;
data b;
        set raw(where=(x='b'));
run;
data out(keep=x y pair);
        if _n_=1 then do;
                        length x $8;
                        declare hash h(dataset:'a',ordered:'yes');
                        declare hiter iter('h');
                        h.defineKey('id');
                        h.defineData('id','a_y');
                        h.defineDone();
                        call missing(id,a_y);
                end;
        set b;
        pair=_n_;
        do while(iter.next()=0);
                if diff=. or abs(y-a_y) le diff then do;
                                diff=abs(y-a_y);
                                temp_ay=a_y;
                                a_key=id;
                        end;
        end;
        rc=h.remove(key:a_key);
        output;
        x='a';
        y=temp_ay;
        output;
run;[/code:2h6470s1]
作者: shiyiming    时间: 2010-7-11 13:46
标题: Re: 如何分组?
这个问题有人工智能的意思,差不多可以认为是相亲算法。 Hopewell的hash算法很好。

不过我觉得有个问题,就是非唯一解的问题。

拿相亲举例吧,如果条件相同的两个男的,谁先出场,谁最先配到最接近的那个女的,后来的从剩下中再找。
而上面没有考虑这个问题。如调整下面数据集其中两个数的位置,得到的配对不一样。

如:在这样的数据,后面加上一个排序,结果就不一样了。
data raw;
   input @3 x $ y;
datalines;
1 a 1
2 a 5
3 a 6
4 a 10
5 b 1
6 b 9
7 b 11
;
proc sort;
by  x descending  y ;
run;

结果A:
Obs    x     y    pai
1     b     1      1
2     a     1      1
3     b     9      2
4     a    10      2
5     b    11      3
6     a     6      3

排序后结果B:
Obs    x     y    pair
1     b    11      1
2     a    10      1
3     b     9      2
4     a     6      2
5     b     1      3
6     a     1      3


所以我觉得还应该引入个排队机制,如有限解决年纪大的,就按年龄递减排队进场,先解决最符合条件的大龄者。

想想这其实是个优化问题,还引发出了继续优化的问题,同等的条件下,还要要保证下一配对条件最接近,或者下下一配对最接近..。

如上面结果B的配对教A而言教优。
作者: shiyiming    时间: 2010-7-12 21:35
标题: Re: 如何分组?
是的,我现在的问题就是,如果有重复值出现,如何把已经产生最小值的一对去除,然后再对余下的进行配对。以此类推进行下去。
谢谢上面两位的solution and comment.
作者: shiyiming    时间: 2010-7-12 21:53
标题: Re: 如何分组?
to jingju11
you can try PROC FASTCLUS
作者: shiyiming    时间: 2010-7-18 11:38
标题: Re: 如何分组?
谢谢hopewell。




欢迎光临 SAS中文论坛 (https://mysas.net/forum/) Powered by Discuz! X3.2