Moyenne des Max avec critères

Softmama

XLDnaute Accro
Bonjour à tous,

Je bloque pour obtenir une formule qui renverrait la moyenne des max selon critères.
Pour plus de clarté j'ai préparé un petit fichier.
J'y ai noté mes avancées et ce que j'aimerais obtenir à partir d'un exemple très simplifié.
Je n'ai pas trouvé de réponse adaptée dans mes recherches sur le forum et compte donc sur vous pour m'aider.

Par avance un grand merci à ceux qui se pencheront sur mon problème.

Soft
 

Pièces jointes

  • FormuleMoyenneMaxisAvecCritères.xlsx
    17.5 KB · Affichages: 42

Modeste

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Salut Softmama (ça faisait longtemps :eek:),

Fidèle à mon habitude, je ne suis pas certain d'avoir compris!
Faire la même chose en une seule formule, je ne l'imagine même pas (avec les mêmes formules "intermédiaires" et matricielle que toi, ça va ... mais au-delà, mon ticket n'est plus valable et il est dangereux de se pencher à l'extérieur!)

Ça vaut donc ce que ça vaut ... une proposition par fonction personnalisée, dans la pièce jointe (vba, donc!)

Je me suis permis de redéfinir les références des plages "Coul_Cherchée" et "Obj_Cherché", respectivement en E6 et E7.
 

Pièces jointes

  • FormuleMoyenneMaxisAvecCritères (Softmama).xlsm
    19.8 KB · Affichages: 37

job75

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Bonjour Softmama, heureux de te retrouver, hello Modeste,

Dans un cas comme celui-ci il ne faut pas hésiter à construire un sérieux tableau intermédiaire.

Sa hauteur est celle du tableau source.

Formule matricielle en H2 pour trouver les objets correspondant aux critères :

Code:
=SIERREUR(INDEX(Obj;PETITE.VALEUR(SI((GAUCHE(Obj;NBCAR(F$2))=F$2)*(GAUCHE(Couleur;NBCAR(F$3))=F$3);LIGNE(Obj));LIGNES(H$2:H2)));"")
Formule normale en I2 pour éliminer les doublons :

Code:
=SI(NB.SI(H$1:H1;H2);"";H2)
Formule matricielle en J2 pour le calcul du maximum :

Code:
=SI(I2="";"";MAX(SI((Obj=I2)*(GAUCHE(Couleur;NBCAR(F$3))=F$3);Nb)))
Formule normale en L2 pour le calcul de la moyenne :

Code:
=MOYENNE(DECALER(J1;;;LIGNES(Obj)))
Nota : j'ai fait commencer les plages nommées Obj Couleur Nb en ligne 1, c'est plus simple.

Fichier joint.

A+
 

Pièces jointes

  • FormuleMoyenneMaxisAvecCritères(1).xlsx
    13.7 KB · Affichages: 28
Dernière édition:

job75

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Re,

Il y a plus simple pour la formule de la colonne H.

Sélectionner toute la plage H2:H15 et entrer dans la barre de formule :

Code:
=REPT(Obj;(GAUCHE(Obj;NBCAR(F$2))=F$2)*(GAUCHE(Couleur;NBCAR(F$3))=F$3))
Valider matriciellement par Ctrl+Maj+Entrée.

Nota: j'ai remis le début des plages Obj Couleur Nb en ligne 2 et modifié la formule de la moyenne en L2 :

Code:
=MOYENNE(DECALER(J2;;;LIGNES(Obj)))
Fichier (2).

A+
 

Pièces jointes

  • FormuleMoyenneMaxisAvecCritères(2).xlsx
    13.5 KB · Affichages: 41

job75

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Bonsoir chère Monique,

Quel plaisir de te revoir, tu te fais rare :)

Je n'ai pas du tout l'intention de rivaliser avec ta solution, superbe comme d'habitude.

Donc je continue avec mes 3 colonnes intermédiaires.

Mais j'ai organisé le tableau en tableau Excel (Tableau1) dans lequel j'ai introduit les 3 colonnes intermédiaires, qui sont à masquer.

Fichier (3).

Edit : on notera qu'ainsi il n'y a plus de fonction DECALER (volatile) qui entraîinait une invite à la fermeture.

Bonne fin de soirée.
 

Pièces jointes

  • FormuleMoyenneMaxisAvecCritères(3).xlsx
    15.1 KB · Affichages: 43
Dernière édition:

Softmama

XLDnaute Accro
Re : Moyenne des Max avec critères

Bonjour à tous,

Un grand merci pour vos solutions que je vais maintenant m'atteler à décortiquer dans les détails afin de bien tout comprendre.
Je vais essayer d'adapter ceci à mes besoins originels, mais je pense que vous m'avez bien mis sur la voie. Je reviens vers vous pour vous donner le résultat de tout cela.
 

