mardi 14 décembre 2010

Heritage de tables

En statistique nous sommes souvent confronté à trois grands types de variables:
- Binaire
- Catégorielle (qualitative)
- Quantitative (continue ou discrète).

Lorsque l'on doit stocker ce type de variable dans une base de donnée, il serait tentant d'utiliser trois tables différentes et de stocker le type de la variable dans une table de définition des variables:
-- Définition de la variable (métadonnée)
tblVariable
VarID int;
type int; (1-Binaire, 2-Categorielle, 3-Quantitative)
Code varchar(10)

-- valeur de la variable binaire
tblBinaire
ID int;
VarID int;
Valeur BIT;

-- valeur de la variable catégorielle
tblCategorielle
ID int;
VarID int;
Valeur varchar(10);

-- valeur de la variable quantitative
tblQuantitative
ID int;
VarID int;
Valeur DECIMAL 10.4;

Le problème de cette approche est qu'il est difficile de créer une intégrité référencielle entre la table Variable et les autres tables puisque le type de variable définira avec quelle table on doit faire le lien et donc les ID entre les différentes tables pourront se recouvrir. Il est donc difficile de définir une FOREIGN key entre 3 tables pouvant avoir des ID Identique et une table source...

Une approche plus simple pourrait considérer la table variable comme une table de base dont hérite les autres tables.

CREATE TABLE tblVariable
(
varid SERIAL PRIMARY KEY,
Code varchar(10);
)

CREATE TABLE tblVariableInst
(
id SERIAL PRIMARY KEY, -- idéalement autonumber
varid INT
FOREIGN KEY (varid) REFERENCES tblVariable(varid)
)

CREATE TABLE tblBinaire
(
id INT UNSIGNED PRIMARY KEY NOT NULL,
Valeur BIT,
FOREIGN KEY (id) REFERENCES tblVariableInst(varid)
)

CREATE TABLE tblCategorielle
(
id INT UNSIGNED PRIMARY KEY NOT NULL,
Valeur Varchar(10),
FOREIGN KEY (id) REFERENCES tblVariableInst(varid)
)

CREATE TABLE tblQuantitative
(
id INT UNSIGNED PRIMARY KEY NOT NULL,
Valeur NUMERIC 10.4;
FOREIGN KEY (id) REFERENCES tblVariableInst(varid)
)

Pour créer une nouvelle variable liée à une variable modèle 1234 par exemple.
@var_id=INSERT INTO tblVariableInst (1234) RETURN ID
INSERT INTO tblQuantitative (@var_id, 9.25)

Ces deux lignes devront être placée dans une transaction, pour éviter d'avoir des ID de VarInstance perdu en cas de problème.

L'avantage de cette approche est que l'intégrité référentielle est parfaitement maintenue entre la table de définition tblVariable (métadonnée) et les tables filles.

Rmk: En sql server on utilisera @@IDENTITY_SCOPE pour obtenir l'ID crée dans la table de base. Par contre en PostgreSQL il est possible de demander au INSERT de retourner le dernier ID crée. L'ID crée pour toutes les tables filles est stocké dans la table tblVariableInst (Variable instance) qui contient une clé étrangère sur la table de définition.

vendredi 10 décembre 2010

Comprendre la nullité

La valeur NULL (pour SQL) ne signifie pas 0, FALSE ou chaine vide. Il s'agit d'une erreur classique dans le développement.
NULL signifie indéterminé ou inconnu. Beaucoup de développeurs ont cette incompréhension de l'inconnu.

Exemple:

date
13/10/2010
NULL
13/12/2010

SELECT COUNT(DATE) where DATE<'13/12/2010' retournera 1 et non pas 2.
Car NULL représente une date inconnue et pas une date nulle (par ex 31/12/1899), comme la date est inconnue il est impossible de savoir si elle est plus petite ou plus grande que le 13/12/2010. Un autre exemple, si je dit que Jacques à 32 ans et que Pierre à un age à NULL. Dans ce cas de figure, cela signifie que l'age de Pierre n'a pas été entré dans le système. Si je demande si Jacques est plus vieuw que Pierre la réponse sera je ne sais pas.
=> Comparer un numérique avec un NULL donne un résultat indéterminé.
Si maintenant je ne connais pas l'age d'Alain. Comme savoir si Alain est plus vieux que Pierre, après tout ils ont peut-être le même age.
=> Comparer un NULL avec un NULL donne un résultat indéterminé.

Si j'ajoute l'age d'Alain à celui de Jacques le résultat peut aussi être n'importe quoi et ne sera certainement pas32
NULL{+,-,*,/}Nombre donne un NULL.
Même chose avec les concaténation de chaine de caractères. Concaténer un NULL avec une autre chaîne donne une chaîne indéterminée.

Cas particuliers dans les opérations booléennes:
NULL true=true
NULL & false=false

Toutes les autres opérations incluants des NULL donnent des NULL.

mardi 7 décembre 2010

Eclipse et Tomcat sous Debian lenny

Il y a quelques temps j'ai commencé quelques développements en Java, Tomcat et Postgre SQL sous Debian Lenny. Tout semblait fonctionner pafaitement, je pouvais lancer et arrêter le démon Tomcat à partir d'Eclipse et effectuer du debugging sans problèmes. Toutefois, quelques mise à jour de Lenny plus tard, à chaque tentative de démarrage du démon, je me retrouvais avec le message suivant:

SEVERE: Class loader creation threw exception
java.lang.InternalError: One of the management beans is not compliant.
at java.lang.management.ManagementFactory.getPlatformMBeanServer(libgcj.so.90)
at org.apache.catalina.startup.Bootstrap.createClassLoader(Bootstrap.java:183)
at org.apache.catalina.startup.Bootstrap.initClassLoaders(Bootstrap.java:92)
at org.apache.catalina.startup.Bootstrap.init(Bootstrap.java:207)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:391)
Caused by: javax.management.NotCompliantMBeanException: MBean is not compliant
at mx4j.server.MX4JMBeanServer.registerImpl(MX4JMBeanServer.java:818)
at mx4j.server.MX4JMBeanServer.registerMBeanImpl(MX4JMBeanServer.java:769)
at mx4j.server.MX4JMBeanServer.registerMBean(MX4JMBeanServer.java:753)
at java.lang.management.ManagementFactory.getPlatformMBeanServer(libgcj.so.90)
...4 more


ce qui est assez ennuyeux vous en conviendrez...
Le problème est lié au fait que l'installation du jre effectuée est indépendante de la distribution Debian Lenny. Donc lorsque certaines mise à jour sont effectuées, le jre quant à lui n'est pas remis à jour ce qui peut poser rapidement des problèmes de compatibilités.

Le plus simple est donc d'installer un jre plus récent et plus ... standard.
Le jre par défaut sur Lenny est le gcj (du gnu) qui a l'avantage d'être complètement libre de license, mais qui n'est pas le plus efficient.

