Gene expression data analysis often presents a major challenge: the multiplicity of variables. When it comes to comparing the expression of thousands of genes between two groups (e.g., "affected" vs "unaffected" subjects), the naive approach often involves using macros to loop over each variable.
However, this method can run into performance issues and, more insidiously, data structure errors leading to null results ($n=0$).
Imagine a dataset where each row represents a subject. You have columns for the genes of healthy individuals (unaffected_gene_x) and others for sick individuals (affected_gene_x).
If you try to use the PAIRED statement in PROC TTEST:
The Solution: Restructure the data ("Wide to Long")
Instead of creating a complex macro that runs PROC TTEST 2500 times (which is inefficient), the best practice is to restructure the data to have only a single value column and an identification column (Group/Status).
Here's how to transform your "wide" data into "long" data with a DATA step and arrays (ARRAY):
data analyse_genes;
set donnees_source;
/* Déclaration des tableaux pour vos colonnes existantes */
/* Ajustez la dimension (ici 10) au nombre réel de gènes (ex: 2500) */
array u unaffected_gene_1 - unaffected_gene_10;
array a affected_gene_1 - affected_gene_10;
/* Boucle pour pivoter les données */
do gene_id = 1 to dim(u);
/* Traitement du cas 'Non Affecté' */
if u[gene_id] ne . then do;
status = 'Unaffected';
value = u[gene_id];
output;
end;
/* Traitement du cas 'Affecté' */
if a[gene_id] ne . then do;
status = 'Affected';
value = a[gene_id];
output;
end;
end;
keep gene_id status value;
run;
/* Tri indispensable pour le traitement par groupe */
proc sort data=analyse_genes;
by gene_id;
run;
1
DATA analyse_genes;
2
SET donnees_source;
3
/* Déclaration des tableaux pour vos colonnes existantes */
4
/* Ajustez la dimension (ici 10) au nombre réel de gènes (ex: 2500) */
5
array u unaffected_gene_1 - unaffected_gene_10;
6
array a affected_gene_1 - affected_gene_10;
7
8
/* Boucle pour pivoter les données */
9
DO gene_id = 1 to dim(u);
10
/* Traitement du cas 'Non Affecté' */
11
IF u[gene_id] ne . THENDO;
12
STATUS = 'Unaffected';
13
value = u[gene_id];
14
OUTPUT;
15
END;
16
17
/* Traitement du cas 'Affecté' */
18
IF a[gene_id] ne . THENDO;
19
STATUS = 'Affected';
20
value = a[gene_id];
21
OUTPUT;
22
END;
23
END;
24
keep gene_id STATUS value;
25
RUN;
26
27
/* Tri indispensable pour le traitement par groupe */
28
PROC SORTDATA=analyse_genes;
29
BY gene_id;
30
RUN;
This transformation allows moving from a sparse structure to one optimized for group statistical analysis.
Running the T-Test Efficiently
Once the data is restructured, there is no longer a need for a macro. A single PROC TTEST procedure is sufficient, using the BY statement to process each gene separately and CLASS to define the groups.
proc ttest data=analyse_genes;
by gene_id; /* Effectue le test pour chaque gène */
class status; /* Définit les groupes (Affected / Unaffected) */
var value; /* La variable contenant la mesure */
run;
1
PROC TTESTDATA=analyse_genes;
2
BY gene_id; /* Effectue le test pour chaque gène */
3
class STATUS; /* Définit les groupes (Affected / Unaffected) */
4
var value; /* La variable contenant la mesure */
5
RUN;
This method is significantly faster than invoking the procedure thousands of times.
Automating the Retrieval of Significant Results
With thousands of tests, reading the standard output is impossible. The trick is to use ODS OUTPUT to retrieve the statistics (t-values and p-values) into a table, and then filter this table.
/* Redirection des résultats vers une table SAS */
ods output ttests = resultats_ttests;
proc ttest data=analyse_genes;
by gene_id;
class status;
var value;
run;
/* Filtrer pour ne garder que les différences significatives */
data genes_significatifs;
set resultats_ttests;
/* On filtre souvent sur la méthode Pooled ou Satterthwaite selon l'égalité des variances */
where Probt < 0.05;
run;
1
/* Redirection des résultats vers une table SAS */
2
ods OUTPUT ttests = resultats_ttests;
3
4
PROC TTESTDATA=analyse_genes;
5
BY gene_id;
6
class STATUS;
7
var value;
8
RUN;
9
10
/* Filtrer pour ne garder que les différences significatives */
11
DATA genes_significatifs;
12
SET resultats_ttests;
13
/* On filtre souvent sur la méthode Pooled ou Satterthwaite selon l'égalité des variances */
14
where Probt < 0.05;
15
RUN;
The resultats_ttests table will contain variables like tValue (t-statistic) and Probt (the p-value), allowing you to immediately identify the genes of interest among thousands.
Avertissement important
Les codes et exemples fournis sur WeAreCAS.eu sont à but pédagogique. Il est impératif de ne pas les copier-coller aveuglément sur vos environnements de production. La meilleure approche consiste à comprendre la logique avant de l'appliquer. Nous vous recommandons vivement de tester ces scripts dans un environnement de test (Sandbox/Dev). WeAreCAS décline toute responsabilité quant aux éventuels impacts ou pertes de données sur vos systèmes.
SAS et tous les autres noms de produits ou de services de SAS Institute Inc. sont des marques déposées ou des marques de commerce de SAS Institute Inc. aux États-Unis et dans d'autres pays. ® indique un enregistrement aux États-Unis. WeAreCAS est un site communautaire indépendant et n'est pas affilié à SAS Institute Inc.
Ce site utilise des cookies techniques et analytiques pour améliorer votre expérience.
En savoir plus.