Showing posts with label marketing. Show all posts
Showing posts with label marketing. Show all posts

Tuesday, December 6, 2011

A new way to draw maps in SAS


SAS’s ODS Graphics technology brought the concept of layer into data visualization. We can use those SG procedures to do many tricks. Previously in SAS, a map has to be drawn from its GMAP procedure. Now we can simply use 3-4 lines of codes to sketch some maps by the scatter statement in PROC SGPLOT, such as North America or Asia.

ods html style = money;
proc sgplot data = maps.namerica noautolegend;
scatter x = x y = y / group = id markerattrs=(size=1);
xaxis grid label = ' '; yaxis grid label = ' ';
run;
proc sgplot data = maps.china ;
scatter x = x y = y /markerattrs=(size=2);
xaxis grid label = ' '; yaxis grid label = ' ';
run;



We can apply it to single countries, like China or India. For India, the aspect has to be modified a little. It can be aslo done by PROC SGSCATTER. My friend Xiangxiang has a great tutorial for this procedure.

ods html style = harvest;
proc sgplot data = maps.asia noautolegend;
scatter x = x y = y / group = id markerattrs=(size=1);
xaxis grid label = ' '; yaxis grid label = ' ';
run;

ods html style = htmlbluecml;
ods graphics on / width=6in height = 6in;
proc sgplot data = maps.india;
scatter x = x y = y /markerattrs=(size=2);
xaxis grid label = ' '; yaxis grid label = ' ';
run;
ods graphics / reset;
Thanks to SAS’s ODS group, those SG procedures always give me limitless fun

Wednesday, November 30, 2011

When Google Analytics meets SAS

Thanks to Tricia’s introduction, I recently realized that Google Analytics is such a powerful tool for web analytics or business intelligence. It will fit the special needs if we use SAS to analyze the well-structure users’ data accumulated in Google Analytics. The challenge is that Google Analytics API and SAS hardly meet each other: Google Analytics often serves web/Linux, and SAS dwells in the ecosystems of Windows/UNIX/Mainframe. On a Windows-equipped computer, I tried three methods to pull out this blog’s data from Google Analytics to SAS: they have their own pros and cons.

Method 1: CliendLogin + HTTP protocol
The Data Export API of Google Analytics has 3 types of authorization, and ClientLogin is one of them. After downloading a token, the information from Google Analytics can be received through the HTTP protocol. William Roehl has a wonderful paper to describe how to pass the authorization step and then parse the XML data by applying two SAS macros. R’s RGoogleAnalytics package and Python’s GA library are also based the similar principles.
Pros: simple and effective. A client user can choose SAS, R or Python to download data. The codes are all open-sourced and easy to get modified for any particular need.
Cons: they all need cURL to set up SSL connection while downloading data. Since cURL is not built for Windows, it’s really awkward to use cURL on a PC which could fail many attempts.

Method 2: Data Feed Query Explorer
Google Analytics API has a web portal to supply data. It uses a browser to realize the operations in the first method above.
Pros: the easiest solution. The portal provides all options for the metrics, dimensions and segments.
Cons: the data has to be re-structured in SAS. It is getting slow when displaying a lot of results.



Method 3: OAuth + Google’s Python client library
OAuth is another authorization method. To obtain the necessary client’s key and secret for this approach, Google Analytics API has to be activated from Google API Console.
Pros: this authorization method is recommended by Google. The official Python library is very fast. Data downloaded in Python can be saved as CSV and then incorporated by SAS.

Cons: a little complicated. A SAS user has to learn some Python to tweak the codes.

Google Analytics now kicks off a new web interface which has a pretty high learning curve. In my opinion, using it's Data Export API as a front-end database and SAS as a back-end analytics platform will help generate customized models.

Tuesday, October 25, 2011

NCAA football and computer rankings

I am a big fan of NCAA football. I found that in the past weeks the cold-blooded computer rankings are more accurate than the poll rankings(BCS, Harris Poll and USA Today). And they are pretty good in predicting the game results, such as the fall of Oklahoma last week.