Le plus simple est donc d'installer le jre de java.
J'ai opté pour la version: jre-6u22-linux-i586.bin
Le plus simple est de la télécharger dans le répertoire utilisateur.
Ensuite en mode utilisateur:
$chmod a+x jre-6u22-linux-i586.bin
Puis en mode root
#mkdir /usr/java
#cd /usr/java
#/home//jre-6u22-linux-i586.bin
Le fichier va s'extraire tout seul.
Une fois le nouveau JRE installé il faut le faire reconnaître par Eclipse.
Window/Preference/Java/Installed JREs
Cliquer sur ajouter. Donnez le nom jre-6u22-linux-i586 et indiqué le path d'origine /usr/java/jrel-6.0_22
Déselectionnez le JRE gcj et sélectionnez le nouveau.

Aller dans
Window/Preference/Tomcat/JVM setting
dans la combo box, choisir le nouveau JRE jre-6u22-linux-i586
Ajouter un nouveau ClassPath
/usr/java/jrel-6.0_22
Et supprimer l'ancien

Voilà maintenant le démon Tomcat devrait pouvoir être à nouveau piloté par Eclipse et le debugging à nouveau rendu possible...

vendredi 17 septembre 2010

Creational Pattern (2)

2) Builder

Le builder est utilisé pour créer un objet complex indépendamment de sa représentation. Ainsi on pourra créer le même processus de construction pour générer des représentations différentes.

Cas d'utilisation:
Le ReaderRTF : le reader RTF parse un fichier RTF et traduit les formattages, soit il n'y a pas de formattage (plain-text), soit il faut les afficher en Html, Latex, ...

Dans ce cas de figure deux operations apparaissent : le parsing et l'affichage.
Nous allons donc créer deux classes:
La classe Director qui contient l'algorithme de parsing du fichier RTF
Et une classe Builder (abstraite) qui contient les méthodes d'affichage (ex: ConvertCharacter, ConvertFont, ConvertParagra...)
Les autres classes builder vont dériver de celle-là, exemple : ASCIBuilder, HtmlBuilder ou LatexBuilder (ConcreteBuilder). Les méthodes de la classe abstraites seront outrepassées et permettront d'afficher le document RTF, soit en text, soit en html ou soit en représentation graphique.

L'avantage du système est que le parsing peut générer plusieurs représentation, toutefois, il est aussi possible de changer l'algorithme de parsing et de ré-utiliser la même représentation.

Exemple du labyrinthe:
L'abstract builder contiendra les méthodes: BuildRoom, BuildDoor. Les concrete builder implémenteront concrètement la création des Room et des Door.
La classe MazeGame contiendra l'algorithme de création (Director) et définira quel room et quelles portes créer afin de générer un labyrinthe complexe.
L'abstract class builder contiendra une fonction GetMaze qui renverra le labyrinthe. La classe MazeBuilder sert donc uniquement à créer, elle renvoit ensuite l'instance de l'objet crée dans ce cas ci un objet de type Maze.

Application dans TrialXS:
Le pattern utilisé dans l'export crée en 2002, à l'époque, je ne savais pas quel nom leur donner c'est pourquoi la dénomination peut paraître étrange.
Le but de l'export est d'extraire des données relatives aux patients et de les exporter dans différents (text, SAS ou CDISC).

L'Export est composé d'une classe d'extraction des données appelée:
TPatientItemProvider (Director)
Cette classe contient toute la mécanique d'extraction des CRF relatifs aux patients, chaque fois qu'un CRF existant est complété elle appelle la méthode CollectData de la classe builder.
Si il s'agit d'un nouveau CRF non existant, on appellera la méthode : CollectStructure qui construira un nouveau CRF.

La méthode CollectData fait partie de la Classe TFormExport. Cette classe est l'abstract builder.
Différent builder en dérivent, tels que TFormSASExport, TFormFlat ou TCDISCExport. Cette classe n'est pas vraiment un abstract builder puisqu'elle est déjà le produit en tant que tel. Pour réaliser le pattern on aurait dû avoir une clasee TFormBuilder.getFormExport qui aurait renvoyé les TFormExport crées.

A la fin de la construction, le composite produite sera une liste de CRF défini dans une structure particulière (soit de simple fichier texte, soit des fichiers text avec un fichier de définition, soit une structure xml).

Autres exemples: TCVisitPlanBuilder: Cette classe construit un visit plan théorique en tenant compte des visites model et des visit instances. Encore une fois, il s'agit d'un cas particulier car le Director et le Builder sont aggrégés dans la même classe. Mais l'idée reste la même assurer la création d'un objet complexe à partir d'une autre classe.

Un pattern de type Builder génère en général un Composite.

mercredi 15 septembre 2010

Creational Patterns

1) Abstract factory :

Utilisé pour gérer de multiples look & feel ou source de données, on évite de créer des instances d’une classe particulière directement dans l’application. On passe par une classe intermédiaire qui se charge de créer les objets pour nous.

Nous allons appliquer ce pattern à TrialXS. Supposons que nous voulions rendre l’application indépendante du type de server de base de données (ce qui complique la tâche). Nous allons considérer deux server de base de données SQL Server et Oracle.

Exemple :
// Abstract Factory
TDBObjectFactory=class
function CreateProject :TProject;virtual;
function CreatePatient;TPatient;virtual;

End;
// Abstract Product
TDBObject=class
Procedure get;virtual;
Procedure Save;virtual;
Function createsql:string;virtual;
End;
TProject=class(TDBObject)
property BaseLine : integer read fBaseLine;
end;
TPatient=class(TDBObject)
end;
// Concrete Product
TSqlProject=class(TProject)
Function createsql:string;override //Contient le sql de creation de l’objet pour Sql server
Function Save ;override ;
Function get ; override ;
End ;
// Concrete product
TOraProject=class(TProject)
Function createsql:string;override //Contient le sql de creation de l’objet pour Oracle
Function Save ;override ;
Function get ; override ;
End ;
// Concrete Factory
TSqlObjectFactory =class(TDBObjectFactory)
Function CreateProject ;override; // Retourne un objet TSqlProject
function CreatePatient;override;
End;
// Concrete Factory
TOraObjectFactory=class(TDBObjectFactory)
function CreateProject ;override; // retourne un objet TOraProject
function CreatePatient;override;
End;

Dans l’initialisation de l’application

Var
ObjectFactory:TDBObjectFactory;
begin
If db_type=sql then
ObjectFactory:=TSqlObjectFactory.Create;
Else
ObjectFactory:=TOraObjectFactory.Create;
End;

Chaque fois que je crée un objet db dans l’application, je passerai par l’objet ObjectFactory. En faisant soit

Var
Project :TProject ;
begin
Project :=ObjectBuilder.CreateProject ;
Project.get;
end;

Ceci Va me donner un objet de type SqlProject ou OraProject suivant le type de serveur sql utilisé. Partout dans l’application j’utiliserai l’interface de TProject en me moquant de savoir si j’ai un OraProject ou un SqlProject puisqu’ils réalisent tous deux la même interface. Ce système, certe plus lourd à le mérite d’éviter les castings.

Cela signifie que le type de server sql est défini une fois, partout ailleurs dans l’application je me ficherais de savoir si j’utilise Oracle ou SQL Server puisque c’est l’instance de la classe TDBObjectFactory (ObjectFactory) qui appellera les bon constructeur de classe.
Mon application sera donc indépendante du server de base de donnée pour récupérer ses objets.
TDBObjectFactory ou TDBObject sont généralement considérées comme des classes abstraites ou des interfaces, elles ne peuvent pas être instanciée directement.

