Comment calculer les moyennes pondérées dans Google Sheets?


36

J'ai un Google Sheets où les produits sont répertoriés en tant que lignes et les attributs en tant que colonnes. L'attribut de chaque produit est évalué sur une échelle de 1 à 10. Ma dernière colonne est une moyenne de ces valeurs (c'est-à-dire =Average(B2:D2)). Cela fonctionne très bien si chaque attribut a le même poids.

+--------+-------+-------+-------+---------+
|        | Attr1 | Attr2 | Attr3 | Overall |
+--------+-------+-------+-------+---------+
| Prod 1 | 10    | 8     | 9     | 9       |
| Prod 2 | 2     | 10    | 7     | 6.33    |
| Prod 3 | 4     | 6     | 6     | 5.33    |
+--------+-------+-------+-------+---------+

Le problème est que je veux que chaque attribut ait un poids différent. Par exemple, Attr1 pourrait ne pas être important et ne devrait valoir que 50%, tandis que Attr3 est très important et devrait représenter 300%.

+--------+-------------+-------+--------------+---------+
|        | Attr1 (50%) | Attr2 | Attr3 (300%) | Overall |
+--------+-------------+-------+--------------+---------+
| Prod 1 | 10          | 8     | 9            | 8.89    |
| Prod 2 | 2           | 10    | 7            | 7.11    |
| Prod 3 | 4           | 6     | 6            | 5.78    |
+--------+-------------+-------+--------------+---------+

La valeur pour la première ligne serait:

(10*0.5 + 8*1 + 9*3) / (0.5+1+3) = 8.89

qui pourrait être calculé en utilisant:

(
  B2*(IFERROR(REGEXEXTRACT(B1, "\d+"), 100)/100) 
  + C2*(IFERROR(REGEXEXTRACT(C1, "\d+"), 100)/100)
  + D2*(IFERROR(REGEXEXTRACT(D1, "\d+"), 100)/100) 
) / (
  IFERROR(REGEXEXTRACT(B1, "\d+"), 100)/100
  + IFERROR(REGEXEXTRACT(C1, "\d+"), 100)/100
  + IFERROR(REGEXEXTRACT(D1, "\d+"), 100)/100
)

qui, comme vous pouvez le constater, peut devenir très difficile à gérer à mesure que de nouveaux attributs sont ajoutés. Idéalement, je recherche une solution ne nécessitant pas la création de cellules temporaires pour faciliter les calculs.

Existe-t-il une fonction intégrée ou une convention commune qui puisse m'aider à calculer ces moyennes pondérées?

Réponses:


8

Il n'y a pas de fonction intégrée pour calculer la moyenne pondérée, vous devez donc écrire une fonction personnalisée si vous souhaitez éviter d'utiliser trop de cellules temporaires. Alors, voici comment vous pouvez atteindre votre objectif.

Allez dans Outils > Scripts > Editeur de script ... , Copiez / collez le code ci-dessous et enregistrez-le:

function weightedAverage(v, w) {
  var sum_v = 0;
  var sum_w = 0;

  if (v[0].length != w[0].length) {
    return "#ERROR: Incorrect number of values and weights";  
  }

  for (var c = 0; c < v[0].length; ++c) {
    sum_v += v[0][c] * w[0][c]; 
    sum_w += w[0][c]; 
  }

  return sum_v/sum_w;
}​

Utilisez-le comme:

=weightedAverage(B3:D3,$B$2:$D$2) 

B3:D3sont vos valeurs et $B$2:$D$2vos poids. Ce n'est pas une preuve d'erreur (la seule vérification est de vous assurer que les deux tableaux ont la même longueur), mais cela fera l'affaire.

Dans l'exemple ci-dessus, je n'essaie pas d'extraire les poids du titre de l'attribut, mais je les lis à partir de la deuxième ligne ( B2:D2) pour rendre notre vie plus facile et plus claire. Le $ne change pas le résultat de la formule. Cela n'affecte que ce qui se passe lorsque vous copiez la formule dans une autre cellule. La partie de la référence de cellule qui suit le $ ne changera pas ( lien pour plus de détails). Ecrivez la formule une fois dans la cellule E3et copiez-la dans le reste des lignes pour la voir en action.


Que $signifient les signes?
Senseful

@Senseful J'ai mis à jour ma réponse, et vous pouvez en général utiliser Google, car dollar sign in excelc'est la même chose, car vous trouverez plus de documentation à ce sujet.
Lipis

1
Votre fonction ne fonctionne pas. Mais cela fonctionne pour moi: gist.github.com/totty90/b58f47dbc430a53d2e5b
Totty.js

1
Il y a une autre réponse mieux notée sur cette page qui fonctionne et utilise la fonction intégréesumproduct
Brad Parks

58

Si vos pondérations sont dans la ligne 2 de B à L et que les données que vous souhaitez moyenner sont dans les lignes 3 et supérieures, par exemple, vous pouvez utiliser sumproduct comme suit:

=sumproduct(B$2:L$2, C3:L3)/sum(B$2:L$2)

7
+1 cette réponse est simple, efficace et bien meilleure que celle acceptée.
Afr


2

Le code de Lipis ne fonctionnait pas pour moi, alors voici une mise à jour. Ce code:

  • fonctionne avec la version actuelle de Google Spreadsheets en adressant correctement les éléments du tableau

  • vérifie si les valeurs sont des nombres

  • a un commutateur pour considérer les valeurs zéro ou non

Code:

/**
  v - Values range
  w - Weights range
  z - count zero values?
*/

function weightedAverage(v, w, z) {
  var sum_v = 0;
  var sum_w = 0;

  if (v.length != w.length) {
    return "#ERROR: Incorrect number of values and weights";  
  }

  for (var c = 0; c < v.length; ++c) {
    if (!z && Number(v[c][0])!=0) {
      sum_v += Number(v[c][0]) * Number(w[c][0]); 
      sum_w += Number(w[c][0]); 
    }
  }

  return sum_v/sum_w;
}

0

Correction du code de Lipis pour qu'il fonctionne avec la version actuelle de Google Spreadsheets:

function weightedAverage(v, w) {
  var sum_v = 0;
  var sum_w = 0;

  if (v.length != w.length) {
    return "#ERROR: Incorrect number of values and weights";  
  }

  for (var c = 0; c < v.length; ++c) {
    sum_v += v[c] * w[c]; 
    sum_w += w[c] * 1; 
  }

  return sum_v/sum_w;
}​

-1; J'ai testé votre code dans les nouvelles feuilles de calcul Google et cela n'a pas fonctionné, cela a donné #NUM!. Le code que Lipis a créé fonctionne toujours. Vous ignorez uniquement le tableau 2D qui est renvoyé.
Jacob Jan Tuinstra

0

ARRAYFORMULA () peut calculer une moyenne pondérée dans Google Spreadsheets (et plus).

Stocker les poids séparément dans B2: D2 simplifie la lecture de la formule. Le calcul de la moyenne pondérée pour E3 ressemble alors à SUMPRODUCT () ci-dessus (copier / coller pour E4 et E5):

=ARRAYFORMULA(sum(B3:D3 * $B$2:$D$2)/sum($B$2:$D$2))

+--------+-------------+-------+-------------+---------+
|        | AttrA (50%) | AttrB | AttrC (300%)| Overall |
| Weight:|        50%  |  100% |        300% |         |
+--------+-------------+-------+-------------+---------+
| Prod 1 |       10    |  8    |       9     | 8.8889  |
| Prod 2 |        2    | 10    |       7     | 7.1111  |
| Prod 3 |        4    |  6    |       6     | 5.7778  |
+--------+-------------+-------+-------------+---------+

Utiliser RegExExtract () pour obtenir les poids à partir de $ B $ 1: $ D $ 1 est un simple changement dans ARRAYFORMULA (). Remplacez la plage simple par l'expression plus complexe " iferror(regexextract($B$1:$D$1,"\d+"),100)/100" et la formule pour E3 devient (copier / coller pour E4 & E5):

=ARRAYFORMULA(sum(B3:D3 * iferror(regexextract($B$1:$D$1,"\d+"),100)/100)/sum(iferror(regexextract($B$1:$D$1,"\d+"),100)/100))

NB: Cette expression rationnelle nécessite des noms d'attributs sans numéros; utilisez donc AttrA, AttrB & AttrC au lieu de Attr1, Attr2 & Attr3.


0

Ayant lu votre question attentivement,

Idéalement, je recherche une solution ne nécessitant pas la création de cellules temporaires pour faciliter les calculs.

Je suis venu avec cette solution, qui utilise pas de cellules temporaires.

Formule

weights = ARRAYFORMULA(IFERROR(VALUE(REGEXEXTRACT($B$1:$D$1,"\((\d+)")),100))

=SUMPRODUCT(B3:D3, weights) / SUM(weights)

copy / paste
=SUMPRODUCT(B2:D2, ARRAYFORMULA(IFERROR(VALUE(REGEXEXTRACT($B$1:$D$1,"\((\d+)")),100)))/SUM(ARRAYFORMULA(IFERROR(VALUE(REGEXEXTRACT($B$1:$D$1,"\((\d+)")),100)))

Capture d'écran

entrez la description de l'image ici

A expliqué

Le REGEXEXTRACTva extraire la valeur dans l'en-tête après le premier crochet droit et VALUEle convertira en un nombre. La IFERRORvolonté définira la valeur à 100si rien n'est trouvé et ARRAYFORMULApermettra de sélectionner une plage plutôt que des cellules individuelles.

Exemple

J'ai créé pour vous un exemple de fichier: Comment calculer des moyennes pondérées dans Google Spreadsheets?


0

Comme la réponse acceptée est d'utiliser Google Apps Script, j'ai également créé un petit extrait de code.

Code

function weightedAverage(v, w) {
  var weights = [], sumWeights = 0;
  for(var k = 0, kLen = w[0].length; k < kLen; k++) {
    var m = w[0][k].match(/\((\d+)/), value;
    if(!m) {
      value = 100;
    } else {
      value = Number(m[1]);
    }
    weights.push(value);
    sumWeights += value;
  }

  var output = [];
  for(var i = 0, iLen = v.length; i < iLen; i++) {
    var sumProduct = 0;
    for(var j = 0, jLen = v[0].length; j < jLen; j++) {
      sumProduct += v[i][j] * weights[j]; 
    }
    output.push(sumProduct / sumWeights);
  } 
  return output;
}

Capture d'écran

entrez la description de l'image ici

Remarque

Le script suivra la même logique que celle présentée dans ce post. Le principal avantage est qu'il calcule les valeurs globales en une fois.

Exemple

J'ai créé pour vous un exemple de fichier: Comment calculer des moyennes pondérées dans Google Spreadsheets?


0

Pour les moyennes pondérées simples , vous pouvez simplement ajouter la valeur de cellule plusieurs fois. Comme si vous voulez que A1 soit à 75% et que B1 soit à 25%, vous pouvez le mettre en jeu =AVERAGE (A1,A1,A1,B1). Donc, en particulier pour le vôtre, ce serait =AVERAGE (B2,C2,C2,D1,D2,D2,D2,D2,D2,D2)B2 qui représenterait la moitié de C2 (50%) et D2 3 x C2 (300%).

Des choses plus compliquées sont au-dessus de ma note de salaire. :)


0

En fait, les deux versions Moyenne.Poids et Somme produisent le même résultat:

AVERAGE.WEIGHTED("Values","Weight")

SUMPRODUCT("Numbers","Weight")/sum("Weight")

Donc, j'utilise plutôt le premier, car il est beaucoup plus simple à gérer, mais je ne sais pas comment ajouter d'autres poids à cette formule.

Ceci est l'info-bulle, mais vous ne savez pas comment ajouter uniquement des poids et non des valeurs supplémentaires

AVERAGE.WEIGHTED(values, weights, [additional_values, ...], [additional_weights, ...])

C'est un peu vague. Essayez-vous de poser une nouvelle question ou est-ce une réponse?
jonsca

-2

Il y a moyen assez simple d'utiliser seulement des fonctions données.

=(sumproduct(E5:E9;G5:G9)/sum(E5:E9))   

où E contenu est le nombre de points et G l'importance de ces points.


2
Cette réponse a déjà été donnée: webapps.stackexchange.com/a/29919/29140
Jacob Jan Tuinstra

@JacobJanTuinstra Pourquoi cette réponse s'affiche-t-elle en premier si elle est jugée bien inférieure à celle que vous référencez? webapps stackexchange fonctionne de façon
mystérieuse
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.