Données disponibles';
$nb_station = count(array_keys($hype_data));
//$nb_parametre = count(array_unique (array_column($hype_data, 'CODE_PARAMETRE')));
//$nb_chronique = count(array_unique (array_column($hype_data, 'CHRONIQUE')));
//$output.='
'.$nb_chronique.' chronique(s) correspondant à '.$nb_station.' point(s) de prélèvement et '.$nb_parametre.' paramètre(s) ont été lues.
';
$output.=''.$nb_station.' point(s) de prélèvement
';
//$output.= theme(
// 'table',
// [
// 'header'=>array_keys($hype_data[0]),
// 'rows'=>$hype_data
// ]
//);
$output.='Caractérisation';
//Tri par date du jeu de données
//array_multisort (array_column($hype_data, 'DATE_DEBUT_PRELEVEMENT'), SORT_ASC, $hype_data);
//$carac = hype_caracterisation($hype_data);
//dsm($carac);
$output.='Tendances/Ruptures';
//dsm($hype_data);
$tmp =[];
$tmp['06594X0019/S'] = $hype_data['06594X0019/S'];
//$tmp['06363X0017/SOURCE'] = $hype_data['06363X0017/SOURCE'];
//krumo($tmp);
$tendance = hype_tendance($tmp);
//$tendance = hype_tendance($hype_data);
krumo($tendance);
}*/
//============================================ Tendances
function hype_tendance($data){
$tendance = [];
//krumo($data);
//exit();
foreach($data as $code=>$stq){
foreach($stq as $cdpar=>$items){
//stat caracterisation generale
$chronique = $items['CHRONIQUE'];
//Tri par date du jeu de données
array_multisort (array_column($chronique , 'DATE_PREL'), SORT_ASC, $chronique );
//array_multisort (array_column($chronique , 'RESULTAT_TH'), SORT_ASC, $chronique );
$carac = hype_caracterisation_chronique($chronique);
//krumo($carac);
//Calcul des dates de rupture avec la P-value pour le test de Pettitt et pour le test de Buishand 1 si c'est significatif 0 si ça ne l'est pas
//test de Pettitt si données non normalement distribuée
//if(pval_shapi[i]<0.05&&is.na(pval_shapi[i])==FALSE){
//Si la pop est <= 3 on ne va même pas plus loin
if($carac['population']>3 && $carac['pval_shapi']){
//test de Pettitt si données non normalement distribuée
if($carac['pval_shapi'] < 0.05){
$carac['testrupt_graph']='Pettitt';
$carac['test_rupt']='test non paramétrique de Pettitt';
$Pettitt = hype_tendance_pettitt(array_column($chronique, 'RESULTAT_TH'));
$carac['rupt_pvalue'] = $Pettitt['pvalue'];
//Si pas rupture
if($Pettitt['pvalue']<=0.05){
$carac['pres_rupt'] = "non";
$carac['rupt_graph1'] = "Pas de rupture significative détectée";
$carac['pres_rupt'] = "";
$carac['rupt'] = null;
}
//SI rupture
else{
$carac['pres_rupt'] = "oui";
$carac['rupt'] = $chronique[$Pettitt['key']]['DATE_DEBUT_PRELEVEMENT']; //DATE_PREL
}
}
//test de Buishand si données normalement distribuées et population >=10
elseif($carac['pval_shapi']>=0.05 && $carac['population']>=10){
$carac['testrupt_graph']='Buishand';
$carac['test_rupt']='test paramétrique de Buishand';
$bu = hype_tendance_bu($data);
if($bu['pvalue']<=0.05){
$carac['pres_rupt'] = "oui";
$carac['rupt'] = $chronique[$bu['key']]['DATE_DEBUT_PRELEVEMENT'];
}else{
$carac['pres_rupt'] = "non";
$carac['rupt_graph1'] = "Pas de rupture significative détectée";
$carac['pres_rupt'] = "";
$carac['rupt'] = null;
}
}
else{
$carac['sig_ruptB']=null;
$carac['pval_rupt']=null;
$carac['rupt']=null;
$carac['pres_rupt'] = "trop peu de données";
$carac['rupt_graph1'] = "Non effectué (pas assez de données)";
$carac['rupt_graph2']='';
$carac['testrupt_graph']='';
$carac['test_rupt']='';
}
//krumo($carac);
}
//"chronique stationnaire"
else{
$carac['sig_ruptB']=null;
$carac['pval_rupt']=null;
$carac['rupt']=null;
$carac['pres_rupt'] = "chronique stationnaire";
$carac['rupt_graph1'] = "Non effectué";
$carac['rupt_graph2']='';
$carac['testrupt_graph']='';
$carac['test_rupt']='';
}
//Si les données sont autocorrélées
if($carac['autocorr_test']){
if($carac['population'] > 40){
$mk = hype_tendance_mk_modif(array_column($chronique , 'RESULTAT_TH'), 0.95);
$carac['pval_mkmodif'] = $mk['cpvalue'];
$carac['test_toto'] = $mk['pvalue'];
$carac['tau_mkmodif'] = $mk['tau'];
if($mk['cpvalue'] && $mk['cpvalue'] <= 0.05){
$carac['text_mkmodif'] = "Un test de Mann-Kendall modifié a été appliqué. Une tendance significative est détectée.";
}
else{
$carac['text_mkmodif'] ="Un test de Mann-Kendall modifié a été appliqué. Aucune tendance significative n'est détectée.";
}
$carac['tendMKmodif_graph1'] = "";
$carac['tendMKmodif_graph2'] = $mk['cpvalue'];
}
else{
$carac['text_mkmodif'] = "Les données sont autocorrélées mais il n'y a pas suffisamment de données pour appliquer un test de Mann-Kendall modifié.";
$carac['tendMKmodif_graph1'] = "Non effectué (pas assez de données)";
$carac['tendMKmodif_graph2'] = "";
$carac['pval_mkmodif'] = null;
}
}
else{
$carac['tendMKmodif_graph1'] = "Non effectué (pas assez de données)";
$carac['tendMKmodif_graph2'] = "";
$carac['text_mkmodif'] = "Les données ne sont pas autocorrélées. Le test de Mann-Kendall modifié n'a donc pas été appliqué.";
$carac['pval_mkmodif'] = null;
}
#Pour toutes les chroniques : Mann-Kendall
if(count(array_unique(array_column($chronique, 'RESULTAT_TH'))) > 1){
$carac['tend'] = "La chronique est stationnaire";
$carac['tendMK_graph1'] = "Chronique stationnaire";
$carac['tendL_graph1'] = "Chronique stationnaire";
$carac['tendMK_graph2'] = "";
$carac['tendL_graph2'] = "";
$carac['interc'] = null;
$carac['slope_Sen_an'] = null;
$carac['rcarre'] = null;
$carac['pval_lin'] = null;
$carac['pente_lin_an'] = null;
$carac['interc_lin'] = null;
$carac['tend_lin'] = "La chronique est stationnaire";
}
else{
#Mann-Kendall
//si au moins 10 analyses
if (count($chronique) >=10) {
$cor = hype_tendance_cor(array_column($chronique, 'RESULTAT_TH'), array_column($chronique, 'DATE_PREL'), 'everything','kendall');
$carac['pval_mk'] = $cor['pvalue'];
if($carac['pval_mk'] == 0 )$carac['pval_graph'] ="<2.2e-16";
else{$carac['pval_graph'] =$cor['pvalue'];}
$carac['estimate_mk'] = $cor['estimate'];
#Calcul pente de Sen
if ($carac['pval_mk']<=0.05){
//============================ TODO ========================================================================
/*
donneesx<-outer(donnees,donnees,"-")
datex<-outer(date_an,date_an,"-")
z<-donneesx/matrix(as.numeric(datex),ncol=nbr_anal[i])
s<-z[lower.tri(z)]
slope_Sen[i]<-median(s,na.rm=TRUE)
if (slope_Sen[i]==0) {
if(estimate_mk[i]<0) {slope_Sen[i]<-max(s[which(s<0)])}
else {slope_Sen[i]<-min(s[which(s>0)])}
}
slope_Sen_an[i]<-slope_Sen[i]*365
#Calcul intercept (Conover,1980)
interc[i]<-median(donnees,na.rm=TRUE)-slope_Sen[i]*as.numeric(median(date_an,na.rm=TRUE))
tend[i]<-paste("Un test de tendance de Mann-Kendall a été appliqué. Une tendance significative de pente",format(slope_Sen[i]*365,digits=3),unite,"/an est détectée.")
tendMK_graph1<-paste(format(slope_Sen[i]*365,digits=3,scientific=TRUE),unite,"/an")
*/
$carac['tendMK_graph2']=$carac['pval_graph'];
}
else{
$carac['tend']="Un test de tendance de Mann-Kendall a été appliqué. Aucune tendance significative n'est détectée";
$carac['tendMK_graph1']="Aucune tendance significative détectée";
$carac['tendMK_graph2']=$carac['pval_graph'];
$carac['interc']=null;
$carac['slope_Sen_an']=null;
}
}
else{
$carac['tend'] = "Il n'y a pas assez de données pour effectuer un test de tendance de Mann-Kendall.";
$carac['tendMK_graph1'] = "Non effectué (pas assez de données)";
$carac['tendMK_graph2'] = "";
$carac['interc'] = null;
$carac['slope_Sen_an'] = null;
$carac['pval_mk'] = null;
$carac['estimate_mk'] = null;
}
}
$tendance[$code.'_'.$cdpar] = $carac;
}
}
return $tendance;
}
function hype_tendance_cor($x, $y, $use, $method){
$mk_modif = db_query("
WITH cor AS (SELECT r_cor(ARRAY[".implode(', ', $x)."], ARRAY[".implode(', ', $y)."], '".$use."', '".$method."') as mk_modif)
SELECT cor[1] as pvalue, cor[2] as estimate
FROM test
")->fetchAssoc();
return $cor;
}
//Test de Mann Kendal modifié
function hype_tendance_mk_modif($data, $ci = 0.95){
$mk_modif = db_query("
WITH test AS (SELECT r_mk_modif(ARRAY[".implode(', ', $data)."], ".$ci.") as mk_modif)
SELECT mk_modif[1] as z, mk_modif[2] as pvalue, mk_modif[3] as zc, mk_modif[4] as cpvalue, mk_modif[5] as tau, mk_modif[6] as nns, mk_modif[7] as sen_slope,
FROM test
")->fetchAssoc();
return $mk_modif;
}
/*-------------------------------------------------------------------------------
* Breakpoint detection in a time series according to Pettitt 1979
* R script by Pascal Haenggi, v20090819
*-------------------------------------------------------------------------------
* x = time series with 1. column: year and 2. column: value
* alpha = significance level for test, e.g. 0.05
*/
function hype_tendance_pettitt($data){
$pettitt = db_query("
WITH test AS (SELECT r_pettitt(ARRAY[".implode(', ', $data)."]) as pettitt)
SELECT pettitt[1] as statistic, pettitt[2] as pvalue, pettitt[3] as nobs, pettitt[4] as key
FROM test
")->fetchAssoc();
return $pettitt;
}
//Buishand U Test (Buishand, 1984), Breakpoint detection in a time series
function hype_tendance_bu($data){
$bu = db_query("
WITH test AS (SELECT r_bu(ARRAY[".implode(', ', $data)."]) as bu)
SELECT bu[1] as statistic, bu[2] as pvalue, bu[3] as key
FROM test
")->fetchAssoc();
return $bu;
}
//============================================ Caracterisation
function hype_caracterisation($data){
$carac = [];
//krumo($data);
foreach($data as $code=>$stq){
foreach($data as $code=>$stq){
foreach($stq as $cdpar=>$items){
//id_chronique = $code.'_'.$cdpar
$carac[$code.'_'.$cdpar] = hype_caracterisation_chronique($items['CHRONIQUE']);
}
}
}
return $carac;
}
function hype_caracterisation_chronique($chronique){
//Stat générale ==> nécessite R
$stats = hype_caracterisation_general(array_column($chronique, 'RESULTAT_TH'));
//==============Taux de quantification - LQs
$lqs = hype_caracterisation_lqs($chronique, $stats);
//Calcul de la moyenne et de l'écart-type des écarts entre deux dates d'analyses
$prel = array_column($chronique, 'DATE_PREL');
sort($prel);
$ecarts = hype_caracterisation_get_ecarts($prel, (3600*24));
$ecarts_stat = hype_caracterisation_general($ecarts);
//identification d'outliers dans la fréquence de prélèvements
$ecarts_stat2 = hype_caracterisation_ecarts2($ecarts, $ecarts_stat);
//test de Shapiro-Wilk
$shapiro = hype_caracterisation_shapiro(array_column($chronique, 'RESULTAT_TH'));
//Autocorrélation des données
//FIX ME : le correlation doit-elle se faire sur les résultats d'analyse ou sur les dates de prélévement
$correlation = hype_caracterisation_correlation($chronique);
//dsm($stats);
return [
"date_min"=>date('Y-m-d', min(array_column($chronique, 'DATE_PREL'))),
"date_max"=>date('Y-m-d', max(array_column($chronique, 'DATE_PREL'))),
"duree"=>(max(array_column($chronique, 'DATE_PREL')) - min(array_column($chronique, 'DATE_PREL')))/(3600*24), //en jour
"population"=>count($chronique),
"moyenne"=>$stats['avg'],
"mediane"=>$stats['p50'],
"percentil1"=>$stats['p25'],
"percentil2"=>$stats['p75'],
"taux_quanti"=>$lqs["taux_quanti"],
"ecarttype"=>$stats['stddev'],
"pval_shapi"=>$shapiro['p.value'],
"normalite"=>$shapiro['normalite'],
"normalite_chart"=>$shapiro['chart'],
"LQmin"=>$lqs["LQmin"],
"LQmax"=>$lqs["LQmax"],
"LQmin2"=>$lqs["LQmin2"],
"LQmax2"=>$lqs["LQmax2"],
"text_med"=>$lqs["LQmessage_p50"],
"text_perc1"=>$lqs["LQmessage_p25"],
"text_perc2"=>$lqs["LQmessage_p75"],
"moy_ecarts"=>isset($ecarts_stat['avg'])?$ecarts_stat['avg']:null,
"med_ecarts"=>isset($ecarts_stat['p50'])?$ecarts_stat['p50']:null,
"ec_typ_ecarts"=>isset($ecarts_stat['stddev'])?$ecarts_stat['stddev']:null,
"moy_ecarts2"=>isset($ecarts_stat2['avg'])?$ecarts_stat2['avg']:null,
"ec_typ_ecarts2"=>isset($ecarts_stat2['stddev'])?$ecarts_stat2['stddev']:null,
"autocorr_r1"=>$correlation['autocorr_r1'],
"autocorr_test"=>$correlation['result'],
"signif_autocorr"=>$correlation['analyse'],
"signif_autocorr_short"=>$correlation['short'],
"test_unite"=>count(array_unique(array_column($chronique, 'UNITE_GRAPH')))>1 ? false:true, //Si une seule unité tout va bien (valeur = true), sinon mettte false qui permettra d'alerter l'utilisateur sur la fait que son jeu de données contient plusieurs unités
];
}
#identification d'outliers dans la fréquence de prélèvements
function hype_caracterisation_ecarts2($ecarts, $stat){
$e2 = [];
if(!empty($ecarts)){
$cap = ($stat['p50']+2) * $stat['stddev'];
$ecarts2 = array_filter($ecarts, create_function('$v', 'return $v>='. $cap .';'));
if(!empty($ecarts2)){
$e2 = hype_caracterisation_general($ecarts2);
}else{
$e2 = $stat;
}
}
return $e2;
}
function hype_caracterisation_get_ecarts($src, $divide = 1){
$ecarts = [];
if(!empty($src)){
$nb = count($src);
for($i=0;$inull,
"LQmax"=>null,
"LQmin2"=>null,
"LQmax2"=>null,
"taux_quanti"=>null,
"LQmessage_p25"=>'',
"LQmessage_p50"=>'',
"LQmessage_p75"=>''
];
if(!empty($chronique)){
$nb_ana = count($chronique);
$nb_quanti = 0;
foreach($chronique as $ana){
if($ana['CODE_SIGNE']==1){
$nb_quanti++;
}
else{
//LQmin
if(is_null($lqs['LQmin']) || $ana['RESULTAT']<$lqs['LQmin']){
$lqs['LQmin'] = $ana['RESULTAT'];
}
//LQmax
if(is_null($lqs['LQmax']) || $ana['RESULTAT']>$lqs['LQmax']){
$lqs['LQmax'] = $ana['RESULTAT'];
}
if($ana['CODE_SIGNE']==10){
//LQmin2
if(is_null($lqs['LQmin2']) || $ana['RESULTAT']<$lqs['LQmin2']){
$lqs['LQmin2'] = $ana['RESULTAT'];
}
//LQmax2
if(is_null($lqs['LQmax2']) || $ana['RESULTAT']>$lqs['LQmax2']){
$lqs['LQmax2'] = $ana['RESULTAT'];
}
}
}
}
#Remarque dans le cas où mediane/decile$stats['p25']){
$lqs['LQmessage_p25'] ="Attention : la valeur du premier quartile est inférieure à la limite de quantification maximale
";
}
if($lqs['LQmax']>$stats['p50']){
$lqs['LQmessage_p50'] ="Attention : la valeur de la médiane est inférieure à la limite de quantification maximale
";
}
if($lqs['LQmax']>$stats['p75']){
$lqs['LQmessage_p75'] ="Attention : la valeur du dernier quartile est inférieure à la limite de quantification maximale
";
}
$lqs['taux_quanti'] = ($nb_quanti/$nb_ana)*100; //on veux des %
}
return $lqs;
}
//Permet la caractérisation d'un jeu de données en utilisant les fonctions PLR (Postgres + R)
function hype_caracterisation_general($item){
//krumo($item);
$r =[];
if(!empty($item)){
//=================== stat de base
$r = db_query("
WITH data AS (SELECT unnest(ARRAY[".implode(', ', $item)."]) as src)
SELECT
min(data.src) as min,
max(data.src) as max,
avg(data.src) as avg,
variance(data.src) as variance,
stddev(data.src) as stddev,
r_quantile(array_accum(data.src), 0.25) as p25,
r_quantile(array_accum(data.src), 0.50) as p50,
r_quantile(array_accum(data.src), 0.75) as p75,
r_quantile(array_accum(data.src), 0.90) as p90
FROM data;
")->fetchAssoc();
$r['pop'] = count($item);
}
return $r;
}
#Autocorrélation des données
function hype_caracterisation_correlation($item){
$correlation = [];
//Tri par date du jeu de données
array_multisort (array_column($item, 'RESULTAT_TH'), SORT_ASC, $item);
#Autocorrélation au rang 1
$rank = 3; //n° de rang + 1 (dans acf l'index 0 vaut 1) + 1 dans pg, les index commencent à 1 pas à 0
$autocorr_r1 = db_query("
WITH acf AS (SELECT r_acf(ARRAY[".implode(', ', array_column($item, 'RESULTAT'))."], 'correlation', FALSE) as data)
SELECT acf.data[".$rank."][1][1] as rank
FROM acf
")->fetchColumn(0);
$correlation['autocorr_r1'] = $autocorr_r1;
if($autocorr_r1){
#Significativité de l'autocorrélation au seuil de 5%
$qnorm = db_query("SELECT r_qnorm((1 + 0.95)/2) as qnorm")->fetchColumn(0);
$seuil = $qnorm / sqrt(count($item));
if(abs($autocorr_r1) > abs($seuil)){
$correlation['analyse'] = "La probabilité que les données soient autocorrélées au rang 1 est supérieure à 95%";
$correlation['short'] = "Données autocorrélées";
$correlation['result'] = true;
}
else {
$correlation['analyse'] = "Il est peu probable que les données soient autocorrélées";
$correlation['short'] ="Données non autocorrélées";
$correlation['result'] = false;
}
}else{
$correlation['analyse'] = "L'autocorrélation des données n'a pas pu être testée.";
$correlation['short'] ="Données non autocorrélées";
$correlation['result'] = null;
}
return $correlation;
}
function hype_caracterisation_shapiro($item){
//krumo($item);
if(!empty($item)){
//===============Shapiro
//Si pop <= 3 on ne peut pas faire le test de shapiro
//Si toutes les valeurs sont identiques on ne pas peux pas faire le shapiro non plus
if(count($item)<=3){
$shapiro=[
'p.value'=>false,
'normalite'=>"Il n'y a pas assez de données pour estimer la normalité de la distribution",
'chart'=>"Test de normalité non effectué"
];
}
//Si toutes les valeurs sont identiques on ne pas peux pas faire le shapiro non plus
elseif(count(array_unique($item))==1){
$shapiro=[
'p.value'=>false,
'normalite'=>"Toutes les valeurs sont identiques. Le test de Shapiro-Wilk n'a pas été appliqué.",
'chart'=>"Chronique stationnaire"
];
}
//on tente le Shapiro
else{
$sh = db_query("SELECT r_shapiro(ARRAY[".implode(', ', $item)."]) as pvalue")->fetchAssoc();
if($sh['pvalue']>=0.05){
$shapiro=[
'p.value'=>$sh['pvalue'],
'normalite'=>"Un test de Shapiro-Wilk a été appliqué. Les données de cette chronique sont normalement distribuées",
'chart'=>"Données normalement distribuées"
];
}
else{
$shapiro=[
'p.value'=>$sh['pvalue'],
'normalite'=>"Un test de Shapiro-Wilk a été appliqué. Les données de cette chronique ne sont pas normalement distribuées",
'chart'=>"Données non normalement distribuées"
];
}
}
}
return $shapiro;
}