Data and plotting
Those ranking data are available on ESPN’s website (and they are well structured data and easy to grab). I subtracted the 6 computer rankings by the overall ranking and drew those differences on a scatter plot.
-Alabama seems to have more chance to take LSU’s place.
-Although Michigan State beat Wisconsin last week, the computers still don’t favor it.
-Auburn looks very promising.
-Oklahoma State is highly possible to become #2.
One complaint about the computer ranking
I don’t like the averaging method of the 6 computer rankings used by BCS. Transformation and factor analysis may make full use of the information - SAS’s user guide provided a detailed solution by PROC PRINQUAL and PROC FACTOR.

data week9;
input @1 RK: 20. @5 TEAM: $40. AVG_bcs: PVS_bcs: $2. RK_hp: $2. PTS_hp pct_hp RK_usa: $2.
PTS_usa pct_usa AVG_computer AH RB CM KM JS PW;
cards;
/* COPY AND PASTE DATA FROM http://espn.go.com/college-football/bcs
*/
;;;
run;

data _tmp01;
set week9;
array rank[6] ah--pw;
do i = 1 to 6;
if rank[i]= 0 then rank[i] = 25;
rank[i] = rk - rank[i];
drop i;
end;
run;
proc sort data=_tmp01;
by team;
run;
proc transpose data=_tmp01 out=_tmp02;
var ah--pw;
by team;
run;

proc template;
define Style HeatMapStyle;
parent = styles.htmlblue;
style GraphFonts from GraphFonts /
'GraphLabelFont' = (", ",6pt)
'GraphValueFont' = (", ",6pt)
'GraphDataFont' = (", ",6pt);
end;
run;
proc template;
define statgraph HeatMap.Grid;
begingraph;
layout overlay / border=true xaxisopts=(label='TEAM') yaxisopts=(label='COMPUTER ALGORITHM');
scatterplot x=team y=_name_ / markercolorgradient=col1 markerattrs=(symbol=squarefilled size=32)
colormodel=threecolorramp name='s';
continuouslegend 's' / orient=vertical location=outside valign=center halign=right;
endlayout;
endgraph;
end;
run;
ods html style=HeatMapStyle image_dpi=300 ;
proc sgrender data=_tmp02 template=HeatMap.grid;
run;

Friday, October 14, 2011

What are those SAS jobs around Cary, NC?


SAS Institute is located in Cary, NC. In this job-scarce economy, an interesting question is: what job opportunities are available for a SAS user around this great company which created SAS, say, in an area of 150-mile radius. Fortunately, I found that the returned values from the omnipotent job search engine, Indeed.com, are highly digestible, although this website doesn’t provide analytics service to general public. To integrate the data from Indeed.com, I designed a macro to extract essential variables from the returned HTML pages. Then I set the time limit for the opening as the past 30 days, ‘SAS’ as keyword to search, and 100 openings to show on each returned page. I extracted 5 such pages by running this macro and eventually I obtained 500 job openings to conduct this experiment.

%macro extract(city =, state = , radius = , page = );
options mlogic mprint;
%do i = 1 %to &page;
%let j = %eval((&i-1)*100);
filename raw url
"http://www.indeed.com/jobs?q=sas%nrstr(&l)=&city+,&state%nrstr(&radius)=&radius%nrstr(&limit)=100%nrstr(&fromage)=30%nrstr(&start)=&j";
data _tmp01;
infile raw lrecl= 500 pad ;
input record $500. ;
if find(record, 'jobmap[') gt 0 and find(record, 'srcname') gt 0;
run;
data _&i;
set _tmp01;
array id[5] $50. indeed_id srcname corpname location title;
length _str $8.;
do _k = 1 to 5;
if _k = 1 then _str = "jk:";
else if _k = 2 then _str = "srcname:";
else if _k = 3 then _str = "cmpesc:";
else if _k = 4 then _str = "loc:";
else _str = "title:";
_len = length(compress(_str));
_start = find(record, compress(_str)) + _len ;
_end = find(record, ",", _start) ;
id[_k] = compress(substr(record , _start , _end - _start), "'");
end;
extract_time = datetime(); format extract_time datetime.;
drop record _:;
run;
%end;
data &city._&state;
set %do n = 1 %to &page;
_&n
%end;;
run;
data &city._&state;
retain obs extract_time corpname location title indeed_id srcname;
set &city._&state;
obs + 1;
run;
proc datasets nolist;
delete _:;
quit;
%mend;
%extract(city = cary, state = nc, radius = 150, page = 5);