Softmama

XLDnaute Accro
Re : Moyenne des Max avec critères

Re bonjour à tous,

Après étude des 3 solutions proposées par Modeste, Job75 et Monique, j'obtiens à chaque fois le résultat voulu et je vous en remercie. Celle de Monique correspond je pense le mieux à mes besoins, même s'il y reste une étape intermédiaire, pour les raisons suivantes :

Mon fichier réel fait 15000 lignes * 18 colonnes et le problème que j'ai soulevé est répété une centaine de fois dans le fichier, ce à chaque fois que l'utilisateur modifie l'une des 5 listboxs de la feuille.

- La solution de Modeste par macro, parfaite pour l'exemple fourni, serait hélas interminable à exécuter sur mon fichier réel (un For each c sur 15000 lignes répétées 100 fois me paraît inenvisageable). Je ne l'ai donc pas développée.

- La solution de Job75 est également très intéressante, mais elle a l'inconvénient d'ajouter 3 colonnes * 15000 lignes = 45000 cellules calculées supplémentaires, ce qui je le crains risque de faire mouliner mon ordi à chacun des 100 recalculs dont j'ai besoin régulièrement.

- La solution proposée par Monique correspond à celle que j'avais commencé à mettre en oeuvre dans mon coin depuis hier, sauf que sa formule pour isoler la liste des objets qui doivent ressortir est largement plus simple que la mienne, ce qui je pense fera gagner du temps d'exécution. Du coup, je vais piloter par macro les 100 valeurs d'objets qui lancera par la méthode de Monique les calculs de la moyenne des max des objets concernés à chaque fois que l'utilisateur modifiera une listbox et je pense ainsi avoir un temps d'exécution raisonnable pour mes besoins.

En tous cas, un grand merci de nouveau à tous 3 pour vous être penché sur ce problème que je n'avais pas imaginé si complexe au départ, ainsi qu'à tous ceux qui se sont de leur côté intéressé à cette question.
 

job75

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Bonjour Softmama, Modeste, Monique,

Cette fonction VBA doit être extrêmement rapide car elle utilise des tableaux VBA :

Code:
Function MoyenneMax#(Obj, Couleur, Nb, crit1$, crit2$)
Dim d As Object, t$, i&
Obj = Obj: Couleur = Couleur: Nb = Nb 'matrices, plus rapides
Set d = CreateObject("Scripting.Dictionary")
t = crit1 & "*" & Chr(1) & crit2 & "*"
For i = 1 To UBound(Obj)
  If Obj(i, 1) & Chr(1) & Couleur(i, 1) Like t Then
    If Not d.exists(Obj(i, 1)) Then
      d(Obj(i, 1)) = Nb(i, 1)
    Else
      If Nb(i, 1) > d(Obj(i, 1)) Then d(Obj(i, 1)) = Nb(i, 1)
    End If
  End If
Next
MoyenneMax = Application.Average(d.items)
End Function
Elle est utilisée en cellule H2.

Bien noter que la casse est respectée.

Fichier joint.

A+
 

Pièces jointes

  • FormuleMoyenneMaxisAvecCritères - VBA(1).xlsm
    20.3 KB · Affichages: 46

job75

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Re,

J'ai testé sur Win 7 - Excel 2010 un tableau de dimensions 15009 x 3.

La formule en H2, avec la fonction VBA, se calcule en 0,05 ou 0,06 seconde.

Edit : par curiosité j'ai construit le tableau A1:F15009 sur le fichier (3) du post #6.

Le recalcul de toutes les formules (copie du tableau sur lui-même) prend 212 secondes :mad:

A+
 
Dernière édition:

job75

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Re,

S'il y a des valeurs textes dans la colonne des nombres on ne s'en apercevra pas et le résultat sera faux.

Une solution est de mettre des CDbl :

Code:
Function MoyenneMax#(Obj, Couleur, Nb, crit1$, crit2$)
Dim d As Object, t$, i&
Obj = Obj: Couleur = Couleur: Nb = Nb 'matrices, plus rapides
Set d = CreateObject("Scripting.Dictionary")
t = crit1 & "*" & Chr(1) & crit2 & "*"
For i = 1 To UBound(Obj)
  If Obj(i, 1) & Chr(1) & Couleur(i, 1) Like t Then
    If Not d.exists(Obj(i, 1)) Then
      d(Obj(i, 1)) = CDbl(Nb(i, 1))
    Else
      If CDbl(Nb(i, 1)) > d(Obj(i, 1)) Then d(Obj(i, 1)) = CDbl(Nb(i, 1))
    End If
  End If
Next
MoyenneMax = Application.Average(d.items)
End Function
Bonne nuit.
 

Softmama

XLDnaute Accro
Re : Moyenne des Max avec critères

Bonjour Job75,

Merci encore pour cette piste qui me semble très intéressante en effet. Je creuserai ceci et viendrai te faire savoir le résultat final. J'ai prévu de me consacrer à ce problème lundi, là j'ai d'autres priorités qui se sont greffé en cette fin de semaine. A bientôt donc :)
 

Softmama

XLDnaute Accro
Re : Moyenne des Max avec critères

Bonjour à tous,


Monique, j'ai finalement abandonné par formule, la macro qui pilotait les données intermédiaires l'ont fait trop ramer. C'est peut-être dû à mon code mal fagoté mais en tout cas, je n'ai pas réussi simplement à l'adapter à mon besoin réel.

Job75, je reviens vers toi comme promis. J'ai testé hier avec la méthode Scripting.Dictionary et suis parvenu en adaptant ta macro à mes besoins au résultat voulu... sauf que ce que je cherchais à obtenir n'était pas la moyenne des max seulement, mais également un ratio de la moyenne des objets (qui en fait sont des équipements sportifs : piscines, stades, gymnases...) sur la moyenne des max et que cette macro rendait un résultat erroné (je m'en suis rendu compte car j'avais parfois des ratios fréquentation/Fréquentation maxi supérieures à 100%).

J'ai beaucoup de critères su mon fichier réel : Je cherche à étudier les fréquentations des équipements sportifs d'une ville, en fonction du type d'usagers, leur identifiant (nom d'association, d'école...), la période de l'année que je sélectionne ou même sur un certain créneau horaire.
Les données de mon tableau sont chargées à l'activation de la feuille avec ces lignes-ci :

VB:
Eq = Feuil2.Range("Eq").Value
Typ = Feuil2.Range("Typ").Value
Usager = Feuil2.Range("Usager").Value
Mois = Feuil2.Range("Mois").Value
HD = Feuil2.Range("HD").Value
HF = Feuil2.Range("HF").Value
Jour = Feuil2.Range("Jour").Value
FréqH = Feuil2.Range("FréqH").Value

où les différentes plages de cellules nommées sont créées dynamiquement et correspondent aux colonnes de mon tableau de 10000 lignes. Voici ta macro adaptée que j'ai produite dans un premier temps :

VB:
Function MoyenneMax(CritJour As String, CritH As Double)
Dim CritEq As String, CritTyp As String, CritUsager As String, CritMoisDéb As String, CritMoisFin As String
Dim d As Object, t As String, i As Long, CritHF As Double, CritHD As Double

Application.Volatile

CritEq = Range("C_Eq") 'Equipement choisi (ou partie du nom)
CritTyp = Range("C_Typ") 'Type d'usager choisi
CritUsager = Range("C_Us") 'Nom de l'usager choisi
CritMoisDéb = Range("C_MD") 'Mois de départ de l'étude
CritMoisFin = Range("C_MF") 'Mois de fin 
CritHF = CritH + 59 / 60 / 24 'Heure de Fin
CritHD = CritH 'Heure de début

Set d = CreateObject("Scripting.Dictionary")

'Critère
t = "*" & CritEq & "*" & Chr(1) & _
    "*" & CritTyp & "*" & Chr(1) & _
    "*" & CritUsager & "*" & Chr(1) & _
    "*" & CritJour & "*"
    

For i = 1 To UBound(Eq)
  If Eq(i, 1) & Chr(1) & Typ(i, 1) & Chr(1) & Usager(i, 1) & Chr(1) & Jour(i, 1) Like t Then
    If Mois(i, 1) >= CritMoisDéb And Mois(i, 1) <= CritMoisFin And Application.Round(CDbl(HD(i, 1)), 6) <= Application.Round(CDbl(CritH), 6) And Application.Round(CDbl(HF(i, 1)), 6) >= Application.Round(CDbl(CritH), 6) Then
      If Not d.exists(Eq(i, 1)) Then
        d(Eq(i, 1)) = CDbl(FréqH(i, 1))
      Else
        If CDbl(FréqH(i, 1)) > d(Eq(i, 1)) Then d(Eq(i, 1)) = CDbl(FréqH(i, 1))
      End If
    End If
  End If
Next
If d.Count = 0 Then MoyenneMax = 0 Else MoyenneMax = Application.Average(d.items)
End Function

J'ai du mettre des .Round(..., 6) pour obtenir les bons résultats car les créneaux horaires traduits par CDbl donnait des erreurs d'interprétation (14:00 devenait 14:00:00,006 ce qui le sortait du créneau 13-14h)

