10.10.08

Scrum - Agile project management



Scrum is a process skeleton that includes a set of practices and predefined roles. The main roles in Scrum are the ScrumMaster who maintains the processes and works similar to a project manager, the Product Owner who represents the stakeholders, and the Team which includes the developers.
During each sprint, a 15-30 day period (length decided by the team), the team creates an increment of potential shippable (usable) software. The set of features that go into each sprint come from the product backlog, which is a prioritized set of high level requirements of work to be done. Which backlog items go into the sprint is determined during the sprint planning meeting. During this meeting the Product Owner informs the team of the items in the product backlog that he wants completed. The team then determines how much of this they can commit to complete during the next sprint. During the sprint, no one is able to change the sprint backlog, which means that the requirements are frozen for a sprint.
There are several implementations of systems for managing the Scrum process which range from yellow stickers and white-boards to software packages. One of Scrum's biggest advantages is that it is very easy to learn and requires little effort to start using.

6.10.08

Maintaining document standards at Kreara
Prepared by Sreedevi Menon

Documentation is an integral part of clinical trial studies and maintenance of standards while preparing various documents is of utmost importance. The documents related to clinical trial study may be anything from SOPs to documents related to project management, data management, statistics or SAS.

At Kreara, all or some of such documents are prepared as per requirement of the study. The emphasis is not only to make these documents as informative as possible but also to convey the information in a concise and effective manner. Further, effort is taken to maintain the quality of the information contained and the way of presentation.

An SOP for General Documentation Guidelines is maintained at Kreara and all personnel in the organization are trained on the same. This standard operating procedure describes the various guidelines to be followed during preparation and amendment of SOPs in general. It also presents guidelines for preparation of project related documents like the naming conventions to be followed.

In addition to this, individual SOPs are maintained for each and every document and to maintain standards, templates with instructions regarding the contents, layout and formatting of the contents are maintained in a central repository. The personnel responsible for writing the documents are required to follow the format in the templates while preparing the documents. The QC personnel check for any non-compliance to templates in the document in addition to the relevance of contents. Further the QA manager is responsible to ensure that the process is followed correctly.

The personnel at Kreara are trained in the SOPs related to document writing. A great deal of exposure in the related field is provided to them so that they are capable of preparing informative and effective documents.

3.10.08

SAS COLON MODIFIER “ =: ”
Prepared by : Sujith K G.

Usually we use substr () function to select a string which starts with specific characters or for selecting a part of a string. We can also use Sas Colon Modifier “=:” for performing the same task. Both methods allow comparison of values based on the prefix of a text string. Both these methods have been explained using the following example

Here we have a dataset adverse which contains patient id and name of adverse event.

data adverse;
Input id ae $;
cards;
001 asthma
002 chesttightness
003 dizziness
004 cold
005 headache
006 dysphonia
007 commoncold
008 nausea
009 cough
;
run;

We are interested to flag the adverse events starting with “co” namely cough, cold and common cold as Yes and others as No.

This can be performed by using the SUBSTR() function as described below

data event;
set adverse;
if lowcase(substr(ae,1,2))='co' then res="Yes";
else res="No";
run;

The same purpose can be served by applying the Colon Modifier “=:” as described in the following steps

Now using, Colon Modifier the condition is,

data event;
set adverse;
if lowcase(ae) =: "co" then res="Yes";
else res="No";
run;

As can be seen from the above examples in the substring function we need to specify the position to extract the first two letters while in Colon modifier such a requirement is not needed.

25.9.08

Kreara - Location
Technopark
View SlideShare presentation or Upload your own. (tags: kreara location)
Ethical Guidelines for Clinical Research - India and the World

24.9.08

Kreara - Clinical Data management and Biomterics

21.9.08

Odds ratio
Prepared by Prajitha Nair & Sreeja E V