Popular job titles
I used Wordle, a text cloud website to summarize all job titles. ‘Analyst’, ‘Developer’ and ‘Programmer’ seem to be quite common titles for a job related to SAS. Obviously many openings ask for experience, since they frequently mentioned ‘Senior’, ‘Manager’, or‘Management’. You can also predict the daily routines of those jobs by ‘Data’, ‘Marketing’, ‘Statistical’, ‘Risk’, ‘Database’, ‘Research’ and ‘Clinical’.

data _null_;
set cary_nc(keep=title);
string =tranwrd(upcase(title), 'SAS', ' ');
string =tranwrd(upcase(string), 'SR', 'SENIOR ');
file 'c:\tmp\output.txt';
put string;
run;
Top 10 job providers
As I expected, SAS is the biggest job provider with 18 openings in the past month, followed by Bank of America (14), Ettain Group(12) and other companies. The top job providers don’t include insurance companies, CRO or pharmaceuticals, which suggests that there are fewer local companies or they may transfer the recruiting task to staffing companies.

proc sql outobs=10;
create table _1 as
select upcase(corpname) as name, count(*) as freq
from cary_nc
where corpname is not missing
group by name
order by freq desc
;quit;

data _2;
set _1;
n + 1;
length category $10.;
if n = 1 then category = 'SAS';
else if n in (2, 6) then category = 'Bank';
else if n in(4, 9, 10) then category = 'Consulting';
else category = 'Staffing';
run;

ods html gpath = 'c:\tmp\' style = harvest;
goptions device=javaimg ftitle="arial/bold" ftext="arial"
htitle=.15in htext=.2in xpixels=600 ypixels=500;
proc gtile data = _2;
tile freq tileby = (name, freq) / colorvar = category;
run;


Location, location, location
Job accumulated in five cities for those talents who have SAS skills: Charlotte, Raleigh, Cary, Durham and Richmond. Except working for SAS Institute, Charlotte and Raleigh are the best cities for a job seeker in Center North Carolina to consider.

proc gchart data= cary_nc;
pie location;
run;


Source of job posts
Nowadays most company websites require the applicants to disclose where they get the information. In this experiment, the top 3 sites are DICE.com, Careebuilder.com and Corp-to-corp.com.

proc sql outobs=10;
create table _3 as
select upcase(srcname) as name, count(*) as freq
from cary_nc
where corpname is not missing
group by name
order by freq desc
;quit;
proc sgplot data = _3;
waterfall category = name response = freq ;
xaxis label= ' '; yaxis label=' ';
run;

Lesson learned from this weekly project
1. PROC GMAP in SAS 9.3 now supports alpha-transparency feature to draw a map -- a significant improvement.
2. Parsing online data doesn’t need to use the awesome Regular Expression syntax, although SAS has a few RE functions. SAS’s character functions are pretty robust.
3. Analyzing the online job information is quite entertaining for me. I believe that mining of those texts deeper would lead to more discoveries of secrets.

Friday, May 6, 2011

Multidimensional scaling for ZIP codes clustering


Multidimensional scaling maps the distances among multiple objects in a two or more dimensional space. This method is getting hotter in analyzing social network, since many SNS website now offer handy tools to visualize the social connections for the users. SAS’s MDS procedure, based on such an algorithm, is a fascinating tool. Larry [Ref. 1] utilized it to map SAS-L, an email list, to a circle shape, by extracting threads and email addresses. Proc MDS is also used to reflect the perceptions of customers to perceptual maps.

In business, some direct marketing activities need to scale down the levels of zip codes. For example, Texas has 2650 ZIP codes. Sometimes it is useful to divide them into manageable sectors. SAS 9.2 has built-in ZIP code and map datasets. And the ‘zipcitydistance’ function lookups the distance between any pair of ZIP codes. At the beginning, a 2650*2650 matrix, based on the distances between any two ZIP codes in Texas, was constructed. Then according to this matrix, Proc MDS calculated the two dimension variables. A following clustering procedure separated them into 5 clusters. Proc GMAP allows generating customized map [Ref. 2]. Thus by it, I annotated those dots back onto a physical map. The comparison between the two images shows the reconstructed relative locations are pretty accurate, though the map's angle by Proc MDS is not very much correct.