Bref une fois ces problèmes réglés, je me suis rendu compte que le résultat renvoyé était donc erroné et j'ai décidé de passer par une variable tableau à 2 dimensions qui enregistrait, outre le nom de l'équipement et son maxi de fréquentation, la fréquentation horaire moyenne relevée et le nombre de créneaux rencontrés. Ce qui a donné cette nouvelle macro, dans la continuité de la précédente (Je l'utilise même à la place des 200 =SOMME.SI.ENS(...) qui jalonnait mon fichier en jouant sur le premier paramètre de la fonction pour obtenir la somme ou la moyenne des maxis par moyennes d'équipements selon mes besoins (ça devient confus, désolé). :

VB:
Function FréqTauxOcc(TypCalcul As Integer, CritJour As String, CritH)
'TypCalCul : 0 = Fréquentation horaire moyenne, 1 = Taux d'occupation
Dim CritEq As String, CritTyp As String, CritUsager As String, CritMoisDéb As String, CritMoisFin As String
Dim d(0 To 50, 0 To 3), t As String, i As Long, j As Integer, CritHF As Double, CritHD As Double
Dim sSom As Double, sNb As Integer, sMax As Double, x As Double, txOc As Double
'0 to 3 : Nom de l'Equipement, SomFréqH, NbFréqH, MaxFréqH
Application.Volatile

CritEq = Range("C_Eq")
CritTyp = Range("C_Typ")
CritUsager = Range("C_Us")
CritMoisDéb = Range("C_MD")
CritMoisFin = Range("C_MF")
CritHF = CritH + 59 / 60 / 24
CritHD = CritH


t = "*" & CritEq & "*" & Chr(1) & _
    "*" & CritTyp & "*" & Chr(1) & _
    "*" & CritUsager & "*" & Chr(1) & _
    "*" & CritJour & "*"
    
j = 0
For i = 1 To UBound(Eq)
  If Eq(i, 1) & Chr(1) & Typ(i, 1) & Chr(1) & Usager(i, 1) & Chr(1) & Jour(i, 1) Like t Then
    If Mois(i, 1) >= CritMoisDéb And Mois(i, 1) <= CritMoisFin And Application.Round(CDbl(HD(i, 1)), 6) <= Application.Round(CDbl(CritH), 6) And Application.Round(CDbl(HF(i, 1)), 6) >= Application.Round(CDbl(CritH), 6) - IIf(Application.Round(CDbl(CritH), 6) >= 22, 0.1, 0) Then
      TrouvedsTableau = False
      For k = LBound(d, 1) To UBound(d, 1)
         If d(k, 0) = Eq(i, 1) Then TrouvedsTableau = True: Exit For
      Next k
      If TrouvedsTableau Then
        d(k, 1) = d(k, 1) + CDbl(FréqH(i, 1))
        d(k, 2) = d(k, 2) + 1
        If CDbl(FréqH(i, 1)) > d(k, 3) Then d(k, 3) = CDbl(FréqH(i, 1))
      Else
        d(j, 0) = Eq(i, 1)
        d(j, 1) = CDbl(FréqH(i, 1))
        d(j, 2) = 1
        d(j, 3) = CDbl(FréqH(i, 1))
        j = j + 1
      End If
    End If
  End If
Next
If j = 0 Then
  txOc = -1
Else
   x = 0: y = 0
  For i = 0 To j - 1
   sSom = 0: sNb = 0
    sSom = d(i, 1) + sSom
    sNb = sNb + d(i, 2)
    sMax = sMax + d(i, 3)
    x = x + sSom / sNb
    y = y + 1
   ' Debug.Print x, y, x / y
  Next
  txOc = x / y
  If TypCalcul = 1 Then txOc = txOc / sMax * y 'Taux d'occupation du bâtiment
End If
FréqTauxOcc = txOc
End Function

Cette fonction convient tout à fait à mes besoins, puisque la feuille de calcul qui contient 250 grosses formules (matricielles + personnalisées) sont calculées en 1/2 seconde à peine et qu'elles ne nécessitent plus de formules intermédiaires. Donc tout est parfait pour moi. Encore merci pour m'avoir mis sur cette piste, j'avais trop le nez dans le guidon et pas pris assez de recul sur mon problème. Au final elles génèrent 2 graphiques en courbes de niveaux, l'une qui montre la fréquentation du / des équipements choisis heure par heure sur la semaine, l'autre leur taux d'occupation.
 

job75

XLDnaute Barbatruc
Re : Moyenne des Max avec critères

Bonjour Softmama,

Bravo d'avoir réussi car ton problème etait bien compliqué. Juste une remarque :

J'ai du mettre des .Round(..., 6) pour obtenir les bons résultats car les créneaux horaires traduits par CDbl donnait des erreurs d'interprétation (14:00 devenait 14:00:00,006 ce qui le sortait du créneau 13-14h)

c'est en effet ce qu'il faut toujours faire quand on manipule et compare des heures.

A+
 

Discussions similaires

Statistiques des forums

Discussions
312 361
Messages
2 087 627
Membres
103 608
dernier inscrit
rawane