In order to quantify the association between the exposure and the outcome of interest the incidence of disease in a group of individuals exposed to the supposed risk factor must be compared with the incidence in a group of persons not exposed. This comparison can be summarized by calculating either the ratio of the measures of disease occurrence for the two groups, which indicates the likelihood of developing the disease in the exposed individuals relative to those unexposed.In case-control studies, it is not possible to directly estimate disease incidence in those exposed and those unexposed, since people are selected on the basis of having or not having the condition of interest, not on the basis of their exposure status. It is however, possible to calculate the odds of exposure in the cases and in the controls.The odds ratio (OR) estimates the magnitude of association between the exposure and outcome. It is defined as the ratio of odds of an event occurring in one group to the odds of it occurring in another group, or to a sample-based estimate of that ratio. These groups might be an experimental group and control group.The 2x2 contingency table showing the relationship between the exposure and the disease is presented as follows:


Probability of being exposed among cases=a/(a+c)Probability of being non-exposed among cases=c/(a+c)Odds of being exposed among cases=a/cProbability of being exposed among controls=b/(b+d)Probability of being non-exposed among controls=d/(b+d)Odds of being exposed among controls=b/dOdds ratio = (odds of being exposed among cases)/ (odds of being exposed among controls)= (a/c)/ (b/d)= (a*d)/ (b*c)
In strict terms, the odds ratio obtained tells us how many more (or less, if the exposure is associated with a reduced risk) times likely the cases are to have been exposed to the factor under study compared with the controls.

If odds ratio is equal to 1 then this implies that the condition or event under study is equally likely in both groups. An odds ratio greater than 1 indicates that the condition or event is more likely in the first group. An odds ratio less than 1 indicate that the condition or event is less likely in the first group. The odds ratio can vary from zero to infinity.

Odds Ratio using SAS
Prepared by Prajitha Nair


In the case-control study, the risk of cervical cancer was examined in relation to a gene XXXX. The status of the genes is abnormal and normal wherein normal is considered as the referent category.

Consider an example:data gene;input cat $7. genstatus $4. count;cards;case abn 119control abn 68case nor 317control nor 319;run;

ods output RelativeRisks=relrisk(where=(studytype="Case-Control (Odds Ratio)"));proc freq data=gene ;tables cat*genstatus/relrisk ;weight count;run;ods output close;

The table will be as follows:

Odds of exposure among cases=119/317Odds of exposure among controls=68/319Odds ratio= odds of exposure among cases/odds of exposure among controls =1.76

The odds ratio with respect to XXXX shows that the odds of abnormal genotype occurring in case group is 1.76 times higher than it occurring in control group. The 95% confidence interval for the odds ratio is obtained as (1.26, 2.46).The cervical cancer cases were 76% more likely to have abnormal genes than controls. In short, the odds ratio indicates that women who have abnormal genes were 76% more likely to develop cervical cancer than those with normal genes.


19.9.08

Odds Ratio when cell count is zero

Prepared by Prajitha Nair

If frequency of the counts in any one of the cell is zero then the odds ratio cannot be computed?
Consider the example:


data gene;
input cat $7. genstatus $4. count;
cards;
case abn 119
control abn 0
case nor 317
control nor 319
;
run;

ods output RelativeRisks=relrisk(where=(studytype="Case-Control (Odds Ratio)"));

proc freq data=gene ;
tables cat*genstatus/relrisk ;
weight count;
run;

ods output close;

The output will look as follows:


This can be resolved as follows:
ods output CommonRelRisks=cmnrelrisk;
proc freq data=gene ;
tables cat*genstatus/relrisk cmh ;
weight count;
run;

ods output close;

The output will be produced as:




data cmnrelrisk_1(keep=Value LowerCL UpperCL);
set cmnrelrisk;
if studytype eq " (Odds Ratio)" then if method eq "Logit **" and value ne . then output;
else if studytype="Case-Control" then if method eq "Mantel-Haenszel" and value not in (.,0.0000) then output;
format LowerCL UpperCL ODDSR8.3 value ODDSR8.3;
run;


The cmh option will help to tackle the problem. The logit method will add 0.5 in all the cells of the 2 x 2 cross tabulation table where zero is in anyone of the cell and then odds ratio is evaluated.

Thus the odds ratio obtained is 240.5
06.

4.9.08

Kreara - Preclinical research services


26.5.08

Understanding the %pageXof Y macro

Compiled by Rupesh R

The following macro needs to be applied for the purpose of presenting page numbers in Page X of Y format within the body of the document.

When calling the macro, the proc report code should be quoted by %nrstr as explained in step 1.a below. To avoid clutter of code, here the proc report code is created as a macro. This proc report code should contain a ‘compute before_page_’ block as described in the step 5 below.

%macro pageXofY (report= /* proc report code, quoted by %nrstr */ /*1.a*/
, dummy=dummy /* name of the dummy output file */
);
%global page pages len; /* 1.b*/


/-- first run --*/
%let page = 0;
%let len = 8; /* 1.c*/
filename _dummy &dummy.; /* 1.d*/
proc printto print = _dummy; run; /*1.e*/
%unquote (&report.) ;/* 1.f*/
proc printto; run;/*1.g*/
filename _dummy clear; /*1.h*/

%*-- second run --*;
%let pages = &page.; /*1.i*/
%let page = 0;/*1.j*/
%let len = %eval(%length(&pages.) * 2 + 4); /* 1.k*/
%unquote(&report.);/*1.l*/
%mend pageXofY;

Explanation of Macro
Step 1 (1.a): Using %nrstr function we mask the special characters and mnemonics .Here we mask & and % symbols in the proc report code.

Step 2 (1.b): Initialize three global macro variables
§ The variable ‘page’ returns the current page number
§ The variable ‘pages’ returns the total number of pages
§ The variable ‘len’ returns the expected length of the string ‘_XofY’ (2.c) .

Step 3 (1.c): The initial values of macro variables ‘page’ and ‘len’ are assigned as 0 and 8 respectively.

Step 4 (1.d): A dummy file path is defined for the output of proc printto

Step 5 (1.e): PRINTTO procedure is used for printing the output in the specified dummy file (_dummy).

Step 6 (1.f): The proc report code created for generating the output is executed using %unquote function in this step.

%UNQUOTE is to restore normal tokenization of a value whose tokenization was altered by a previous macro quoting function. %UNQUOTE takes effect during macro execution. If the value is not unmasked before it reaches the SAS compiler, the DATA step does not compile correctly and it produces error messages.

1) Execute the entire report procedure and generate an output to the specified file path “&dummy.”

2) In report procedure we should include the following set of statements.

compute before/after _page_;
call execute('%let page = %eval(&page. + 1);'); /* 2.a*/
length _XofY $&len.; /* 2.b. */
_XofY = symget('page') ' of ' symget('pages');/*2.c*/
line 'page ' _XofY $&len..; /* 2.d. */
endcomp;
3) Before/After each page of reporting the variable ‘page’ is calculated and so when we exit from this procedure the macro variable ‘page’ has the value of total number of pages. (i.e. The initial value of ‘page’ is ‘0’ when it comes to the first page of file then it becomes ‘1’ and so on, see step (2.a))
4) We get the total pages of report in variable ‘page’.Here the variable “pages” is not initialized. So symget (‘pages’) will return nothing
Step 7 (1.g): Exit the printto procedure and SAS reset the file path to the output window (by default).

Step 8 (1.h): Clear the dummy file.

Step 9 (1.i): Assign the current value of variable ‘page’ to the macro variable ‘pages’. i.e. we assign the total number of pages to the variable ‘pages’

Step 10 (1.j): Reset the variable ‘page’ to ‘0’.

Step 11 (1.k): Calculate the approximate length of the variable ‘_XofY’ based on current value of ‘pages’.

Step 12 (1.l): Re-execute the report procedure for getting the output as per the requirement.
1) Execute the entire report procedure and generate output in the specified path given in the ods rtf file statement.
2) This time the compute block call the ‘page’ value as the current page and ‘pages’ as the total number of pages. So we will get the page number as Page X of Y form.
The following example illustrates the above macro.Here we get page X of Y on the top of each page.

data one;
do var = 1 to 100;
output;
end;
run;

%Macro Report;
proc report data=one nowd;
column var;
define var / display;
compute before _page_;/*2.a*/
call execute('%let page = %eval(&page. + 1);'); /* 2.b*/
length _XofY $&len.; /* 2.c. */
_XofY = symget('page') ' of ' symget('pages');/*2.d*/
line 'page ' _XofY $&len..; /* 2.e. */
endcomp;
run;
%Mend Report;

/* example usage */

options linesize=64 nonumber nodate;
%pageXofY(report=%nrstr(%Report));

16.4.08

Different ODS Footers

If suppose we have ten observations and we are required to present the output such that the observation are distributed on different pages depending on the value of the variable “order”. Also the different pages need to have different footers , footers being presented in the body of the document.As a first step, a variable "page" is created which represents the page number corresponding to the observation in the dataset as described below.

data catval1;
set catval end=eof;
if order le 4 then page=1;
else if 5 le order le 7 then page=2;
else if order ge 8 then page=3;
run;

The footers can be presented in the body of the document using compute before /after statements in proc report as below.

proc report data= catval1 ;
column order var1 var2 ;
………………………………
………………………………
Other SAS statements;
…………………………………
………………………………..
compute before page;
If page=1 then footer= "\li75 @ Subjects who select more than one race” ;
If page=2 then footer=" ";
If page=3 then footer="\li75 + BMI = Weight (kg) / [Height (m)]^2";
endcomp;

/*here _page_ is the SAS generated variable */

compute after _page_ / style=[just=l protectspecialchars=off];
footer11= footer;
footer12="\li75 # Overall p-value for continuous variables “
footer13="\li for Categorical variables from CMH general association test";
line @1 footer11 $300.;
line @1 footer12 $300.;
line @1 footer13 $300.;
endcomp;

/* this will give different footers in each page*/
by page;
run;

The first page will contain the following footers

@ Subjects who select more than one race
# Overall p-value for continuous variables
for Categorical variables from CMH general association test

The second page will contain the following footers

# Overall p-value for continuous variables
for Categorical variables from CMH general association test

The third page will contain the following footers
+ BMI = Weight (kg) / [Height (m)]^2
# Overall p-value for continuous variables
for Categorical variables from CMH general association test

NOTE: Groups are not created because the usage of parameter is DISPLAY.

A SAS dataset named subject is created. The SAS code for the creation of the dataset subject is as follows:
data subject;
input patid name$ sex$ visit $ parameter$ result $;
cards;
0101 lisha f Screening weight 65
0101 lisha f Screening height 150
0101 lisha f Visit1 weight 66
0101 lisha f Visit1 height 150
0102 manu m Screening weight 80
0102 manu m Screening height 165
0102 manu m Visit1 weight 80
0102 manu m Visit2 height 165
;
run;

The aim is to summarize the values across a single observation. The template is as follows:

When using the following code, the output is generated but a Note is also generated in the log as mentioned below:

proc report data=subject nowindows;
column patid name sex visit parameter result;
define patid/"Patient Number" group;
define name/"Subject Number" group;
define sex/"Sex" group;
define visit/"Visit" group;
define parameter/"Test" display;
define result/"Values" display;
run;