Reference:
1. Larry Hoyle. ‘Visualizing Two Social Networks Across Time with SAS’. SAS Global 2009.
2. Darrell Massengill and Jeff Phillips. ‘Tips and Tricks IV: More SAS/GRAPH Map Secrets’. SAS Global 2009.

/*******************READ ME*********************************************
* - MULTIDIMENSIONAL SCALING FOR ZIP CODES CLUSTERING -
*
* SAS VERSION: SAS 9.2.2
* DATE: 07may2011
* AUTHOR: hchao8@gmail.com
*
****************END OF READ ME******************************************/

****************(1) RETRIEVE MAP AND ZIP CODE DATA IN TEXAS FROM SAS ***;
data txzip;
set sashelp.zipcode;
where statecode = "TX";
run;

data txmap;
length x y 8;
set maps.counties;
where state = 48;
run;

****************(2) CREATE A ZIP-TO-ZIP DISTANCE MATRIX*****************;
proc sql;
create table zip01 as
select a.zip as zipa, b.zip as zipb,
zipcitydistance(zipa, zipb) as distance
from txzip as a, txzip as b
;quit;

proc transpose data = zip01 out = zip02 prefix = var;
by zipa;
id zipb;
var distance;
run;

****************(3) CONDUCT MDS AND CLUSTERING WITH 5 CLUSTERS**********;
proc mds data = zip02 level = absolute out = mds_done ;
id zipa;
run;

proc fastclus data = mds_done maxc = 5 out = clus_done;
var dim:;
where _name_ is not missing;
run;

proc sgscatter data = clus_zip;
plot dim1 * dim2 / group = cluster grid;
run;

****************(4) TRANSFORM ZIP CODE TO GEOGRAPHIC DATA FOR ANNOTATION**;
proc sql;
create table clus_zip as
select a.zipa as zip, a.cluster, b.x, b.y
from clus_done as a left join txzip as b
on a.zipa = b.zip
;quit;

data clus_zip1;
retain anno_flag 1;
set clus_zip;
x = -x * atan(1) / 45;
y = y * atan(1) / 45;
length function style color text $8;
function = 'label';
xsys='2'; ysys='2'; hsys='3';
when='A'; style='special'; text='L';
size = 2; position = 'E';
if cluster = 1 then color = 'blue';
else if cluster = 2 then color = 'red';
else if cluster = 3 then color = 'purple';
else if cluster = 4 then color = 'green';
else color = 'yellow';
run;

****************(5) MAP CLUSTERED ZIP CODES GEOGRAPHICALLY ******************;
data combine;
set txmap clus_zip1;
run;

proc gproject data = combine out = combined dupok;
id county;
run;

data txmap anno_dots;
set combined;
if anno_flag > 0 then output anno_dots;
else output txmap;
drop anno_flag;
run;

ods html gpath = 'c:\';
goptions reset=all dev=gif xpixels = 1280 ypixels = 1024;
proc gmap data = txmap map = txmap anno = anno_dots;
id county;
choro state / nolegend;
run;
quit;
ods html close;

****************END OF ALL CODING***************************************;
mds_to_post

Monday, August 23, 2010

Predict 3G users for telecom by using SAS Enterprise Miner


Situation: For a telecommunication company, there are a training dataset of 18,000 customers and a scoring dataset of 2,000 customers.
Task:Find potential 3G users from the existent 2G users to increase ARPU and MARPU
Action: Trained models by decision tree, neural network and logistic regression on SAS EM 5.2.
Result: Proposed tailed device and service, promotion channel, and branding image strategy for segments; Formed an ensemble model with misclassification rate <.04 and Impremented the model.


/*VERY BEGINNING: DATA TRANSFER FOR MODELING BY SAS ENTERPRISE MINER*/

options noxwait noxsync;

dm 'x "cd D:\";';

dm 'x " md mylib" ';

dm 'x "xcopy d:\matchresult\*.*/D/E/S/R/Y/A d:\mylib " ';