Avantage: permet de changer toute une famille de produit en une fois.
Inconvénient:Il n'est pas facile d'ajouter un nouveau produit, car il faut updater et créer plusieurs classes. (pas très flexible)

On utilise souvent l'abstract Factory avec le pattern Singleton, car on ne doit avoir qu'une instance de la Concrete Factory.

On appelle également ce pattern :Kit ou Usine (terme français pour Factory)

vendredi 10 septembre 2010

Validation des Systèmes Informatiques

Définition de la validation:

"Etablir des preuves documentées qui fournissent un haut degré d'assurance qu'un processus spécifique produira constamment a produit conforme à ses spécifications pré-déterminées et à ses attributs qualificatifs".

FDA, Guidelines on General Principle of Process Validation (1987)

D'une part, il faut distinguer validation d'un logiciel (Software Validation) et validation d'un système (System Validation). (Le logiciel n'étant qu'une composante du système).
On peut définir la validation d'un système comme étant une qualification qui vérifie les étapes du processus.
Dans le cas du développement on parle d'un processus comprenant: la collecte des requirements, la création des spécification fonctionnelles, les spécifications de Design, la construction du système.

IQ : Installation Qualification : vérifie que l'environnement est conforme aux system requirement définies dans la phase de Design.
(check list qui vérifie que l'équippement est conforme, que le logiciel est correctement installé et correctement configuré). Le système fonctionne.
OQ : Operational Qualification : vérifie que le système fait ce qu'il est censé faire (test scripts)
verifie la phase fonctionnelle (les spécifications fonctionnelles). Fait ce qu'il doit faire.
PQ :Performance qualification : vérfie que les system requirements (temps de réponse définit) sont corrects. L'utilisabilité pour le client. Ca fait ce que ça doit faire dans temps acceptables

Valider signifie produire ces trois documents décrivant l'IQ, l'OQ et le PQ. Ces documents sont bien sur les preuves énnoncées dans la définition.
La production et le contenu de ces documents est le noeud gordien du problème.

mercredi 8 septembre 2010

Cross Tab Queries en SQL Server 2005

Les cross tab queries sont souvent bien utiles pour présenter des synthèses de résultats par catégories par exemple (En statistique cela est très utile pour l'ANOVA ou les tests du khi carré sur des comptes variables binaires).

Certains informaticiens ont le réflexe de récupérer les données via un data set puis de les trier eux même sous formes de tableau, cette opération est souvent très couteuse alors que SQL Server 2005 nous offre la commande PIVOT.

Cette commande permet de créer un tableau de donnée en un clin d'oeil.

Voici un cas d'exemple

SELECT ID_Project, ID_FormModel, [1],[2],[3],[4],[5],[6] FROM
(select FM.ID_Project, FM.ID_FormModel, FI.FormStatus, 1 AS cnt from tblDMFormModel FM
LEFT OUTER JOIN tblDMForminstance FI on FI.ID_FormModel=FM.ID_FormModel) AS RawData
PIVOT (
SUM(cnt) FOR FormSTATUS IN ([1],[2],[3],[4],[5],[6])
) pvt
WHERE ID_Project=165

La première ligne formatte le tableau en affichant les deux colonnes non pivotables : l'id_project et le form model, les valeurs en gras indique les valeur du status des formes.

La seconde ligne construit le tableau des données brutes sur laquelle nous allons appliquer le pivot. (Le left outer join sert à récupérer tous les form modèles, même ceux qui n'ont pas de form instance). 1 indique que le form instance apparait une fois.
PIVOT fait pivoter les valeurs de rows autours de FormStatus en sommant les form instance pour obtenir les comptes.

Voilà, c'est peut-être pas super bien expliqué mais ça marche !

vendredi 13 août 2010

Echantillonnage par méthode des quotas

Ou pourquoi les sondages journalistiques sont souvent faux :-)...

Il est admis par les statisticiens qu'une méthode fiable d'échantillonnage est la l'échantillonnage randomisé. (On prend un échantillon de manière aléatoire dans la population). Cette méthode dit d'échantillonnage probabiliste est plus coûteuse, plus complexe à mettre en place mais donne une très bonne précision en terme d'erreur puisqu'il est possible de calculer la probabilité d'inclusion de chaque unité dans l'échantillon.
Si l'échantillon pris est aléatoire il représentera d'ailleurs les caractéristiques de la population d'origine. Si ce n'est pas le cas c'est que l'on a un sérieux problème.

Il existe toutefois des méthodes d'échantillonnage dites non probabilistes, en particulier la méthode dites des quotas.
Cette méthode est très employée pour constituer les sondages lus dans les médias. L'idée consiste à créer un échantillon disposant des même propriétés que la population mère.
Cette méthode n'est pas aléatoire, il est impossible de calculer la probabilité d'inclusion d'une unité dans l'échantillon. Cela signifie qu'il est difficile d'établir une marge d'erreur.
On définit le % des critères choisis, ensuite on tire au hasard des individus selon la proportion définie dans l'échantillon.
Cette méthode repose sur l'hypothèse que l'information que l'on souhaite obtenir est corréléeé avec la population. (Ce qui n'est pas toujours vrai).

Autre petit détail, dans beaucoup de cas les sondages se font de manière téléphonique en général durant les heures de bureau. Cela aussi peut donner un biais non négligeable, si la sous population dans laquelle vous tiré les sujets est constituées uniquement de femmes au foyer, de personnes sans emplois ou de pensionnés, cela n'est pas forcément représentatif de toute la population. Donc risque de biais non négligeable.

Tout cela pour dire, mais ça vous le saviez déjà qu'il ne faut pas avoir une confiance aveugle dans les sondages effectués dans les journaux...

Sources:
Echantillonnage probabiliste
Echantillonnage par la méthode des quotas

mercredi 11 août 2010

Mensonges statistiques (I)

Dans un article de la libre d'aujourd'hui on nous annonce fièrement:

"L'important patrimoine des familles belges n'est pas tellement imputable aux placements à succès mais au comportement enthousiaste des Belges pour l'épargne. Une famille belge moyenne possède 156.000 euros d'épargne et de placements."

En moyenne une famille belge possède 156.000 euros.

Vraiment ?
Dans un tel cas de figure la moyenne est sans doute le plus mauvais indicateur car elle a tendance à être influencée par les valeurs extrêmes. Evidemment comme dans tout article se référant aux stats nous n'avons pas la distribution. D'où difficulté d'analyser, toutefois voyons cela via un exemple.

Quelqu'un décide d'entrer dans une entreprise de dix personnes et l'on clamme que le salaire moyen est de 3700 euros brut. Heureux notre nouvel employé travail avec zèle et lors de son premier salaire il touche 1000 euros, stuppeur et tremblements...
Notre jeune ami s'est retrouvé floué pour la simple raison que si la distribution des salaires est la suivante:
1000,1000,1000,1000,1000,1000,1000,10000,10000,10000.
Soit 7 employés gagnent 1000 euros
3 managers (CEO,PDG,actionnaire) gagnent 10000 euros soit dix fois plus que les autres.
Alors, la moyenne salariale est bien de 3700 euros, toutefois elle est fortement influencée par les 3 gros salaires des managers. Donc, son salaire sera assez éloigné de 3700 euros.

Dans un tel cas de figure pour être honnête il vaut mieux utiliser la médianne (valeur de l'effectif à la moitié de la distribution ordonnée) et là nous aurions bien trouvé 1000 euros. Notez quand dans le cas d'une distribution normale ça ne pose pas vraiment de problème puisque la moyenne est égale à la médiane.

Dans le cas de l'épargne ci dessus, ce sera semblable car je doute personnellement que la distribution soit normale. La moyenne sera probablement influencée par les gros épargnants qui sont loin de représenter la grosse majorité. Quelqu'un d'honnête aurait donc donné la médiane plus proche de l'épargne réelle plutôt qu'une épargne moyenne fantasmée et certainement surévaluée...

lundi 2 août 2010

SQL-Server Load-Unload

Il existe une commande "DOS" bien pratique pour décharger le contenu d'une table dans un fichier texte. Ce déchargement se fait à une vitesse assez incroyable:

c:\bcp <dbname>..<tablename> out <c:\file.unl> -n -S <server-ip> -U <user> -P <password>

Ex:
c:\bcp txsoct..tblAudit out c:\test.unl -n -S localhost -U toto -P keep_the_secret

L'opération réciproque existe également et permet de recharger une table à une vitesse relativement grande.

c:\bcp <dbname>..<tablename> in <c:\file.unl> -n -S <server-ip> -U <user> -P <password>
Ceci peut s'avérer quelquefois bien utile !

mercredi 30 juin 2010

IIS et les "regional settings"

Ceux qui ont déjà manipulé IIS quelquefois ont probablement eu la désagréable surprise de voir leur application fonctionner très bien dans leur environnement de développement pour ne plus fonctionner du tout lorsque l'on passe en environnement de test. En particulier lorsque cette application se base sur des dates ou des valeurs décimales.

Cela vient du fait qu'IIS utilise deux utilisateurs spéciaux pour s'éxecuter comme service ou exécuter des nouveaux threads.

IUSR_
IWAM_

Ces deux utilisateurs ont leur propre régional settings (basés sur le default). Si les regional settings de ces utilisateurs ne correspondent pas avec ceux de l'environnement de développement, les problèmes apparaissent une solution proposée par Microsoft est la suivante. Forcer IIS à utiliser les default regional settings.

Ceci peut se faire de la manière suivante:
1) A l'aide de regedit, créer ou mettre a jour la clé (DWORD) suivante:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\InetInfo\Parameters\SetVarConversionLocaleSetting = 2
Les valeurs sont les suivantes:
0 - comportement par défaut
1 - utiliser l'impersonisation pour l'utilisateur IIS
2 - Forcer IIS à utiliser les default regional settings

2) Au moyen de l'outil regional settings mettre les settings du user courant comme étant les default regional settings.

3) Redémarrer le serveur pour bénéficier des nouveaux effets.

Pour plus d'informations:
http://support.microsoft.com/kb/306044/en-us

Voilà, ce n'est peut-être pas le moyen le plus simple mais ça marche.

mardi 1 juin 2010

Importing Data into TrialXS

TrialXS is a web application used to collect, review and process study data for clinical Trials.

Currently we develop an interesting tool that allows to import an exported set of data (FLAT Export). This feature is quite interesting because if you can mimic an export of TrialXS by using Excel or every other tool you can potentially re-import those data into TrialXS. Under the condition that your data are consistent at the database level.

To process this import TrialXS, first, checks a lot of criteria that comes from the imported data. Especially the CODE of investigators, sites, ...

The interest is to know how this import features can know if yes or no the patient has already been imported.
As TrialXS users knows the Patient Identifier is recalculated automatically by TrialXS. In the other hand, TrialXS consider for importing a special field called PatExtRef for patient external reference. You must ensure that this PatExtRef must be unique for each imported patient otherwise to make sure that TrialXS will not try to re-import the data for an existing patient in the same study.

From the import process view the PatExtRef is given by the PATID defined in the header of the datafile.

mercredi 26 mai 2010

SQL Server Transaction Log

Le transaction log est le fichier utilisé par SQL Server pour effectuer ses transactions. Ce fichier peut suivant le paramétrage gonfler d'un certain % de son volume chaque fois que ses limites sont atteintes. C'est pourquoi il est bon de temps à autres de faire un SHRINK de ce fichier.

Voici une méthode qui vous donne l'espace utilisé par le transaction log.

SELECT name ,size/128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS int)/128.0 AS AvailableSpaceInMBFROM sys.database_files;

La taille restante avant que le fichier ne se mette à gonfler est donnée en MB.

USE DatabaseName
GO
DBCC SHRINKFILE(FileName, 1)
BACKUP LOG DatabaseName WITH TRUNCATE_ONLY
DBCC SHRINKFILE(FileName, 1)
GO

Voici une méthode qui vous permet de réduire drastiquement la taille du transaction Log, ceci dit vous pouvez aussi le faire à partir de l'interface graphique.

jeudi 13 mai 2010

Manipuler des listes génériques en C++

Pour rappel les types génériques sont supportés depuis récemment par un certain nombre de compilateur. Il faut savoir que cette notion existe depuis près de 20ans sous le nom de templates.

L'intérêt d'un type générique est de pouvoir générer des classes adaptables à un type de données particuliers. Ceci est très pratique par exemple pour les listes.
Si vous voulez gérer une liste liée manipulant des entiers, du texte ou des réels vous n'aurez sans doute pas envie de ré-écrire une classe liste par type de données à manipuler.

Le C++ offre depuis longtemps un mécanisme appelé "template" (modèle de classes) qui permet d'effectuer automatiquement cela pour vous.

La plupart des templates standards offerts par défaut avec C++ se trouve dans le module STL. Il suffit d'effectuer en début de code un #include

Vous trouverez ici un petit exemple sur comment créer et manipuler une liste liée générique contenant des chaines de caractères (max 255 caractères).

Le programme fonctionne en mode console et a été crée avec Code::Blocks.
Les options sont les suivantes :
1 permet d'encoder des données dans la liste
2 permet de lister les données, un identifiant est affiché pour pouvoir les supprimer
3 permet de supprimer une donnée de la liste sur base de l'identifiant.

Listing:
ajouter hyperlien...

Questions:

Comment est libéré le list ? Normalement, il détruit automatiquement à la sortie du main ? Qu'advient-il de ses éléments ?
Faut-il faire un erase du contenu avant de sortir du scope de la fonction ??

Transformation de Box-Cox

Les transformations de Box-Cox sont généralement utilisées en régression linéaire pour tenter de corriger :
- la non-linéarité d'un régresseur
- l'hétéroskédasticité des résidus.
- corriger la normalité de la distribution d'une variable (ex: distribution log-normale d'une variable X dont il faut corriger la normalité qui donne une distribution Y qui elle est normale).

Plutôt que de mettre ce régresseur tel quel dans le modèle, on peut le mettre au carré ou prendre son logarithme. La transformation de Box-Cox est une méthode de généralisation de cette approche.
Elle est donnée par l'équation:
Ta(y)=[(y^a)-1]/a
pour a>0
On peut aisément montrer que pour la limite a=0, la transformation de Box-Cox revient à prendre le logarithme de y.

Rappel du calcul des dérivées:
Si y=a^x alors
log(y)=xlog(a)
On différencie les deux membres de l'égalité
dy/y=1*log(a)*dx
dy/dx=y*log(a)
avec y=a^x
dy/dx=a^x*(log(a))

Appliqué à la transformation de Box-Cox cela nous donne:
lim (a->0) [(y^a)-1]/a
On applique la règle de l'Hospital car il s'agit de la recherche de limite d'un quotient. Remarquez que l'on dérive par rapport à a.
par la démonstration précédente, au numérateur il reste : ((y^a)-1)'=(y^a*log(y)-0)
Au dénomiteur la dérivée de a par rapport à a vaut 1. Il reste:
lim (a->0) Ta(y)=y^a*logy=y^0logy=logy.

Le cas particulier d'un transformation de Box-Cox sur une variable avec un a=0 revient à prendre le logarithme de cette variable.

mercredi 21 avril 2010

Design Patterns (I)

Les différents Design Patterns

Creational
Factory : Définit une interface de création d'objet. Permet à la classe de laisser à une sous classe le soin de créer l'objet.
Singleton : Assure que la classe n'a qu'une seule instance et fournit un point d'accès unique à celle-ci.

Structural
Adapter : Convertit l'interface d'un classe en une autre interface attendue par le client. Permet à des classes d'interfaces différentes de travailler ensemble.
Bridge : Découple l'abstraction de l'implémentation ainsi les deux peuvent évoluer de manière indépendante.
Composite : Compose des objets en structure en arbre pour représenter leur hierarchies. Permet au client de s'adresser à des compositions d'objets.
Decorator : Attache des responsabilités additionnelles à un objet de manière dynamique. Le Decorator permet une alternative flexibles à l'utilisation de sous classes pour étendre les fonctionalités.

Behavioral
Interpreter : Donne un langage, défini une représentation de sa grammaire. Interprète les commande d'un langage.
Command : Encapsule les requêtes comme des objets. Laisse la possibilité de paramétrer les clients avec différentes requêtes, queue ou log-request.
Iterator : Fournit un moyen d'accéder aux éléments d'une aggrégation de manière séquentielle.
Strategy : Défini une famille d'algorithme, les encapsule et le rend interchangeable. Permet de faire évoluer les algorithmes suivant l'utilisation du client.
Memento: Sans violer l'encapsulation, capture et externalise les objets et les états internes de l'objet afin de pouvoir le restaurer plus tard.

Règles de construction

- Ne pas confondre héritage de classe et héritage d'interface
Héritage de classe: on passe un objet particulier existant dans les méthodes
Héritage d'interface : la méthode attend un objet répondant à cette interface, l'objet n'est pas signé et peut-être crée au moyen d'un pattern creational.

"Program to an Interface not an implementation"

- Héritage et composition
Il est facile de croire que l'héritage permet une bonne re-usabilité, parfois c'est un leure, la composition permet de mettre en oeuvre des méchanisme plus simple. La composition peut placer une interface sur une colloboration d'objet, ce qui masque la complexité de l'extérieur, l'héritage ne le permet pas.

"Favor object composition over class inheritance"

Sources:Elements of Reusable Object-Oriented Software,
- Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (GOF)

samedi 17 avril 2010

R (CRAN)

Installation de R sous Linux Debian Lenny


en root taper la commande suivante:

apt-cache search '^r-' \
egrep -v -i '(biologygeneticmap)' \
egrep -v -i sql \
awk '/^r\-/ {print $1}' \
xargs apt-get install --yes

En utilisateur normal taper "R" dans la console, R devrait démarrer.
Complément d'information;
http://www.mayin.org/ajayshah/KB/R/documents/install.html
http://cran.r-project.org/doc/manuals/R-lang.html#Introduction

Importer des données
Le plus simple est sans doute d'importer les données au format texte (.txt). Le fichier commence par un en-tête contenant le nom des colonnes, les colonnes sont séparées par un tab.
On utilise la commande R : read.table()

lundi 22 février 2010

Bases de l'administration Linux

Je sais que c'est très bateau mais parfois on est content d'avoir un pense bête lorsque l'on a un trou de mémoire:
Attention comme les caractères pipes sont interdits j'ai utilisés celui-ci à la place :"!"

Lister les directory
ls -l ! egrep '^d'

Liste les fichiers
ls -l ! egrep -v '^d'

Rechercher les fichier d'un répertoire qui se terminent par : *.tex
ls -l ! egrep '.tex$'
Ceci est équivallent du dir *.tex du DOS (rappel $ indique la fin de la ligne)

Recherche tous les fichiers ne se terminant pas par .texmoins évident en dos.
ls - l ! egrep -v '.tex$'

Affiche tous les fichiers commençant par a ou A (Linux est case sensitive)
ls ! egrep '^[aA]'

Equivallent du Dir a*dans ce cas le '^' indique le début de la ligne, il n'est pas utilisé comme not.

Affiche tous les fichier commençant par a ou A et finissant par .tex
ls ! egrep '^[aA]' ! egrep '.tex$'
Ceci est equivallent du Dir a*.tex

Rechercher à travers tous les répertoires un fichier se terminant par '.tex'
ls / -Rl ! egrep '.tex$'
soyez prudent avec l'utilisation du -l lors de ce type de recherche récursive.

Espace libre sur le disque
df -kh
le paramètre "h" permet d'afficher en mode humain

Afficher l'espace libre d'un répertoire
du /home/repertoire

