Help us understand the problem. What is going on with this article?

PageSpeed Insightsの点数はどのように計算されているか。100点をとるための条件

PageSpeed Insightsの採点ロジックについて詳しく調べてみたところ、意外なことがわかりました。

2020/6/3 追記

本家レポートよりPageSpeed Insightsのスコア改善が捗る裏レポートツールを公開しました。合わせてご参考ください。
https://simulate.site/cheatspeed-insights/

2020/3/19 追記

Lighthouse 6へのバージョンアップでこのページにかかれている内容が一部変更される可能性があります。
こちらも併せてご参考ください。

PageSpeed Insightsのスコア大変動か? Lighthouse 6 で変わる採点ルールを先取りチェック! - アイデアマンズブログ

点数に反映される監査項目は5つだけ

PageSpeed Insightsを実行するといろいろな指摘事項が出てきます。なので指摘が多いと点数が下がる減点方式と思われがちです(私もそう思っていました)。

実は、PageSpeed Insightsの点数はたった5つの監査スコアの加重平均で計算されています

  • Interactive インタラクティブになるまでの時間(重み 5)
  • Speed Index 速度インデックス (重み 4)
  • First Contentful Paint コンテンツの初回ペイント (重み 3)
  • First CPU Idle CPUの初回アイドル (重み 2)
  • First Meaningful Paint 意味のあるコンテンツの初回イベント (重み 1)

指摘項目はあくまで上記の指標を改善させるためのアドバイスです。指摘をクリアしても直接点数が上がるわけではありません

逆にどんな手を使おうと上記の指標を改善すればPageSpeed Insightsの点数が上がります。技術的に頑張るよりコンテンツを見直す方が効率よく点数を上げられる場合が多いと思います。

PageSpeed Insightsで満点をとる方法

もうひとつ、100点を取るための具体的な条件を特定しました。

以下のすべて条件を満たせば、PageSpeed Insightsの点数が必ず100点になります(Lighthouse 4.3.0時点)。

  • Interactive インタラクティブになるまでの時間 1900ms以下
  • Speed Index 速度インデックス 1950ms以下
  • First Contentful Paint コンテンツの初回ペイント 1350ms以下
  • First CPU Idle CPUの初回アイドル 1950ms以下
  • First Meaningful Paint 意味のあるコンテンツの初回イベント 1350ms以下

3Gネットワーク相当の通信環境での条件なので容易ではありません。

採点ロジック

PageSpeed Insightsは内部でLighthouseを利用しています。

LighthouseはGoogle Chromeチームが主導するオープンソースのWebページ監査ツールです。Lighthouseのパフォーマンスカテゴリスコア = PageSpeed Insightsの点数です。

Lighthouseのスコア計算を行っている部分を追ってみましょう。

カテゴリスコアは監査スコアの加重平均

パフォーマンススコア(PageSpeed Insightsの点数)のようなカテゴリスコアの計算を行っているのがscoring.jsです。

L75付近で監査項目のスコアscoreを、重みweightを加味して加重平均しています。

      const scores = auditRefs.map(auditRef => ({
        score: resultsByAuditId[auditRef.id].score,
        weight: auditRef.weight,
      }));
      const score = ReportScoring.arithmeticMean(scores);

監査項目は5つ以外 weight=0

加重平均なので重みweightが0だと、その監査項目のスコアがどんなに高くても全体の点数にはまったく反映されません。

PageSpeed InsightsをAPI経由で実行するとJSONデータが得られます。上記の計算に使われているlighthouseResult.categories.performance.auditRefsを見ると、weightが0以外なのは5項目だけです。

        "auditRefs": [
          {
            "id": "first-contentful-paint",
            "weight": 3,
            "group": "metrics"
          },
          {
            "id": "first-meaningful-paint",
            "weight": 1,
            "group": "metrics"
          },
          {
            "id": "speed-index",
            "weight": 4,
            "group": "metrics"
          },
          {
            "id": "interactive",
            "weight": 5,
            "group": "metrics"
          },
          {
            "id": "first-cpu-idle",
            "weight": 2,
            "group": "metrics"
          },
          {
            "id": "estimated-input-latency",
            "weight": 0,
            "group": "metrics"
          },
// ...略(以下のweightはすべて0)...
        ]

つまり、first-contentful-paintfirst-meaningful-paintspeed-indexinteractivefirst-cpu-idle以外の監査スコアはいくら改善してもそれ自体では全体の点数は上がらないということです。

監査項目ごとの点数はどう計算されているか

interactiveなどの監査項目はいずれもタイミングに関する指標で、単位はミリ秒(ms)です(SpeedIndexは諸説ありますが、ここではms単位として扱われています)。

例えば重みが最も大きいinteractiveinteractive.jsにおいてAudit.computeLogNormalScoreメソッドでスコアリングされています。

    return {
      score: Audit.computeLogNormalScore(
        timeInMs,
        context.options.scorePODR,
        context.options.scoreMedian
      ),
      rawValue: timeInMs,
      displayValue: str_(i18n.UIStrings.seconds, {timeInMs}),
      extendedInfo: {
        value: extendedInfo,
      },
    };

Audit.computeLogNormalScoreを追っていくと、audit.jsや、statistics.jsで対数正規分布上のパーセンタイルでスコア計算をしているようです。

2019/4/24追記 難しくて執筆当時は端折ってしまいましたが、あとで調べたところ対数正規分布の分布関数が実装されていました。パフォーマンス指標は対数正規分布になるとみなし、累積分布関数である値が上位何%に位置するか(要は100人中の順位)求めます。1に対する補数がスコアになるという計算です。

逆算して満点を取る条件を見つけようとしたのですが断念…次のプログラムで50ms単位の閾値を探しました。それが冒頭の100点を取る条件です。

// yarn add lighthouse tsv
const Interactive = require('lighthouse/lighthouse-core/audits/metrics/interactive'),
  SpeedIndex = require('lighthouse/lighthouse-core/audits/metrics/speed-index'),
  FirstContentfulPaint = require('lighthouse/lighthouse-core/audits/metrics/first-contentful-paint'),
  FirstCPUIdle = require('lighthouse/lighthouse-core/audits/metrics/first-cpu-idle'),
  FirstMeaningfulPaint = require('lighthouse/lighthouse-core/audits/metrics/first-meaningful-paint'),
  Audit = require('lighthouse/lighthouse-core/audits/audit'),
  Tsv = require('tsv')

const classes = [Interactive, SpeedIndex, FirstContentfulPaint, FirstCPUIdle, FirstMeaningfulPaint]

const rows = []
for (let ms = 0; ms < 30000; ms += 50) {
  const row = { ms }
  for (let cls of classes) {
    const opts = cls.defaultOptions
    row[cls.name] = Audit.computeLogNormalScore(
      ms,
      opts.scorePODR,
      opts.scoreMedian,
    )
  }
  rows.push(row)
}

process.stdout.write(Tsv.stringify(rows))

300サイトのデータで検算

以前、通販上位300サイトについてPageSpeed Insightsを実行したデータがあります。

このデータで検算したところ、5項目のスコアの加重平均 = 全体の点数で完全に一致しました。ここまでの説明で採点ロジックはほぼ間違いないと確認しました。

以上です。参考になれば幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした