如何在SAS中同时包含字符和数字变量的表上进行聚类分析?

时间:2018-09-04 12:00:01

标签: sas

Account_id <- c("00qwerf1”, “00uiowe3”, “11heooiue” , “11heooihe” , 
"00sdffrg3”, “03vthjygjj”, “11mpouhhu” , “1poihbusw”)

Postcode <- c(“EN8 7WD”, “EN7 9BB”, “EN6 8YQ”, “EN8 7TT”, “EN7 9BC”, “EN6 
8YQ”, “EN8 7WD”, “EN7 7WB) 

Age <- c(“30”, “35”, “40”, “50”, “60”, “32”, “34”, “45”)

DF <- data.frame(Account_id, Postcode, Age)

我想对SAS中的数据框进行聚类分析。我了解从技术上讲,SAS中不使用数据框,但是我只是出于说明目的使用了这种格式。 Account_idPostcode都是字符变量,Age是数字变量。

下面是我执行数据步骤后使用的代码;

Proc fastclus data=DF maxc-8 maxiter=10 seed=5 out=clus;
Run;

聚类分析不起作用,因为Account_idPostcode是字符变量。有没有办法将这些变量更改为数字变量,或者有一种可以同时使用字符和数字变量的聚类方法?

2 个答案:

答案 0 :(得分:0)

在进行聚类之前,需要定义一个可用于计算观察值之间距离的度量。默认情况下,proc fastclus使用Euclidean metric。这就要求所有输入变量都是数字变量,并且如果将它们全部重新缩放以具有相同的均值和方差,则它们将发挥最佳作用,以便它们在聚类增长时都同样重要。

如果要为每个邮政编码执行单独的聚类分析,则可以在by语句中使用邮政编码,但是如果要将邮政编码本身用作聚类变量,则需要将其转换为数字形式。用两个变量替换邮政编码质心的经度和纬度可能是个不错的选择。

对于您的帐户ID变量而言,什么是一个好的选择并不那么明显,因为这似乎并不能衡量任何事情。我会尝试掌握帐户创建日期或上次活动日期之类的其他信息,这些可以更明显的方式转换为数值。

答案 1 :(得分:0)

您可以确定每个变量的唯一值,然后为fastclus分配原始值的序数作为数字表示形式。

示例代码

注意:FASTCLUS seed =选项是一个数据集说明符,而不是一个简单的数字(与随机数生成器一起使用)

* hacky tweak to place your R coded data values in a SAS data set;
data have;
  array _Account_id(8) $20 _temporary_ ("00qwerf1", "00uiowe3", "11heooiue" , "11heooihe" , 
"00sdffrg3", "03vthjygjj", "11mpouhhu" , "1poihbusw");

  array _postcode(8) $7 _temporary_ ("EN8 7WD", "EN7 9BB", "EN6 8YQ", "EN8 7TT", "EN7 9BC", "EN6 
8YQ", "EN8 7WD", "EN7 7WB");

  array _age (8) $3  _temporary_ ("30", "35", "40", "50", "60", "32", "34", "45");

  do _n_ = 1 to dim (_account_id);
    Account_id = _account_id(_n_);
    Postcode = _postcode(_n_);
    Age = _age(_n_);
    output;
  end;
run;

* get lists of distinct values for each variable;
proc means noprint data=have;
  class _all_;
  ways 1;
  output out=have_freq;
run;

* compute ordinal of each variables original value;
data have_freq2;
  set have_freq;
  if not missing(Account_id) then unum_Account_id + 1;
  if not missing(Postcode) then unum_Postcode + 1;
  if not missing(Age) then unum_Age + 1;
run;

* merge back by original value to obtain ordinal values;
proc sql;
  create table have_unumified as
  select 
    Account_id, Postcode, Age
   , (select unum_Account_id from have_freq2 where have_freq2.Account_id = have.Account_id) as unum_Account_id
   , (select unum_Postcode   from have_freq2 where have_freq2.Postcode = have.Postcode) as unum_Postcode
   , (select unum_Age   from have_freq2 where have_freq2.Age = have.Age) as unum_Age
   from have
   ;
run;

* fastclus on the ordinal values (seed= not specified);
Proc fastclus data=have_unumified maxc=8 maxiter=10 out=clus_on_unum;
  var unum_:;
Run;