Effacer un répertoire et tout son contenu (y compris les sous répertoire) :
rm -rd /home/repertoire/sousrep/*

Decompression d'un tarball zippé au moyen de la commande tar
tar -xwzf .tar.gz

Décompression arj (en tenant compte des sous répertoire)
arj x /home/repertoire/source/fichier.arj /home/repertoire/cible/

Changer les droits sur un fichier
chmod ugo +rwx /home/repertoire/fichier

u vaut pour les droit du user, g pour les droits du groupe, o pour les droits des 'others' (reste du monde) quant à rwx ils représentent (read, write, eXecute). On peut utiliser différentes combinaisons de cela.

mardi 9 février 2010

Accéder des fichiers via Delphi.

Classe TFileStream

Le FileStream est utilisé pour lire ou écrire des informations dans des fichiers. Il s’agit en général de buffer. Il faut donc être prudent quant à l’utilisation de ces méthodes avec du texte.

Unit : classes ;

Concrètement le Filestream ne s’attend pas forcément à écrire du texte, ce qu’il veut c’est un buffer de donnée.
Si vous voulez écrire un texte, il faut utiliser la méthode Write() en lui passant les paramètre suivants :
const
arrCRLF : array [0..1] of Char = ( #13, #10 );
var
sText : string ;
oFileStream : TFileStream;
begin
sText :=’test text file stream’ ;
oFileStream:=TFileStream.Create(‘c:\temp\test.txt’, fmCreate)
oFileStream.Write( sText[1], length(sText);
oFileStream.Write(arrCRLF,2);
oFileStream.Free;
end;

L’avantage de cette méthode est que l’information ne doit pas être contenue en mémoire mais elle peut-être écrite on-fly sur le disque. Ce qui dans certains cas peut franchement vous sauver la vie.
Attention comme on écrit plattement le contenu d’un buffer le CRLF n’est pas géré, il faut donc explicitement indiquer le changement de ligne. C’est l’utilité de la ligne
oFileStream.Write(arrCRLF,2);
Le tableau arrCRLF contenant les caractères #13#10 du carriage return – line feed

samedi 6 février 2010

Connexion à une base de données via Delphi

Il est souvent de bon ton d'utiliser une technologie, telle que ADO ou ADO.NET par exemple, toutefois la question à se poser est : "Est-ce que j'utilise bien cette technologie" en ai-je vraiment compris les fondements, les tenants et les aboutissants...

Nous allons tenter de répondre à ces questions par rapport aux connexions entre Delphi et les bases de données. Tout d'abord il existe deux types de connexions:

Les connexions Explicites se font via un objet de type TCustomConnection qui peut être décliné en TADOConnection.

Il est aussi possible de connecter Implicitement des datasets (ensemble de records provenant d’une base de données formant une sorte de table logique en mémoire, ce concept fondamental sera développé plus tard) vers la base de données (ç-à-d ne pas utiliser l’objet connexion mais passer directement les paramètres du server à la propriété Connectstring). Honnêtement, je ne le conseille pas, car en plus de limiter vos actions ceci peut s’avérer dramatique si vous devez changer les paramètres de la base de données et que vous avez hardcodé les connectstring…

Manipuler l’objet de connexion :

Pour se connecter à la base de données on peut soit utiliser la méthode Open ou mettre la propriété Connected à True. Passer par la seconde méthode permet de lancer l’évènement BeforeConntect et d’éventuellement passer des paramètres de connexion.

Lorsque plus aucun dataset n’utilise l’objet connexion celui-ci est détruit. Dans certains cas, si l’on fait des accès très fréquents à la DB, il est mieux de ne pas autoriser cette destruction pour réduire le trafic réseau et la charge de la DB. Dans ce cas mettre à True la propriété : KeepConnection.

Pour se déconnecter de la DB utiliser la méthode Close ou mettre la propriété Connected à false, faire cela lance un évènement BeforeDisconnect.

Une connexion à une base de données requiert généralement un password, dans le cas d’une connexion ADO, simplement mettre le login/password dans la propriété ConnectString et placer la propriété LoginPrompt à false pour éviter d’avoir la boîte de dialogue.
Noter que hardcoder un password en clair dans une application ou dans un fichier de configuration n’est jamais très intelligent. L’évènement ADO OnWillConnect est appelé à la place du login prompt et permet de définir un login et un password.

Nous n’aborderons pas dans ce billet la gestion des transactions qui est un point fondamental mais qui mérite un billet (voir un livre entier) à lui tout seul.

dimanche 31 janvier 2010

Cours de Biostatistique (V)

Cette partie du cours est relative aux test d'hypothèses T de Student qui s'appliquent aux variables quantitatives.
Dans cette partie vous verrez comment poser une hypothèse sur le comportement d'une population et comment tenter de l'invalider au moyen des données de l'échantillon. La philosophie est simple : Si on rejette l'hypothèse alors l'échantillon permet de démontrer l'invalidité de l'hypothèse, si on ne la rejette pas, nous n'avons pas assez d'information dan sl'échantillon pour prouver qu'elle est fausse. Dans ce cas de figure il est assez difficile de conclure de manière définitive.

Les bases de statistiques touchent à leur fin, il restera encore le test du Khi Carré à documenter.

Les Tests d'hypothèses (I)
Les Tests d'hypothèses (II)

vendredi 22 janvier 2010

L'architecture

Donner une définition claire de l'architecture logiciel est chose parfois peu aisée car le sujet englobe une grande partie du processus de développement.

Dans ce billet, pour clarifier les choses, je vais considérer que l'architecture englobe :

- le design
- l'interaction des composants (organisation des composants)
- l'infrastructure (l'hébergement des composants)

Ces différents éléments qui sont, en réalité, des vues sur le système informatique peuvent se résumer au diagramme suivant:











Ce diagramme nous indique comment percevoir notre système informatique (le système informatique se compose en général d'un logiciel et d'une plateforme physique ou logique permettant de le faire fonctionner).
La vue la plus importante, celle qui dirige et qui induit le système, est la vue de cas d'utilisation.
Les cas d'utilisation représentent les fonctionalités que le système va offrir aux utilisateurs. A chaque cas d'utilisation correspondent différents scénarios : un scénario principal décrivant la fonctionalité attendue, des scénarios alternatifs prenant place lorsqu'une erreur se produit ou qu'une donnée est manquante.

Les quatre vues suivantes ne font qu'implémenter concrètement les spécifications qui ont été définies dans la vue de cas d'utilisation.

La vue logique décrit comment sera organisé le code, comment seront regroupées les fonctions qui réaliseront les cas d'utilisation. Ces fonctions appartiendront à des classes qui pourront collaborer entre elles en vue des réaliser les cas d'utilisation définis. Cette vue est parfois la seule visible pour des petits systèmes d'information.

La vue de processus décrit comment vont fonctionner et comment seront synchroniser les threads ou les processus réalisant des opérations en parallèle. Si le logiciel utilise des services, il génère des threads chaque fois qu'il doit gérer de nouvelles connections, ...

La vue de réalisation (collaboration) décrit comment les composants interagiront ensemble et où ils seront stockés. Ceci peut être représenté par un diagramme de composants. Les noeuds qui contiennent ces composants seront également décris. Cette vue est très utile dans les systèmes distribués.

La vue de déploiement décrit comment le système informatique sera organisé, déployé. Cette vue peut ressembler au diagramme de composant sauf que, ici, l'accent sera mis sur l'agencement du réseau et des serveurs (noeuds).

Les gros systèmes seront généralement décrits par ces quatre vues, les plus petits systèmes se contenteront généralement de la vue logique.


Les types d'architectures logiciels:


Les types d'architecture vont indiquer comment les composants d'un logiciel vont se répartir. On distingue en général des composant utiles à l'affichage, au traitement et au stockage. Une architecture relativement courante dans les systèmes d"information est l'architecture dite
Client/Serveur.
Un logiciel client installé sur un poste de travail accède aux données stockées sur un serveur de base de données. Cette architecture permet de partager facilement des informations entre différents utilisateurs répartis sur des postes différents. En général, cette architecture se limite au réseau physique de l'entreprise. Si les postes de travail sont relativement évolués, les programmes clients pourront aussi effectuer des traitements locaux sur les données. Ceci permet de répartir la charge de travail entre le serveur et les clients.

L'architecture 3 Thiers
Cette architecture est souvent utilisée par les applications Internet (application de eCommerce, de data-capture, ...). Dans ce type d'application, le client est un browser Internet qui permet des traitements relativements légers. Le client accède à un web-serveur qui lui renvoie des pages HTML (HyperText Markup Language) générées dynamiquement. Cette génération dynamique se fait en général par des extensions du web-serveur. Il peut s'agir de DLL, DSO, script CGI(remarquez que PHP par exemple fonctionne sur base d'une DSO).
L'avantage de cette architecture est de s'ouvrir au monde. En effet, il sera possible d'accéder aux données en dehors du réseau local puisque les accès se feront à travers Internet. Toutefois, si on laisse les extensions sur le web-serveur, on arrive très vite au problème de montée en charge. Que se passe-t-il si trop d'utilisateurs se connectent sur le serveur et que le CPU ou la mémoire s'effondre ? Le système deviendra inutilisable. Nous arrivons donc à un problème crucial qui est la "scalabilité" (déjà évoqué dans un précédent billet) c'est-à-dire la faculté de pouvoir fonctionner quel que soit le nombre d'utilisateurs connectés en même temps.

Les architectures distribuées.
Les architectures distribuées utilisent des composants (EJB, COM, COM+, assembly .Net, ...) pouvant s'éxécuter sur un serveur d'application. Ces composants seront sollicités par les extensions du web-serveur. L'avantage de cette approche est que certains composants pourront fonctionner sur un serveur d'application alors que d'autres fonctionneront sur un autre. Ceci permet de répartir la charge et ceci a pu voir le jour grâce à des technologies comme CORBA ou DCOM qui permettait d'invoquer des méthodes de composants à travers le réseau.
Par la suite, DCOM a été remplacé par COM+ qui a lui même évolué en .Net.
D'une manière générale, l'invocation des composants et l'organisation de ceux-ci se fait sur un même réseau local.

Les architectures de services.
L'architecture de service qui a vu le jour dans le début des années 2000 outrepasse la capacité d'utiliser des composants organisés sur un réseau local mais permet d'utiliser des services n'importe où sur Internet.
Un exemple simple serait la possibilité pour le système informatique d'une agence de voyage de communiquer avec le système de réservation d'une compagnie aérienne. Les deux infrastructures sont totalements séparées mais, grâce à l'architecture de service, il serait possible à l'agence de voyage de réaliser automatiquement la réservation du billet d'avion. Cela peut se réaliser au moyen des Web-Services qui sont des composants distribués à travers l'Internet.

mardi 19 janvier 2010

Cours de biostatistique (IV)

Cette partie du cours est consacrée à la fin des distributions de probabilité et à l'inférence statistique.

L'inférence statistique va utiliser l'échantillon et les probabilités pour tenter de prédire le comportement d'une population dont serait extrait l'échantillon.
L'échantillon représente donc un ensemble de données empiriques (provenant des mesures expérimentales).
La population est un modèle théorique décrit par une distribution de probabilité.
Nous distinguerons deux parties importantes dans l'inférence statistique:
  • L'estimation: va nous permettre à partir des données de l'échantillon de définir un intervalle de confiance sur les paramètres de la distribution théorique.
  • Les tests d'hypothèse: nous allons considérer une hypothèse sur la population et tenter d'utiliser l'échantillon pour la démolir.
Dans les cours présentés, nous introduirons brièvement la philosophie du test d'hypothèse.

Inférence statistique (I)
Inférence statistique (II)

lundi 18 janvier 2010

Qualités d’un logiciel

Validité : faculté dont dispose le logiciel de faire ce qu’il doit. Cela s’obtient par l’utilisation d’une bonne méthodologie.

L’intégrité : faculté d’un logiciel à maintenir la justesse de ses données en toutes circonstances, protéger ses accès et ses données d’accès non autorisés. Cela s’obtient par l’utilisation de techniques appropriées (OS capable de gérer les accès mémoire d’une application à l’autre) et d’une bonne méthodologie (utilisation de l’encapsulation provenant de la POO).

La fiabilité : faculté d’un logiciel à gérer ses erreurs correctement. Cela s’obtient par l’utilisation d’une bonne méthodologie de coding, comme, par exemple, l’utilisation et la gestion des exceptions.

La scalabilité : faculté de pouvoir monter en charge, sans devoir modifier le code programme, en changeant simplement l’organisation du logiciel (le scinder sur différents serveurs pour répartir la charge). Ceci s’obtient par un design intelligent.

La reusabilité : faculté de ne pas devoir réinventer la roue à chaque fois que l’on veut ajouter des fonctionnalités mais, au contraire, pouvoir s’appuyer sur une fondation consistante. Ceci s’obtient par un design et une méthodologie corrects.

La maintenabilité : capacité à maintenir sans se noyer ou se faire dépasser par la complexité de celui-ci. C’est avant tout un problème de design et de documentation.

L’extensibilité : capacité d’ajouter de nouvelles fonctionnalités au logiciel. Ceci s’obtient en utilisant un design tenant en compte la reusabilité.

Les performances : faculté de répondre dans des délais raisonnables. Ceci s’obtient par un coding approprié (algorithmes optimisés).

L’interopérabilité : faculté de s'intégrer avec d'autres applications logicielles. On utilise une architecture composant pour achever cet objectif.

La plupart de ces notions de qualité sont dépendantes les unes des autres. Exemple : un logiciel peu fiable peut très bien, à un moment ou à un autre, écrire de mauvaises données au mauvais endroit et avoir un impact sur l’intégrité du logiciel.

Un logiciel basé sur un design de réusabilité pourra facilement être étendu. De plus, ces extensions basées sur des composants ou classes existantes auront un impact positif sur la fiabilité et l’intégritié. La réusabilité facilitera aussi la maintenabilité du logiciel, puisqu’une erreur corrigée à un endroit se répercutera partout. Au final , plus votre logiciel évoluera, plus ses bases se solidifieront.

La scalabilité et les performances, même si elles sont des notions différentes, sont aussi très liées. Avoir des performances extraordinaires qui vont s’effondrer dès que dix utilisateurs vont se connecter n’est pas très intéressant. Avoir une architecture permettant la connexion de millions d’utilisateurs mais mettant dix minutes à produire un résultat qu’il y ait un ou un millions d’utilisateurs n’est pas acceptable non plus.
Toute la finesse consiste à trouver un équilibre, un compromis entre scalabilité et performances.

Ces différents objectifs de qualité, classés ici suivant mon ordre d’importance doivent être traduit par le processus de qualité, qui est lui-même formalisé sous forme de Procedures d’Operation Standard (POS ou SOP en anglais).

L'un des fondements de la qualité est aussi la traçabilité. Son rôle est d'identifier lors de problème où se trouve celui-ci. Ceci semble très bâteau mais, en pratique, c'est parfois très difficile de démêler les faits, en particulier s'il y a un manque de transparence... La traçabilité assure cette transparence.

Il serait intéressant de définir des indicateurs (sorte de KPI) permettant de mesurer ces concepts de qualité.

mardi 12 janvier 2010

Probabilités


Petit exercice de probabilité, bien énervant, comme la plupart des exercices de probabilités ;-)

Une étude auprès des associations de refuge pour animaux nous apprend qu'environ 60% de chiens mâles sont adoptés.

Une autre étude sur les chiens nous apprend qu'environ 70% de chiens mâles pèsent plus de 30kg contre 25% de chiens femelles pesant plus de 30kg.

Si Madame Durand décide d'adopter un chien de plus de 30kg pour son mari, quelle est la probabilité qu'elle adopte un chien mâle ?

Si l'on examine les données, on peut déduire les évènements suivants :

M : Adopter un chien mâle
>=30 : L'animal pèse plus de 30 kg

D'où les probabilités suivantes :

P(M)=0.60 (par l'énnoncé)
D'où P(nonMale)=0.40

a) P(>30kg!Male)=P(>30kg et Male)/P(Male)=0.70
b) P(>30kg et Male)=0.70*0.60 =0.42
c) P(>30kg!nonMale)=P(>30kg et nonMale)/P(nonMale)=0.25
d) P(>30 et nonMale)=0.40*0.25=0.10

Ces assertions nous permettent de créer la table de contigence ici produite (la dernière étant la bonne).

La différence entre le "et" et la probabilité conditionnelle "!" (normalement c'est un pipe, mais ça ne passe pas sur blogger ;) ) est assez énervante, je dois le reconnaître. Le "et" se réfère à l'ensemble des cas possibles c'est-à-dire dans ce cas de figure:
"la probabilité que j'adopte un chien mâle de plus de 30kg parmi tous les chiens adoptables possibles". C'est toujours cette probabilité que l'on retrouve dans la table de contigence et cette probabilité vaut bien sûr 42%.

Or, dans l'ennoncé, on nous demande un chien de plus de 30kg, qui soit un mâle, ce qui signifie que le critère >30kg est fixé, ce qui revient à écrire P(Male!>30kg)=P(Male et 30 kg)/P(>30kg)

P(>30kg)=0.52 (par le tableau)
P(Male!>30kg)=0.42/0.52=80.8%.
Madame Durand aura donc 80.8% de chances de rapporter un chien mâle à son mari.

mercredi 6 janvier 2010

Cours de biostatitistique (III)

Ces notes de cours sont consacrées au calcul des probabilités. En effet, l'intérêt de réaliser des mesures sur un échantillon de données est d'inférer (extrapoler) ces données à une population qui n'est pas toujours connue. Afin de réaliser cette inférence à une population, les statisticiens utilisent un outil mathématique : les probabilités. Grâce à celle-ci, il sera possible de prédire les propriétés d'une population ou encore de donner une marge d'erreur sur les données provenant d'un échantillon par rapport à ce que l'on pourrait mesurer dans la population.

Les notes proposées ici contiennent les règles de calcul de probabilités et de distribution de probabilité.

Le calcul des probabilités
Distributions de probabiltiés

mardi 5 janvier 2010

Delphi Prism 2010

Delphi Prism est le nouveau joujou annoncé par Embarcadero pour developer dans l’environnement .NET et Mono.

L’avantage Mono est bien sûr la possibilité d’utiliser le framework .Net sous Linux ainsi que Mac OS. Encore une fois, le framework n’est jamais le dernier et les outils tels que MonoDevelop sont probablement moins performants que Visual Studio. Mais bon, c’est gratuit donc…
(ref : http://blog.developer.mindtouch.com/2009/08/10/monodevelop-and-visual-studio-2008/)

Cette version de Delphi distribuée par Embarcadero peut s’intégrer dans le CodeGear RAD Studio mais aussi dans le MS Visual Studio.
Ce que Embarcadero ne nous dit pas clairement, c’est que cette nouvelle mouture annonce la mort de Delphi .NET et, dans la foulée, la mort de la VCL.NET. En effet, Delphi Prism est un produit qui n’est ni développé par CodeGear, ni par Embarcadero mais par la société RemObjects qui est elle-même un partenaire de Microsoft Visual.

La mort de la VCL.NET était relativement prévisible, puisque reconstruire un framework .Net au dessus du framework original n’était probablement pas une bonne idée puisque, d’une part, la compatibilité avec l’ancienne VCL n’existait pas et qu'il fallait réécrire malgré tout le code et, d’autre part, pourquoi la copie à l’originale si c’est pour se lancer dans une réécriture autant prendre le framework .NET natif et même choisir le langage écrit pour ce framework, c’est-à-dire C#.
D’ailleurs, certains professionnels de Delphi déconseillaient fortement l’utilisation de cette VCL.NET.

C’est peut-être une bonne nouvelle pour les programmeurs Delphi (et pour l’avenir de Delphi) de savoir que, désormais, on peut coder du Delphi grâce à Visual Studio. Toutefois, pourquoi s’amuser avec Delphi alors que C# est un langage complètement façonné pour cette plateforme…

(source : http://www.e-naxos.com/Blog/post/2009/03/09/Delphi-Prism-la-seconde-mort-de-Delphi.aspx#auteur)

lundi 4 janvier 2010

Scalability & Optimisation

A tort ou à raison, la “scalabilité” d’une architecture est souvent associée aux performances de cette même architecture.

Par achitecture j’entends le design de l'application, la technologie et l’infrastructure utilisée.

En ce qui me concerne je définis la scalabilité comme l’aptitude à supporter un plus grand nombre d’utilisateurs avec des temps de réponses comparables. Bien sûr, on peut y voir un lien directe avec les performances mais pas uniquement.

Je défini les performances d’une application comme étant fonction du hardware utilisé (CPU, RAM, contrôleur disque), l’infrastructure (bande passante du réseau, configuration des routers, switch, …), optimisation du code.
Certes en utilisant au mieux nos ressources nous pourrons avoir des performances rapides, mais qui risqueront de décroître rapidement, si la charge (nombre de requête) augmente rapidement.

L’idée d’une architecture "scalable" ou extensible est de fournir une application qui aura des temps de réponses plus ou moins constants en fonction de la charge.

Une image que j’aime évoquer est celle de la formule 1 et du tracteur. Une formule 1 pourra atteindre de vitesse de pointe phénoménale, mais elle ne pourra plus rouler si vous lui attachez une charge trop conséquente. Le tracteur fonctionne à l’opposé, il ne roulera pas vite mais pourra tirer pratiquement n’importe quelle charge.

Pour « scaler » en général on utilise une infrastructure qui permet d’adjoindre de nouveaux serveurs en cas de besoin. Cette faculté doit être prévue par le design, la technologie et l’infrastructure de votre application.
D’aucun pourrait dire qu’adjoindre des serveurs est idiot puisqu’il suffit d’upgrader le matériel (mettre un meilleur cpu et plus de ram). D’une part les upgrade matériels ne sont pas infini, la motherboard ne peut pas accepter un nombre illimité de processeurs ou de barettes de RAM. D’autre part si un processus mange 100% de votre temps CPU sur le processeur, il pénalisera d’office le reste des utilisateurs. Sur des serveurs différents, ce problème est moins grave, un serveur bloqué ne bloquera pas forcément les autres.

La question à se poser lors du design est simple:
Que se passe-t-il si j’ajoute un nouveau serveur ?
Si le design initiale ne marche pas il faut tenter de déterminer pourquoi.

L’un des problèmes fondamentaux est la réplication des sessions utilisateurs d’un serveur vers un autre (concevoir une architecture statefull). Heureusement, il existe des techniques pour solutionner ce genre de problèmes.

Conclusion

Existe-t-il des meilleurs outils de développements (meilleures technologies) pour être scalable ou pas ?
Ma réponse serait non, car la scalabilité est avant tout un problème de design, si vous avez mal conçu votre architecture, quelque soit le langage utilisé, votre application ne pourra pas être étendue facilement.
D’un autre côté si la scalabilité n’est pas forcément liée à l’optimisation, ce n’est pas pour autant que l’on peut programmer n’importe comment sans rien n’optimiser. Si le but est de conserver un temps de réponse constant quelque soit le nombre d’utilisateurs, ce temps de réponse doit tout de même être acceptable !