The SAS log will look like as follows::
1
2
3 data subject;
4 input patid name$ sex$ visit $ parameter$ result $;
5 cards;
NOTE: The data set WORK.SUBJECT has 8 observations and 6 variables.
NOTE: DATA statement used:
real time 0.01 seconds
cpu time 0.00 seconds
14 ;
15 run;
16
17 proc report data=subject nowindows;
18 column patid name sex visit parameter result;
19 define patid/"Patient Number" group;
20 define name/"Subject Number" group;
21 define sex/"Sex" group;
22 define visit/"Visit" group;
23 define parameter/"Test" display;
24 define result/"Values" display;
25 run;
NOTE: Groups are not created because the usage of parameter is DISPLAY.
NOTE: There were 8 observations read from the data set WORK.SUBJECT.
NOTE: PROCEDURE REPORT used:
real time 0.01 seconds
cpu time 0.01 seconds

A note is produced in the SAS log “NOTE: Groups are not created because the usage of parameter is DISPLAY.”
To remove this note from the log the following code should be used.

proc report data=subject nowindows;
column patid name sex visit parameter result;
define patid/"Patient Number" order;
define name/"Subject Number" order;
define sex/"Sex" order;
define visit/"Visit" order;
define parameter/"Test" display;
define result/"Values" display;
run;

The log is generated as
1
2
3 data subject;
4 input patid name$ sex$ visit $ parameter$ result $;
5 cards;
NOTE: The data set WORK.SUBJECT has 8 observations and 6 variables.
NOTE: DATA statement used:
real time 0.00 seconds
cpu time 0.00 seconds
14 ;
15 run;
16
17 proc report data=subject nowindows;
18 column patid name sex visit parameter result;
19 define patid/"Patient Number" order;
20 define name/"Subject Number" order;
21 define sex/"Sex" order;
22 define visit/"Visit" order;
23 define parameter/"Test" display;
24 define result/"Values" display;
25 run;
NOTE: There were 8 observations read from the data set WORK.SUBJECT.
NOTE: PROCEDURE REPORT used:
real time 0.00 seconds
cpu time 0.00 seconds


The SAS log is now free of the notes, errors and warnings. Instead of using the group variable, use order with display in the define statement.
Applying Cochran-Mantel–Haenzel (CMH) general association test

Compiled by Rupesh R

Here the objective is to determine the general association between categorical variables subject and ranking for each emotion.

The CMH general association test is applied for this purpose. Proc freq is as described below to carry out the test. Proc freq generates p-values corresponding to each emotion and the results are outputted to the dataset hypnosis1.


The dataset is created as follows


data hypnosis;
input subject emotion $ ranking @@;
cards;
1 fear 4 1 joy 3 1 sadness 1 1 calmness 2
2 fear 4 2 joy 2 2 sadness 3 2 calmness 1
3 fear 3 3 joy 2 3 sadness 4 3 calmness 1
4 fear 4 4 joy 1 4 sadness 2 4 calmness 3
5 fear 1 5 joy 4 5 sadness 3 5 calmness 2
6 fear 4 6 joy 3 6 sadness 2 6 calmness 1
7 joy 4 7 joy 1 7 sadness 2 7 calmness 3
8 joy 3 8 joy 4 8 sadness 2 8 calmness 1
;
run;


The following code is used to carry out the analysis. The option ‘cmh’ in the ‘tables’ statement carries out the test. The option ‘cmhga’ presents the P-value for CMH General Association without a warning in the log.


proc sort;
by emotion;
run;



proc freq;
tables subject*ranking / cmh;
by emotion;
output out=hypnosis1 cmhga;
run;


The dataset hypnosis1 is obtained as follows





























emotion_CMHGA_DF_CMHGAP_CMHGA
calmness14140.449711056
fear10100.440493285
joy20.25210.505479124
sadness21210.458944209


In the dataset p_cmhga will be labeled as ’ P-value for CMH General Association’; df_cmhga as “DF for CMH General Association” and _cmhga_ as “CMH General Association” .

15.4.08

Using just=dec for alignment of decimals

Compiled by Prajitha Nair

We have a column in proc report with either 1 or 2 digits right of the decimal and an uncertain number of digits to the left. For enhanced output, the values have to be presented such that they are aligned with respect to the decimal point.

