Introduction
Par rapport à d'autres langages open source tels que Perl et Python, la communauté PHP manque d'efforts importants pour développer des bibliothèques mathématiques.
Une des raisons à cela peut être qu'il existe déjà un grand nombre d'outils mathématiques matures, ce qui peut entraver les efforts de la communauté pour développer elle-même des outils PHP. Par exemple, j'ai travaillé sur un outil puissant, S System, doté d'un ensemble impressionnant de bibliothèques statistiques, spécialement conçu pour analyser des ensembles de données et qui a remporté un prix ACM en 1998 pour la conception de son langage. Si S ou son cousin open source R n'est qu'un appel exec_shell, pourquoi se donner la peine d'implémenter la même fonctionnalité de calcul statistique en PHP ? Pour plus d’informations sur le système S, son ACM Award ou R, consultez les références associées.
N'est-ce pas un gaspillage d'énergie pour les développeurs ? Si la motivation pour développer une bibliothèque mathématique PHP est d'économiser les efforts des développeurs et d'utiliser le meilleur outil pour le travail, alors le sujet actuel de PHP a du sens.
D’un autre côté, des motivations pédagogiques peuvent encourager le développement de bibliothèques mathématiques PHP. Pour environ 10 % des personnes, les mathématiques constituent un sujet intéressant qui mérite d’être exploré. Pour ceux qui maîtrisent également PHP, le développement d'une bibliothèque mathématique PHP peut améliorer le processus d'apprentissage des mathématiques. En d'autres termes, ne vous contentez pas de lire le chapitre sur les tests T, mais implémentez également un programme capable de calculer l'intermédiaire correspondant. valeurs et les afficher dans un format standard leurs classes.
Grâce à des conseils et à des formations, j'espère démontrer que développer une bibliothèque mathématique PHP n'est pas une tâche difficile et peut représenter un défi technique et d'apprentissage intéressant. Dans cet article, je fournirai un exemple de bibliothèque mathématique PHP, appelé SimpleLinearRegression, qui démontre une approche générale pouvant être utilisée pour développer des bibliothèques mathématiques PHP. Commençons par discuter de quelques principes généraux qui m'ont guidé dans le développement de la classe SimpleLinearRegression.
Principes directeurs
J'ai utilisé six principes généraux pour guider le développement de la classe SimpleLinearRegression.
Créez une classe pour chaque modèle d'analyse.
Utilisez les liens inverses pour développer des cours.
Un grand nombre de getters sont attendus.
Stockez les résultats intermédiaires.
Définissez les préférences pour les API détaillées.
La perfection n'est pas le but.
Examinons chacune de ces lignes directrices plus en détail.
Créez une classe pour chaque modèle d'analyse.
Chaque test ou processus d'analyse majeur doit avoir une classe PHP portant le même nom que le test ou le processus. Cette classe contient des fonctions d'entrée, des fonctions de calcul de valeurs intermédiaires et de valeurs récapitulatives et des fonctions de sortie (. en remplacement des valeurs intermédiaires). Les valeurs et les valeurs récapitulatives sont toutes affichées à l'écran sous format texte ou graphique).
Utilisation du chaînage inverse pour développer des classes
En programmation mathématique, la cible de codage est généralement la valeur de sortie standard qu'une procédure d'analyse (telle que MultipleRegression, TimeSeries ou ChiSquared) souhaite produire. Du point de vue de la résolution de problèmes, cela signifie que vous pouvez utiliser le chaînage arrière pour développer des méthodes de type mathématique.
Par exemple, l'écran de sortie récapitulative affiche les résultats d'une ou plusieurs statistiques récapitulatives. Ces résultats statistiques récapitulatifs reposent sur le calcul de résultats statistiques intermédiaires, et ces résultats statistiques intermédiaires peuvent impliquer des résultats statistiques intermédiaires plus profonds, et ainsi de suite. Cette approche de développement basée sur les backlinks mène au principe suivant.
Attendez-vous à un grand nombre de cours de mathématiques getter
. La plupart du travail de développement de classe consiste à calculer des valeurs intermédiaires et récapitulatives. En pratique, cela signifie que vous ne devriez pas être surpris si votre classe contient de nombreuses méthodes getter qui calculent des valeurs intermédiaires et récapitulatives.
Stockage des résultats intermédiaires
Stocke les résultats d'un calcul intermédiaire dans un objet de résultat afin que vous puissiez utiliser les résultats intermédiaires comme entrée pour les calculs ultérieurs. Ce principe est implémenté dans la conception du langage S. Dans le contexte actuel, ce principe est mis en œuvre en sélectionnant des variables d'instance pour représenter les valeurs intermédiaires calculées et les résultats récapitulatifs.
Définition des préférences pour une API détaillée
Lors du développement d'un schéma de dénomination pour les fonctions membres et les variables d'instance dans la classe SimpleLinearRegression, j'ai découvert que si j'utilisais des noms plus longs (quelque chose comme getSumSquaredError au lieu de getYY2 ) pour décrire les fonctions membres et les variables d'instance, alors cela Il est plus facile de comprendre le contenu opérationnel de la fonction et la signification des variables.
Je n'ai pas complètement abandonné les noms abrégés ; cependant, lorsque j'utilise une forme abrégée d'un nom, je dois essayer de fournir une note qui explique pleinement la signification du nom. Mon point de vue est le suivant : les schémas de dénomination très abrégés sont courants dans la programmation mathématique, mais ils rendent plus difficile la compréhension et la preuve qu'une certaine routine mathématique est correcte qu'elle ne devrait l'être.
La perfection n'est pas l'objectif
Le but de cet exercice de codage n'est pas nécessairement de développer un moteur mathématique hautement optimisé et rigoureux pour PHP. Dans les premiers stades, l'accent doit être mis sur l'apprentissage de la mise en œuvre de tests analytiques significatifs et de la résolution de problèmes difficiles dans ce domaine.
Variables d'instance
Lors de la modélisation d'un test ou d'un processus statistique, vous devez indiquer quelles variables d'instance sont déclarées.
La sélection des variables d'instance peut être déterminée en tenant compte des valeurs intermédiaires et récapitulatives générées par le processus d'analyse. Chaque valeur intermédiaire et récapitulative peut avoir une variable d'instance correspondante, avec la valeur de la variable comme propriété d'objet.
J'ai utilisé cette analyse pour déterminer quelles variables déclarer pour la classe SimpleLinearRegression dans le listing 1. Une analyse similaire peut être effectuée sur les procédures MultipleRegression, ANOVA ou TimeSeries.
Listing 1. Variables d'instance de la classe SimpleLinearRegression
<?php
// Copyright 2003, Paul Meagher
// Distribué sous GPL
classe SimpleLinearRegression {
var$n;
var $X = tableau();
var $Y = tableau();
var $ConfInt;
var $Alpha;
var $XMois;
var $YMoyenne ;
var $SommeXX;
var $SommeXY;
var $SommeYY;
var $Pente;
var $YInt;
var $PredictedY = tableau();
var $Erreur = tableau();
var $SquaredError = tableau();
var $ErreurTotale;
var $SumError;
var $SumSquaredError;
var $ErrorVariance;
var $StdErr;
var $SlopeStdErr;
var $SlopeVal; // Valeur T de la pente
var $YIntStdErr;
var $YIntTVal; // Valeur T pour l'interception Y
var$R;
var $RSquared;
var $DF; // Degrés de liberté
var $SlopeProb; // Probabilité d'estimation de la pente
var $YIntProb; // Probabilité d'estimation de l'interception Y
var $AlphaTVal; // Valeur T pour le paramètre alpha donné
var $ConfIntOfSlope;
var $RPath = "/usr/local/bin/R"; // Votre chemin ici
var $format = "%01.2f"; // Utilisé pour formater la sortie
}
?>
Constructeur
La méthode constructeur de la classe SimpleLinearRegression accepte un vecteur X et un vecteur Y, chacun avec le même nombre de valeurs. Vous pouvez également définir un intervalle de confiance par défaut de 95 % pour votre valeur Y attendue.
La méthode constructeur commence par vérifier que le formulaire de données est adapté au traitement. Une fois que les vecteurs d'entrée réussissent les tests de « taille égale » et de « valeur supérieure à 1 », la partie centrale de l'algorithme est exécutée.
L'exécution de cette tâche implique le calcul des valeurs intermédiaires et récapitulatives du processus statistique via une série de méthodes getter. Attribuez la valeur de retour de chaque appel de méthode à une variable d'instance de la classe. Le stockage des résultats de calcul de cette manière garantit que les valeurs intermédiaires et récapitulatives sont disponibles pour les routines d'appel dans les calculs chaînés. Vous pouvez également afficher ces résultats en appelant la méthode de sortie de cette classe, comme décrit dans le listing 2.
Listing 2. Appel des méthodes de sortie de classe
<?php
// Copyright 2003, Paul Meagher
// Distribué sous GPL
fonction SimpleLinearRegression($X, $Y, $ConfidenceInterval="95") {
$numX = nombre($X);
$numY = nombre($Y);
si ($numX != $numY) {
die("Erreur : la taille des vecteurs X et Y doit être la même.");
}
si ($numX <= 1) {
die("Erreur : la taille du tableau d'entrée doit être d'au moins 2.");
}
$this->n = $numX ;
$this->X = $X ;
$this->Y = $Y ;
$this->ConfInt = $ConfidenceInterval ;
$this->Alpha = (1 + ($this->ConfInt / 100) ) / 2;
$this->XMean = $this->getMean($this->X);
$this->YMean = $this->getMean($this->Y);
$this->SumXX = $this->getSumXX();
$this->SumYY = $this->getSumYY();
$this->SumXY = $this->getSumXY();
$this->Slope = $this->getSlope();
$this->YInt = $this->getYInt();
$this->PredictedY = $this->getPredictedY();
$this->Erreur = $this->getError();
$this->SquaredError = $this->getSquaredError();
$this->SumError = $this->getSumError();
$this->TotalError = $this->getTotalError();
$this->SumSquaredError = $this->getSumSquaredError();
$this->ErrorVariance = $this->getErrorVariance();
$this->StdErr = $this->getStdErr();
$this->SlopeStdErr = $this->getSlopeStdErr();
$this->YIntStdErr = $this->getYIntStdErr();
$this->SlopeTVal = $this->getSlopeTVal();
$this->YIntTVal = $this->getYIntTVal();
$this->R = $this->getR();
$this->RSquared = $this->getRSquared();
$this->DF = $this->getDF();
$this->SlopeProb = $this->getStudentProb($this->SlopeTVal, $this->DF);
$this->YIntProb = $this->getStudentProb($this->YIntTVal, $this->DF);
$this->AlphaTVal = $this->getInverseStudentProb($this->Alpha, $this->DF);
$this->ConfIntOfSlope = $this->getConfIntOfSlope();
renvoie vrai ;
}
?>
Les noms des méthodes et leurs séquences ont été dérivés d'une combinaison de backlinking et de référence à un manuel de statistiques utilisé par les étudiants de premier cycle, qui explique étape par étape comment calculer les valeurs intermédiaires. Le nom de la valeur intermédiaire que je dois calculer est préfixé par « get », dérivant ainsi le nom de la méthode.
Ajuster le modèle aux données
La procédure SimpleLinearRegression est utilisée pour produire un ajustement de ligne droite aux données, où la ligne a l'équation standard suivante :
y = b + mx
Le format PHP de cette équation ressemble à celui du Listing 3 :
Listing 3. Ajuster le modèle aux données Correspondance de l'équation PHP
$PredictedY[$i] = $YIntercept + $Slope * $X[$i]
La classe SimpleLinearRegression utilise le critère des moindres carrés pour dériver des estimations des paramètres d'ordonnée à l'origine (Y Intercept) et de pente (Slope). Ces paramètres estimés sont utilisés pour construire une équation linéaire (voir Listing 3) qui modélise la relation entre les valeurs X et Y.
À l’aide de l’équation linéaire dérivée, vous pouvez obtenir la valeur Y prévue pour chaque valeur X. Si l'équation linéaire correspond bien aux données, alors les valeurs observées et prédites de Y ont tendance à être cohérentes.
Comment déterminer s'il existe un bon ajustement
La classe SimpleLinearRegression génère un certain nombre de valeurs récapitulatives. Une valeur récapitulative importante est la statistique T, qui mesure dans quelle mesure une équation linéaire s'adapte aux données. Si l’accord est très bon, la statistique T aura tendance à être grande. Si la statistique T est petite, alors l'équation linéaire doit être remplacée par un modèle qui suppose que la moyenne des valeurs Y est le meilleur prédicteur (c'est-à-dire que la moyenne d'un ensemble de valeurs est généralement un prédicteur utile de l’observation suivante, faites-en le modèle par défaut).
Pour tester si la statistique T est suffisamment grande pour ne pas considérer la moyenne des valeurs Y comme le meilleur prédicteur, vous devez calculer la probabilité aléatoire d'obtenir la statistique T. Si la probabilité d'obtenir une statistique T est faible, vous pouvez alors rejeter l'hypothèse nulle selon laquelle la moyenne est le meilleur prédicteur et, par conséquent, être sûr que le modèle linéaire simple s'adapte bien aux données.
Alors, comment calculer la probabilité de la valeur statistique T ?
Calcul de la probabilité de la valeur statistique T
Puisque PHP manque de routines mathématiques pour calculer la probabilité de la valeur statistique T, j'ai décidé de laisser cette tâche au package de calcul statistique R (voir www.r-project.org dans Ressources) pour obtenir les valeurs nécessaires. Je souhaite également attirer l'attention sur ce package car :
R fournit de nombreuses idées qu'un développeur PHP pourrait émuler dans une bibliothèque mathématique PHP.
Avec R, il est possible de déterminer si les valeurs obtenues à partir de la bibliothèque mathématique PHP sont cohérentes avec celles obtenues à partir de packages statistiques open source matures et disponibles gratuitement.
Le code du listing 4 montre à quel point il est facile de laisser R obtenir une valeur.
Listing 4. Gestion du package statistique R pour obtenir une valeur
<?php
// Copyright 2003, Paul Meagher
// Distribué sous GPL
classe SimpleLinearRegression {
var $RPath = "/usr/local/bin/R"; // Votre chemin ici
fonction getStudentProb($T, $df) {
$Probabilité = 0,0 ;
$cmd = "echo 'dt($T, $df)' | $this->RPath --slave";
$result = shell_exec($cmd);
list($LineNumber, $Probability) = éclater(" ", trim($result));
retourner $Probabilité ;
}
fonction getInverseStudentProb($alpha, $df) {
$InverseProbabilité = 0,0 ;
$cmd = "echo 'qt($alpha, $df)' | $this->RPath --slave";
$result = shell_exec($cmd);
list($LineNumber, $InverseProbability) = éclater(" ", trim($result));
retourner $InverseProbability ;
}
}
?>
Notez que le chemin d'accès à l'exécutable R a été défini et utilisé dans les deux fonctions. La première fonction renvoie la valeur de probabilité associée à la statistique T en fonction de la distribution T de Student, tandis que la deuxième fonction inverse calcule la statistique T correspondant au paramètre alpha donné. La méthode getStudentProb est utilisée pour évaluer l'ajustement du modèle linéaire ; la méthode getInverseStudentProb renvoie une valeur intermédiaire, qui est utilisée pour calculer l'intervalle de confiance pour chaque valeur Y prévue.
En raison de l'espace limité, il m'est impossible de détailler toutes les fonctions de cette classe une par une, donc si vous souhaitez comprendre la terminologie et les étapes impliquées dans une analyse de régression linéaire simple, je vous encourage à vous référer au manuel de statistiques utilisé. par des étudiants de premier cycle.
Étude d'épuisement professionnel
Pour démontrer comment utiliser ce cours, je peux utiliser les données d'une étude d'épuisement professionnel dans un utilitaire. Michael Leiter et Kimberly Ann Meechan ont étudié la relation entre une mesure de l'épuisement professionnel appelée indice d'épuisement et une variable indépendante appelée concentration. La concentration fait référence à la proportion de contacts sociaux d'une personne provenant de son environnement de travail.
Pour étudier la relation entre les valeurs de l'indice de consommation et les valeurs de concentration pour les individus de leur échantillon, chargez ces valeurs dans un tableau portant le nom approprié et instanciez cette classe avec ces valeurs de tableau. Après avoir instancié une classe, affichez quelques valeurs récapitulatives générées par la classe pour évaluer dans quelle mesure le modèle linéaire s'adapte aux données.
Le listing 5 montre un script qui charge les données et affiche les valeurs récapitulatives :
Listing 5. Script qui charge les données et affiche les valeurs récapitulatives
<?php
// BurnoutStudy.php
// Copyright 2003, Paul Meagher
// Distribué sous GPL
inclure "SimpleLinearRegression.php" ;
// Charger les données de l'étude d'épuisement professionnel
$Concentration = tableau(20,60,38,88,79,87,
68,12,35,70,80,92,
77,86,83,79,75,81,
75,77,77,77,17,85,96);
$ExhaustionIndex = tableau(100 525 300 980 310 900,
410 296 120 501 920 810,
506 493 892 527 600 855,
709.791.718.684.141.400.970);
$slr = nouveau SimpleLinearRegression($Concentration, $ExhaustionIndex);
$YInt = sprintf($slr->format, $slr->YInt);
$Slope = sprintf($slr->format, $slr->Slope);
$SlopeTVal = sprintf($slr->format, $slr->SlopeTVal);
$SlopeProb = sprintf("%01.6f", $slr->SlopeProb);
?>
<table border='1' cellpadding='5'>
<tr>
<th align='right'>Équation :</th>
<td></td>
</tr>
<tr>
<th align='right'>T :</th>
<td></td>
</tr>
<tr>
<th align='right'>Prob > T :</th>
<td><td>
</tr>
</table>
L'exécution de ce script via un navigateur Web produit le résultat suivant :
Équation : Épuisement = -29,50 + (8,87 * Concentration)
T : 6.03
Prob > T : 0,000005
La dernière ligne de ce tableau indique que la probabilité aléatoire d’obtenir une valeur T aussi élevée est très faible. On peut conclure qu’un modèle linéaire simple a un meilleur pouvoir prédictif que la simple utilisation de la moyenne des valeurs de consommation.
Connaître la concentration de relations sur le lieu de travail d'une personne peut être utilisée pour prédire le niveau d'épuisement professionnel qu'elle pourrait consommer. Cette équation nous dit : pour chaque augmentation d'une unité de la valeur de concentration, la valeur de consommation d'une personne dans le domaine des services sociaux augmentera de 8 unités. Cela prouve une fois de plus que pour réduire le risque d’épuisement professionnel, les personnes travaillant dans les services sociaux devraient envisager de se faire des amis en dehors de leur lieu de travail.
Ceci n’est qu’une esquisse de ce que ces résultats pourraient signifier. Pour explorer pleinement les implications de cet ensemble de données, vous souhaiterez peut-être étudier les données plus en détail pour vous assurer qu'il s'agit de la bonne interprétation. Dans le prochain article, je discuterai des autres analyses à effectuer.
Qu'avez-vous appris ?
D'une part, vous n'avez pas besoin d'être un génie pour développer des packages mathématiques significatifs basés sur PHP. En adhérant aux techniques standard orientées objet et en adoptant explicitement des méthodes de résolution de problèmes de chaînage inverse, il est relativement facile d'utiliser PHP pour implémenter certains des processus statistiques les plus élémentaires.
D'un point de vue pédagogique, je pense que cet exercice est très utile, ne serait-ce que parce qu'il nécessite de réfléchir à des tests ou à des routines statistiques à des niveaux d'abstraction plus ou moins élevés. En d’autres termes, un excellent moyen de compléter vos tests statistiques ou votre apprentissage procédural consiste à implémenter la procédure sous forme d’algorithme.
La mise en œuvre de tests statistiques nécessite souvent d'aller au-delà des informations fournies et de résoudre et de découvrir de manière créative les problèmes. C’est aussi un bon moyen de découvrir des lacunes dans les connaissances sur un sujet.
Par contre, vous constatez que PHP manque de moyens inhérents pour échantillonner les distributions, ce qui est nécessaire pour implémenter la plupart des tests statistiques. Vous devrez laisser R effectuer le traitement pour obtenir ces valeurs, mais je crains que vous n'ayez ni le temps ni l'intérêt d'installer R. Les implémentations PHP natives de certaines fonctions de probabilité courantes peuvent résoudre ce problème.
Autre problème : la classe génère de nombreuses valeurs intermédiaires et récapitulatives, mais la sortie récapitulative n'en profite pas réellement. J'ai fourni des résultats lourds, mais ils ne sont ni suffisants ni bien organisés pour que vous puissiez interpréter correctement les résultats de l'analyse. En fait, je n’ai absolument aucune idée de comment intégrer la méthode de sortie dans cette classe. Il faut remédier à cette situation.
Enfin, pour donner un sens aux données, il ne suffit pas d’examiner les valeurs récapitulatives. Vous devez également comprendre comment les points de données individuels sont distribués. L’une des meilleures façons d’y parvenir est de représenter graphiquement vos données. Encore une fois, je n'y connais pas grand-chose, mais si vous souhaitez utiliser cette classe pour analyser des données réelles, vous devez résoudre ce problème.