When the display value contains a decimal point, we can use just=dec to align the numbers directly. The JUST=DEC option can be used to align the decimal points in the values in a column

define colname / display "Column/header" style=[just=dec];

where colname is the name of the column name as specified in the SAS.

If we are using ods rtf tags then we can use the pretext option for the purpose

define colname /display “Column Header”

style(column)={pretext="\qj\tqdec\tx1200" protectspecialchars=off just=center};

Extracting Engine and Path name of the code
Compiled by Prajitha Nair




The input parameter in the macro will be the name of the SAS file whose path is to be determined.

%macro PathbyName(progName);

%global fullPath fullPath1 engine;
%if %index(%upcase(&progName),.SAS) eq 0 %then
%let progName=&progName..sas;

proc sql noprint;
select xpath into :fullPath
from dictionary.extfiles where
index(upcase(xpath),"%upcase(&progName) " ) gt 0 ;
select setting into :engine from sashelp.voption
where optname="ENGINE";
quit;

%let engine = %trim(&engine);
%put engine = &engine;
%let fullpath = %trim(&fullPath);

%put fullpath = &fullPath;

%mend PathbyName;

Accessing the current working directory where the file containing the SAS code is stored


Compiled by Prajitha Nair


Let the SAS editor containing the code be KR-PH-XXX-SAS-Init.sas and it is stored in a folder named SAS Programs_Final.


The following %let statements assigns the folder and editor names to macro variables pgmfld and pgm respectively.


%let pgmfld = SAS Programs_Final; /*Folder in which SAS code is stored*/
%let pgm= KR-PH-XXX-SAS-Init.sas; /*Name of the program editor*/


The following macro is then used to extract the path of the editor from sashelp.vextfl and determine the path of the folder as “dir1” and of the editor as “dir2”.


%macro filePath;
%global fpath maxRef;

proc sql noprint;
select xpath into :fPath
from sashelp.vextfl where xpath ? "&pgm";
quit;


%let fpath = %trim(&fpath);
%put &fpath;
%global dir1 dir2 pgm1 pgmfld1;
%let pgm1 =%trim(&pgm);
%let pgmfld1= %trim(&pgmfld);


data _null_;
x=length("&fpath")-length("&pgm1");
y=length("&fpath")-length("&pgm1")-length("&pgmfld1")-1;
call symput("dir2" ,trim(substr("&fpath",1,x)));
call symput("dir1" ,trim(substr("&fpath",1,y)));
run;


%mend filePath;


This macro helps in determining the path of the code and enables the code to be executed in any computer provided the SAS code is saved within a folder and the naming conventions are followed as above.

14.3.08

15.2.08

New Abode

Finally after three years of exemplary hard work of all the present & past employees of KREARA, our dream of a beautiful new office came to frution on January 27th 2008. Thanks to all our clients and employees who have helped us make this dream come true



23.11.07

Randomisation - Data sets

Compiled by Prajitha Nair
Here is a piece of code that will generate mock randomisation list that the programmers could use to generate the outputs before unblinding the data


/*Creating the dummy dataset for randomisation*/

Proc format;
value treat 1='Test'
2='Reference'
3='Placebo';
run;

/*Randomly assigning medical kit number to treatments*/
proc plan seed=111605;
factors medkit_no=220 random block=1 random/noprint;
output out=first;
treatments treat=3 cyclic (1 2 3 );
run;

proc sort data=first out=rand_trt;
by medkit_no;
run;

data rand_trt(keep=medkitno treat);
set rand_trt;
medkitno=put(medkit_no, z3.);
format treat treat.;
run;


/*merge to get the randomised patient included in the study*/
proc sort data=rand_trt;
by medkitno;
run;

proc sort data=medkit_alloc;/*sas dataset imported from mysql*/
by medkitno;
run;

data formo.randl;
merge rand_trt(in=a) medkit_alloc(in=b);
by medkitno;
run;