Last active
November 17, 2024 16:03
-
-
Save adamsilverstein/5caf45f73a39e3f51fa1d0a8082c6f1b to your computer and use it in GitHub Desktop.
Performant Translations Colab
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/adamsilverstein/5caf45f73a39e3f51fa1d0a8082c6f1b/performant-translations-colab.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "KcAZ2RHCg_Ze" | |
}, | |
"source": [ | |
"## Measure the impact of performant translations\n", | |
"\n", | |
"This colab will measure two distinct impacts\n", | |
"\n", | |
"* Core feature: impact on X for sites that are Y, before and after they enabled the feature\n", | |
"* Plugin: impact on sites that enabled the Performant Translations plugin\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Setup" | |
], | |
"metadata": { | |
"id": "4G2WkwMPzxbT" | |
} | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "qTmLBxDxBAZL" | |
}, | |
"source": [ | |
"### Provide your credentials to the runtime" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": { | |
"id": "SeTJb51SKs_W", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "8def6cfd-36f9-461b-e8df-9ce282fda22d" | |
}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Authenticated\n" | |
] | |
} | |
], | |
"source": [ | |
"from google.colab import auth\n", | |
"auth.authenticate_user()\n", | |
"print('Authenticated')\n", | |
"project_id = 'wpp-research'" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "goQQ96EDKs_7" | |
}, | |
"source": [ | |
"### Declare the Cloud project ID which will be used throughout this notebook\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from google.cloud.bigquery import magics\n", | |
"# Update with your own Google Cloud Platform project name\n", | |
"magics.context.project = 'wpp-research'" | |
], | |
"metadata": { | |
"id": "YdTgQYtSoOoE" | |
}, | |
"execution_count": 2, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"### Add a helper to get the latest dataset" | |
], | |
"metadata": { | |
"id": "yV85Ec6A9FED" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from datetime import datetime, timedelta\n", | |
"\n", | |
"def get_first_of_previous_month():\n", | |
" today = datetime.now()\n", | |
" first_day_previous_month = datetime(today.year, today.month - 1, 1) if today.month > 1 else datetime(today.year - 1, 12, 1)\n", | |
" return first_day_previous_month.strftime('%Y_%m_%d')\n", | |
"\n", | |
"dataset = get_first_of_previous_month() # eg. \"2023_06_01\" - datasets are updated monthly, indicate the latest" | |
], | |
"metadata": { | |
"id": "stNLljYnR355" | |
}, | |
"execution_count": 3, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "UMKGkkZEPVRu" | |
}, | |
"source": [ | |
"### Optional: Enable data table display\n", | |
"\n", | |
"Colab includes the ``google.colab.data_table`` package that can be used to display large pandas dataframes as an interactive data table.\n", | |
"It can be enabled with:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"id": "LMNA-vBHPyHz" | |
}, | |
"outputs": [], | |
"source": [ | |
"%load_ext google.colab.data_table" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from google.colab import data_table\n", | |
"data_table.enable_dataframe_formatter()" | |
], | |
"metadata": { | |
"id": "JlBfb2k3JpRS" | |
}, | |
"execution_count": 5, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# Queries" | |
], | |
"metadata": { | |
"id": "2FfbQTTPMspu" | |
} | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"### TTFB by localization status\n", | |
"From wpp-research::sql/2024/01/ttfb-localized-sites.sql" | |
], | |
"metadata": { | |
"id": "ouqXcVW2vh7N" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from google.cloud import bigquery\n", | |
"\n", | |
"client = bigquery.Client(project=project_id)\n", | |
"\n", | |
"query = f\"\"\"\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_GOOD(good FLOAT64,\n", | |
" needs_improvement FLOAT64,\n", | |
" poor FLOAT64)\n", | |
" RETURNS BOOL AS ( SAFE_DIVIDE(good, good + needs_improvement + poor) >= 0.75 );\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_NON_ZERO(good FLOAT64,\n", | |
" needs_improvement FLOAT64,\n", | |
" poor FLOAT64)\n", | |
" RETURNS BOOL AS ( good + needs_improvement + poor > 0 );\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_LOCALIZED(lang STRING)\n", | |
" RETURNS BOOL AS ( lang IS NOT NULL\n", | |
" AND lang != \"en\"\n", | |
" AND lang != \"en-us\" );\n", | |
"WITH\n", | |
" pages AS (\n", | |
" SELECT\n", | |
" client,\n", | |
" IS_LOCALIZED(REPLACE(TRIM(LOWER(JSON_VALUE(JSON_VALUE(payload, '$._almanac'), '$.html_node.lang'))), '_', '-' )) AS is_localized,\n", | |
" page AS url,\n", | |
" FROM\n", | |
" `httparchive.all.pages`,\n", | |
" UNNEST(technologies) AS t\n", | |
" WHERE\n", | |
" date = '2023-12-01'\n", | |
" AND is_root_page\n", | |
" AND t.technology = 'WordPress' ),\n", | |
" devices AS (\n", | |
" SELECT\n", | |
" CONCAT(origin, '/') AS url,\n", | |
" IF\n", | |
" (device = 'desktop', 'desktop', 'mobile') AS client,\n", | |
" IS_NON_ZERO(fast_ttfb,\n", | |
" avg_ttfb,\n", | |
" slow_ttfb) AS any_ttfb,\n", | |
" IS_GOOD(fast_ttfb,\n", | |
" avg_ttfb,\n", | |
" slow_ttfb) AS good_ttfb\n", | |
" FROM\n", | |
" `chrome-ux-report.materialized.device_summary`\n", | |
" WHERE\n", | |
" date = CAST(\"2023-12-01\" AS DATE)\n", | |
" AND device IN ('desktop',\n", | |
" 'tablet',\n", | |
" 'phone') )\n", | |
"SELECT\n", | |
" client,\n", | |
" is_localized,\n", | |
" SAFE_DIVIDE(COUNTIF(good_ttfb), COUNTIF(any_ttfb)) AS ttfb_passing_rate\n", | |
"FROM\n", | |
" devices\n", | |
" JOIN\n", | |
" pages\n", | |
" USING\n", | |
" (client,\n", | |
" url)\n", | |
"GROUP BY\n", | |
" is_localized,\n", | |
" client\n", | |
"ORDER BY\n", | |
" is_localized ASC,\n", | |
" client ASC\n", | |
"\"\"\"\n", | |
"\n", | |
"localize_or_not = client.query(query).to_dataframe()\n" | |
], | |
"metadata": { | |
"id": "XYbol66evJE1" | |
}, | |
"execution_count": 6, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"localize_or_not.head(1000)" | |
], | |
"metadata": { | |
"id": "LPXobb8QvkSG", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 208 | |
}, | |
"outputId": "ac72865f-da3d-4a99-cf75-473d0bfe8340" | |
}, | |
"execution_count": 7, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" client is_localized ttfb_passing_rate\n", | |
"0 desktop False 0.307445\n", | |
"1 mobile False 0.196011\n", | |
"2 desktop True 0.331216\n", | |
"3 mobile True 0.254033" | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-b7a065f7-3b3b-4317-9ea4-e33c4f36e5e8\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>ttfb_passing_rate</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.307445</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.196011</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.331216</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.254033</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-b7a065f7-3b3b-4317-9ea4-e33c4f36e5e8')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-b7a065f7-3b3b-4317-9ea4-e33c4f36e5e8 button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-b7a065f7-3b3b-4317-9ea4-e33c4f36e5e8');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-b86b1875-2571-4b83-8a52-eef747d8cfdd\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-b86b1875-2571-4b83-8a52-eef747d8cfdd')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-b86b1875-2571-4b83-8a52-eef747d8cfdd button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "localize_or_not", | |
"summary": "{\n \"name\": \"localize_or_not\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_passing_rate\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.060166357541579896,\n \"min\": 0.1960105308950741,\n \"max\": 0.3312159014712447,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.1960105308950741,\n 0.2540327301518636\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"desktop\",\nfalse,\n{\n 'v': 0.30744503527151634,\n 'f': \"0.30744503527151634\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"mobile\",\nfalse,\n{\n 'v': 0.1960105308950741,\n 'f': \"0.1960105308950741\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"desktop\",\ntrue,\n{\n 'v': 0.3312159014712447,\n 'f': \"0.3312159014712447\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"mobile\",\ntrue,\n{\n 'v': 0.2540327301518636,\n 'f': \"0.2540327301518636\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"ttfb_passing_rate\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-63573e67-a73c-47f4-bed5-b5cbb8f8d072\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-63573e67-a73c-47f4-bed5-b5cbb8f8d072')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-63573e67-a73c-47f4-bed5-b5cbb8f8d072 button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 7 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [], | |
"metadata": { | |
"id": "h59eYHfTwRWH" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"### TTFB passing rate 10/1/24" | |
], | |
"metadata": { | |
"id": "HBejguopxinI" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from google.cloud import bigquery\n", | |
"\n", | |
"client = bigquery.Client(project=project_id)\n", | |
"\n", | |
"query = f\"\"\"\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_GOOD(good FLOAT64,\n", | |
" needs_improvement FLOAT64,\n", | |
" poor FLOAT64)\n", | |
" RETURNS BOOL AS ( SAFE_DIVIDE(good, good + needs_improvement + poor) >= 0.75 );\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_NON_ZERO(good FLOAT64,\n", | |
" needs_improvement FLOAT64,\n", | |
" poor FLOAT64)\n", | |
" RETURNS BOOL AS ( good + needs_improvement + poor > 0 );\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_LOCALIZED(lang STRING)\n", | |
" RETURNS BOOL AS ( lang IS NOT NULL\n", | |
" AND lang != \"en\"\n", | |
" AND lang != \"en-us\" );\n", | |
"WITH\n", | |
" pages AS (\n", | |
" SELECT\n", | |
" client,\n", | |
" IS_LOCALIZED(REPLACE(TRIM(LOWER(JSON_VALUE(JSON_VALUE(payload, '$._almanac'), '$.html_node.lang'))), '_', '-' )) AS is_localized,\n", | |
" page AS url,\n", | |
" FROM\n", | |
" `httparchive.all.pages`,\n", | |
" UNNEST(technologies) AS t\n", | |
" WHERE\n", | |
" date = '2024-10-01'\n", | |
" AND is_root_page\n", | |
" AND t.technology = 'WordPress' ),\n", | |
" devices AS (\n", | |
" SELECT\n", | |
" CONCAT(origin, '/') AS url,\n", | |
" IF\n", | |
" (device = 'desktop', 'desktop', 'mobile') AS client,\n", | |
" IS_NON_ZERO(fast_ttfb,\n", | |
" avg_ttfb,\n", | |
" slow_ttfb) AS any_ttfb,\n", | |
" IS_GOOD(fast_ttfb,\n", | |
" avg_ttfb,\n", | |
" slow_ttfb) AS good_ttfb\n", | |
" FROM\n", | |
" `chrome-ux-report.materialized.device_summary`\n", | |
" WHERE\n", | |
" date = CAST(\"2024-10-01\" AS DATE)\n", | |
" AND device IN ('desktop',\n", | |
" 'tablet',\n", | |
" 'phone') )\n", | |
"SELECT\n", | |
" client,\n", | |
" is_localized,\n", | |
" SAFE_DIVIDE(COUNTIF(good_ttfb), COUNTIF(any_ttfb)) AS ttfb_passing_rate\n", | |
"FROM\n", | |
" devices\n", | |
" JOIN\n", | |
" pages\n", | |
" USING\n", | |
" (client,\n", | |
" url)\n", | |
"GROUP BY\n", | |
" is_localized,\n", | |
" client\n", | |
"ORDER BY\n", | |
" is_localized ASC,\n", | |
" client ASC\n", | |
"\"\"\"\n", | |
"\n", | |
"localize_or_not_24 = client.query(query).to_dataframe()\n" | |
], | |
"metadata": { | |
"id": "_sVCe4dsxg3X" | |
}, | |
"execution_count": 8, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"localize_or_not_24.head(1000)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 208 | |
}, | |
"id": "ScLf4yeNxt7M", | |
"outputId": "5de5095e-4dfc-4ca8-cdbf-229e2ffb6d4c" | |
}, | |
"execution_count": 9, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" client is_localized ttfb_passing_rate\n", | |
"0 desktop False 0.316738\n", | |
"1 mobile False 0.221321\n", | |
"2 desktop True 0.336921\n", | |
"3 mobile True 0.270966" | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-b33f8c02-f83d-4deb-b851-8235f565486c\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>ttfb_passing_rate</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.316738</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.221321</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.336921</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.270966</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-b33f8c02-f83d-4deb-b851-8235f565486c')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-b33f8c02-f83d-4deb-b851-8235f565486c button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-b33f8c02-f83d-4deb-b851-8235f565486c');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-14419aa8-36b0-457e-b0d0-30d0bc7c044c\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-14419aa8-36b0-457e-b0d0-30d0bc7c044c')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-14419aa8-36b0-457e-b0d0-30d0bc7c044c button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "localize_or_not_24", | |
"summary": "{\n \"name\": \"localize_or_not_24\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_passing_rate\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.05146614745586329,\n \"min\": 0.22132055966815736,\n \"max\": 0.3369209730338933,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.22132055966815736,\n 0.270965663613118\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"desktop\",\nfalse,\n{\n 'v': 0.31673812458898926,\n 'f': \"0.31673812458898926\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"mobile\",\nfalse,\n{\n 'v': 0.22132055966815736,\n 'f': \"0.22132055966815736\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"desktop\",\ntrue,\n{\n 'v': 0.3369209730338933,\n 'f': \"0.3369209730338933\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"mobile\",\ntrue,\n{\n 'v': 0.270965663613118,\n 'f': \"0.270965663613118\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"ttfb_passing_rate\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-5c421312-a442-46e5-9779-6b0c91a42d52\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-5c421312-a442-46e5-9779-6b0c91a42d52')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-5c421312-a442-46e5-9779-6b0c91a42d52 button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 9 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import pandas as pd\n", | |
"\n", | |
"# Compare absolute change between localize_or_not and localize_or_not_24\n", | |
"merged_df = pd.merge(localize_or_not, localize_or_not_24, on=['client', 'is_localized'], suffixes=('_2023', '_2024'))\n", | |
"merged_df['ttfb_passing_rate_absolute_change'] = merged_df['ttfb_passing_rate_2024'] - merged_df['ttfb_passing_rate_2023']\n", | |
"merged_df.head(1000)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 208 | |
}, | |
"id": "SKyf9JDCxwWA", | |
"outputId": "97ce42db-2568-403a-a19b-e10d06a4edd3" | |
}, | |
"execution_count": 11, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" client is_localized ttfb_passing_rate_2023 ttfb_passing_rate_2024 \\\n", | |
"0 desktop False 0.307445 0.316738 \n", | |
"1 mobile False 0.196011 0.221321 \n", | |
"2 desktop True 0.331216 0.336921 \n", | |
"3 mobile True 0.254033 0.270966 \n", | |
"\n", | |
" ttfb_passing_rate_absolute_change \n", | |
"0 0.009293 \n", | |
"1 0.025310 \n", | |
"2 0.005705 \n", | |
"3 0.016933 " | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-2e7c07c0-ad9c-4108-879a-bfbf78dbf21d\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>ttfb_passing_rate_2023</th>\n", | |
" <th>ttfb_passing_rate_2024</th>\n", | |
" <th>ttfb_passing_rate_absolute_change</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.307445</td>\n", | |
" <td>0.316738</td>\n", | |
" <td>0.009293</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.196011</td>\n", | |
" <td>0.221321</td>\n", | |
" <td>0.025310</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.331216</td>\n", | |
" <td>0.336921</td>\n", | |
" <td>0.005705</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.254033</td>\n", | |
" <td>0.270966</td>\n", | |
" <td>0.016933</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-2e7c07c0-ad9c-4108-879a-bfbf78dbf21d')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-2e7c07c0-ad9c-4108-879a-bfbf78dbf21d button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-2e7c07c0-ad9c-4108-879a-bfbf78dbf21d');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-7f8f5b5a-8559-4c73-ad82-c47a6ce6c008\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-7f8f5b5a-8559-4c73-ad82-c47a6ce6c008')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-7f8f5b5a-8559-4c73-ad82-c47a6ce6c008 button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "merged_df", | |
"summary": "{\n \"name\": \"merged_df\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_passing_rate_2023\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.060166357541579896,\n \"min\": 0.1960105308950741,\n \"max\": 0.3312159014712447,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.1960105308950741,\n 0.2540327301518636\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_passing_rate_2024\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.05146614745586329,\n \"min\": 0.22132055966815736,\n \"max\": 0.3369209730338933,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.22132055966815736,\n 0.270965663613118\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_passing_rate_absolute_change\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.008700471229457914,\n \"min\": 0.0057050715626486,\n \"max\": 0.025310028773083276,\n \"num_unique_values\": 4,\n \"samples\": [\n 0.025310028773083276,\n 0.016932933461254407\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"desktop\",\nfalse,\n{\n 'v': 0.30744503527151634,\n 'f': \"0.30744503527151634\",\n },\n{\n 'v': 0.31673812458898926,\n 'f': \"0.31673812458898926\",\n },\n{\n 'v': 0.009293089317472913,\n 'f': \"0.009293089317472913\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"mobile\",\nfalse,\n{\n 'v': 0.1960105308950741,\n 'f': \"0.1960105308950741\",\n },\n{\n 'v': 0.22132055966815736,\n 'f': \"0.22132055966815736\",\n },\n{\n 'v': 0.025310028773083276,\n 'f': \"0.025310028773083276\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"desktop\",\ntrue,\n{\n 'v': 0.3312159014712447,\n 'f': \"0.3312159014712447\",\n },\n{\n 'v': 0.3369209730338933,\n 'f': \"0.3369209730338933\",\n },\n{\n 'v': 0.0057050715626486,\n 'f': \"0.0057050715626486\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"mobile\",\ntrue,\n{\n 'v': 0.2540327301518636,\n 'f': \"0.2540327301518636\",\n },\n{\n 'v': 0.270965663613118,\n 'f': \"0.270965663613118\",\n },\n{\n 'v': 0.016932933461254407,\n 'f': \"0.016932933461254407\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"ttfb_passing_rate_2023\"], [\"number\", \"ttfb_passing_rate_2024\"], [\"number\", \"ttfb_passing_rate_absolute_change\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-a0a9f9e5-ff93-45bb-8cbb-a8ceb5846f04\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-a0a9f9e5-ff93-45bb-8cbb-a8ceb5846f04')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-a0a9f9e5-ff93-45bb-8cbb-a8ceb5846f04 button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 11 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## TTFB score changes" | |
], | |
"metadata": { | |
"id": "UwijSnIfyoLw" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from google.cloud import bigquery\n", | |
"\n", | |
"client = bigquery.Client(project=project_id)\n", | |
"\n", | |
"query = f\"\"\"\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_LOCALIZED(lang STRING)\n", | |
" RETURNS BOOL AS ( lang IS NOT NULL\n", | |
" AND lang != \"en\"\n", | |
" AND lang != \"en-us\" );\n", | |
"WITH\n", | |
" pages AS (\n", | |
" SELECT\n", | |
" client,\n", | |
" IS_LOCALIZED(REPLACE(TRIM(LOWER(JSON_VALUE(JSON_VALUE(payload, '$._almanac'), '$.html_node.lang'))), '_', '-' )) AS is_localized,\n", | |
" page AS url,\n", | |
" FROM\n", | |
" `httparchive.all.pages`,\n", | |
" UNNEST(technologies) AS t\n", | |
" WHERE\n", | |
" date = '2023-11-01'\n", | |
" AND is_root_page\n", | |
" AND t.technology = 'WordPress' ),\n", | |
" devices AS (\n", | |
" SELECT\n", | |
" CONCAT(origin, '/') AS url,\n", | |
" IF\n", | |
" (device = 'desktop', 'desktop', 'mobile') AS client,\n", | |
" p75_ttfb AS ttfb\n", | |
" FROM\n", | |
" `chrome-ux-report.materialized.device_summary`\n", | |
" WHERE\n", | |
" date = CAST(\"2023-11-01\" AS DATE)\n", | |
" AND device IN ('desktop',\n", | |
" 'tablet',\n", | |
" 'phone') )\n", | |
"SELECT\n", | |
" client,\n", | |
" is_localized,\n", | |
" AVG(ttfb) AS avg_ttfb\n", | |
"FROM\n", | |
" devices\n", | |
" JOIN\n", | |
" pages\n", | |
" USING\n", | |
" (client,\n", | |
" url)\n", | |
"GROUP BY\n", | |
" is_localized,\n", | |
" client\n", | |
"ORDER BY\n", | |
" is_localized ASC,\n", | |
" client ASC\n", | |
"\"\"\"\n", | |
"\n", | |
"localize_or_not_ttfb_2023 = client.query(query).to_dataframe()\n" | |
], | |
"metadata": { | |
"id": "SPRQqBEzyr0H" | |
}, | |
"execution_count": 17, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"localize_or_not_ttfb_2023.head(1000)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 208 | |
}, | |
"id": "NyM1v1Qm1SdV", | |
"outputId": "b890bf70-8ad4-4ef2-f4db-ed087bfee06e" | |
}, | |
"execution_count": 18, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" client is_localized avg_ttfb\n", | |
"0 desktop False 1343.236099\n", | |
"1 mobile False 1639.110170\n", | |
"2 desktop True 1376.459262\n", | |
"3 mobile True 1577.732006" | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-093afb80-a97c-42bc-aec0-5776aaff88a6\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>avg_ttfb</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>1343.236099</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>1639.110170</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>1376.459262</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>1577.732006</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-093afb80-a97c-42bc-aec0-5776aaff88a6')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-093afb80-a97c-42bc-aec0-5776aaff88a6 button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-093afb80-a97c-42bc-aec0-5776aaff88a6');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-f31937a6-ef61-4cb8-bdfc-1332a46400c9\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-f31937a6-ef61-4cb8-bdfc-1332a46400c9')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-f31937a6-ef61-4cb8-bdfc-1332a46400c9 button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "localize_or_not_ttfb_2023", | |
"summary": "{\n \"name\": \"localize_or_not_ttfb_2023\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"avg_ttfb\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 146.31503388460007,\n \"min\": 1343.2360994654653,\n \"max\": 1639.110169663145,\n \"num_unique_values\": 4,\n \"samples\": [\n 1639.110169663145,\n 1577.7320062324136\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"desktop\",\nfalse,\n{\n 'v': 1343.2360994654653,\n 'f': \"1343.2360994654653\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"mobile\",\nfalse,\n{\n 'v': 1639.110169663145,\n 'f': \"1639.110169663145\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"desktop\",\ntrue,\n{\n 'v': 1376.4592624179481,\n 'f': \"1376.4592624179481\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"mobile\",\ntrue,\n{\n 'v': 1577.7320062324136,\n 'f': \"1577.7320062324136\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"avg_ttfb\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-3fe086b8-d963-429a-9514-2f5507e5902b\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-3fe086b8-d963-429a-9514-2f5507e5902b')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-3fe086b8-d963-429a-9514-2f5507e5902b button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 18 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from google.cloud import bigquery\n", | |
"\n", | |
"client = bigquery.Client(project=project_id)\n", | |
"\n", | |
"query = f\"\"\"\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_LOCALIZED(lang STRING)\n", | |
" RETURNS BOOL AS ( lang IS NOT NULL\n", | |
" AND lang != \"en\"\n", | |
" AND lang != \"en-us\" );\n", | |
"WITH\n", | |
" pages AS (\n", | |
" SELECT\n", | |
" client,\n", | |
" IS_LOCALIZED(REPLACE(TRIM(LOWER(JSON_VALUE(JSON_VALUE(payload, '$._almanac'), '$.html_node.lang'))), '_', '-' )) AS is_localized,\n", | |
" page AS url,\n", | |
" FROM\n", | |
" `httparchive.all.pages`,\n", | |
" UNNEST(technologies) AS t\n", | |
" WHERE\n", | |
" date = '2024-10-01'\n", | |
" AND is_root_page\n", | |
" AND t.technology = 'WordPress' ),\n", | |
" devices AS (\n", | |
" SELECT\n", | |
" CONCAT(origin, '/') AS url,\n", | |
" IF\n", | |
" (device = 'desktop', 'desktop', 'mobile') AS client,\n", | |
" p75_ttfb AS ttfb\n", | |
" FROM\n", | |
" `chrome-ux-report.materialized.device_summary`\n", | |
" WHERE\n", | |
" date = CAST(\"2024-10-01\" AS DATE)\n", | |
" AND device IN ('desktop',\n", | |
" 'tablet',\n", | |
" 'phone') )\n", | |
"SELECT\n", | |
" client,\n", | |
" is_localized,\n", | |
" AVG(ttfb) AS avg_ttfb\n", | |
"FROM\n", | |
" devices\n", | |
" JOIN\n", | |
" pages\n", | |
" USING\n", | |
" (client,\n", | |
" url)\n", | |
"GROUP BY\n", | |
" is_localized,\n", | |
" client\n", | |
"ORDER BY\n", | |
" is_localized ASC,\n", | |
" client ASC\n", | |
"\"\"\"\n", | |
"\n", | |
"localize_or_not_ttfb_2024 = client.query(query).to_dataframe()\n" | |
], | |
"metadata": { | |
"id": "IZs2WmxT1FvT" | |
}, | |
"execution_count": 16, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"localize_or_not_ttfb_2024.head(1000)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 208 | |
}, | |
"id": "ixyepIm-1VNl", | |
"outputId": "b3e033f9-7ddb-40c9-d0c5-82ed18114152" | |
}, | |
"execution_count": 19, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" client is_localized avg_ttfb\n", | |
"0 desktop False 1329.573209\n", | |
"1 mobile False 1597.053311\n", | |
"2 desktop True 1352.784210\n", | |
"3 mobile True 1532.340842" | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-a36e99d1-725a-45bd-a2a9-755673b411f1\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>avg_ttfb</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>1329.573209</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>1597.053311</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>1352.784210</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>1532.340842</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-a36e99d1-725a-45bd-a2a9-755673b411f1')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-a36e99d1-725a-45bd-a2a9-755673b411f1 button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-a36e99d1-725a-45bd-a2a9-755673b411f1');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-53d97e88-730e-4c4b-9c18-addc374bb088\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-53d97e88-730e-4c4b-9c18-addc374bb088')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-53d97e88-730e-4c4b-9c18-addc374bb088 button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "localize_or_not_ttfb_2024", | |
"summary": "{\n \"name\": \"localize_or_not_ttfb_2024\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"avg_ttfb\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 132.06524602108334,\n \"min\": 1329.5732088181987,\n \"max\": 1597.0533109308935,\n \"num_unique_values\": 4,\n \"samples\": [\n 1597.0533109308935,\n 1532.340842273954\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"desktop\",\nfalse,\n{\n 'v': 1329.5732088181987,\n 'f': \"1329.5732088181987\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"mobile\",\nfalse,\n{\n 'v': 1597.0533109308935,\n 'f': \"1597.0533109308935\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"desktop\",\ntrue,\n{\n 'v': 1352.7842097040073,\n 'f': \"1352.7842097040073\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"mobile\",\ntrue,\n{\n 'v': 1532.340842273954,\n 'f': \"1532.340842273954\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"avg_ttfb\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-538a269d-1870-4b27-83ab-d20f8276dfaf\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-538a269d-1870-4b27-83ab-d20f8276dfaf')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-538a269d-1870-4b27-83ab-d20f8276dfaf button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 19 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"### Absolute TTFB change 11/23 -> 10/24" | |
], | |
"metadata": { | |
"id": "RvwaN0FY3Syf" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import pandas as pd\n", | |
"\n", | |
"# Compare absolute change between localize_or_not and localize_or_not_24\n", | |
"merged_df = pd.merge(localize_or_not_ttfb_2023, localize_or_not_ttfb_2024, on=['client', 'is_localized'], suffixes=('_2023', '_2024'))\n", | |
"merged_df['ttfb_p75_absolute_change'] = merged_df['avg_ttfb_2024'] - merged_df['avg_ttfb_2023']\n", | |
"merged_df.head(1000)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 208 | |
}, | |
"id": "54xzjpMB1Xat", | |
"outputId": "107c001b-d3a3-4228-c2ad-974439fe79c7" | |
}, | |
"execution_count": 22, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" client is_localized avg_ttfb_2023 avg_ttfb_2024 \\\n", | |
"0 desktop False 1343.236099 1329.573209 \n", | |
"1 mobile False 1639.110170 1597.053311 \n", | |
"2 desktop True 1376.459262 1352.784210 \n", | |
"3 mobile True 1577.732006 1532.340842 \n", | |
"\n", | |
" ttfb_p75_absolute_change \n", | |
"0 -13.662891 \n", | |
"1 -42.056859 \n", | |
"2 -23.675053 \n", | |
"3 -45.391164 " | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-582a7ed6-0008-49d1-bdc0-8f1cc049b5ef\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>avg_ttfb_2023</th>\n", | |
" <th>avg_ttfb_2024</th>\n", | |
" <th>ttfb_p75_absolute_change</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>1343.236099</td>\n", | |
" <td>1329.573209</td>\n", | |
" <td>-13.662891</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>1639.110170</td>\n", | |
" <td>1597.053311</td>\n", | |
" <td>-42.056859</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>1376.459262</td>\n", | |
" <td>1352.784210</td>\n", | |
" <td>-23.675053</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>1577.732006</td>\n", | |
" <td>1532.340842</td>\n", | |
" <td>-45.391164</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-582a7ed6-0008-49d1-bdc0-8f1cc049b5ef')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-582a7ed6-0008-49d1-bdc0-8f1cc049b5ef button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-582a7ed6-0008-49d1-bdc0-8f1cc049b5ef');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-8b6b0335-3928-4880-a01e-b93b65da2226\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-8b6b0335-3928-4880-a01e-b93b65da2226')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-8b6b0335-3928-4880-a01e-b93b65da2226 button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "merged_df", | |
"summary": "{\n \"name\": \"merged_df\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"avg_ttfb_2023\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 146.31503388460007,\n \"min\": 1343.2360994654653,\n \"max\": 1639.110169663145,\n \"num_unique_values\": 4,\n \"samples\": [\n 1639.110169663145,\n 1577.7320062324136\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"avg_ttfb_2024\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 132.06524602108334,\n \"min\": 1329.5732088181987,\n \"max\": 1597.0533109308935,\n \"num_unique_values\": 4,\n \"samples\": [\n 1597.0533109308935,\n 1532.340842273954\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_p75_absolute_change\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 15.093436795483022,\n \"min\": -45.39116395845963,\n \"max\": -13.662890647266522,\n \"num_unique_values\": 4,\n \"samples\": [\n -42.056858732251385,\n -45.39116395845963\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"desktop\",\nfalse,\n{\n 'v': 1343.2360994654653,\n 'f': \"1343.2360994654653\",\n },\n{\n 'v': 1329.5732088181987,\n 'f': \"1329.5732088181987\",\n },\n{\n 'v': -13.662890647266522,\n 'f': \"-13.662890647266522\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"mobile\",\nfalse,\n{\n 'v': 1639.110169663145,\n 'f': \"1639.110169663145\",\n },\n{\n 'v': 1597.0533109308935,\n 'f': \"1597.0533109308935\",\n },\n{\n 'v': -42.056858732251385,\n 'f': \"-42.056858732251385\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"desktop\",\ntrue,\n{\n 'v': 1376.4592624179481,\n 'f': \"1376.4592624179481\",\n },\n{\n 'v': 1352.7842097040073,\n 'f': \"1352.7842097040073\",\n },\n{\n 'v': -23.675052713940886,\n 'f': \"-23.675052713940886\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"mobile\",\ntrue,\n{\n 'v': 1577.7320062324136,\n 'f': \"1577.7320062324136\",\n },\n{\n 'v': 1532.340842273954,\n 'f': \"1532.340842273954\",\n },\n{\n 'v': -45.39116395845963,\n 'f': \"-45.39116395845963\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"avg_ttfb_2023\"], [\"number\", \"avg_ttfb_2024\"], [\"number\", \"ttfb_p75_absolute_change\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-bd69c2d8-213e-4877-8073-7054cc51872a\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-bd69c2d8-213e-4877-8073-7054cc51872a')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-bd69c2d8-213e-4877-8073-7054cc51872a button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 22 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"### Relative TTFB change 11/23 -> 10/24" | |
], | |
"metadata": { | |
"id": "HIqq35Yo3YKS" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import pandas as pd\n", | |
"\n", | |
"# Compare relative change between localize_or_not and localize_or_not_24\n", | |
"merged_df = pd.merge(localize_or_not_ttfb_2023, localize_or_not_ttfb_2024, on=['client', 'is_localized'], suffixes=('_2023', '_2024'))\n", | |
"merged_df['ttfb_p75_relative_change'] = ( merged_df['avg_ttfb_2024'] - merged_df['avg_ttfb_2023'] ) / merged_df['avg_ttfb_2023']\n", | |
"merged_df.head(1000)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 208 | |
}, | |
"id": "LLi7f3t-26k8", | |
"outputId": "579cecce-49a2-4578-dc82-b6f8febc4ae2" | |
}, | |
"execution_count": 24, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" client is_localized avg_ttfb_2023 avg_ttfb_2024 \\\n", | |
"0 desktop False 1343.236099 1329.573209 \n", | |
"1 mobile False 1639.110170 1597.053311 \n", | |
"2 desktop True 1376.459262 1352.784210 \n", | |
"3 mobile True 1577.732006 1532.340842 \n", | |
"\n", | |
" ttfb_p75_relative_change \n", | |
"0 -0.010172 \n", | |
"1 -0.025658 \n", | |
"2 -0.017200 \n", | |
"3 -0.028770 " | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-8c679565-f375-4961-ba7a-9245bbf504f7\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>avg_ttfb_2023</th>\n", | |
" <th>avg_ttfb_2024</th>\n", | |
" <th>ttfb_p75_relative_change</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>1343.236099</td>\n", | |
" <td>1329.573209</td>\n", | |
" <td>-0.010172</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>1639.110170</td>\n", | |
" <td>1597.053311</td>\n", | |
" <td>-0.025658</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>1376.459262</td>\n", | |
" <td>1352.784210</td>\n", | |
" <td>-0.017200</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>1577.732006</td>\n", | |
" <td>1532.340842</td>\n", | |
" <td>-0.028770</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-8c679565-f375-4961-ba7a-9245bbf504f7')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-8c679565-f375-4961-ba7a-9245bbf504f7 button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-8c679565-f375-4961-ba7a-9245bbf504f7');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-ad6d95a3-8775-46fd-bb8c-2d8d681be5bc\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-ad6d95a3-8775-46fd-bb8c-2d8d681be5bc')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-ad6d95a3-8775-46fd-bb8c-2d8d681be5bc button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "merged_df", | |
"summary": "{\n \"name\": \"merged_df\",\n \"rows\": 4,\n \"fields\": [\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"avg_ttfb_2023\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 146.31503388460007,\n \"min\": 1343.2360994654653,\n \"max\": 1639.110169663145,\n \"num_unique_values\": 4,\n \"samples\": [\n 1639.110169663145,\n 1577.7320062324136\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"avg_ttfb_2024\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 132.06524602108334,\n \"min\": 1329.5732088181987,\n \"max\": 1597.0533109308935,\n \"num_unique_values\": 4,\n \"samples\": [\n 1597.0533109308935,\n 1532.340842273954\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_p75_relative_change\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.00841734495697065,\n \"min\": -0.02876988219745421,\n \"max\": -0.010171622585711929,\n \"num_unique_values\": 4,\n \"samples\": [\n -0.025658347749068344,\n -0.02876988219745421\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"desktop\",\nfalse,\n{\n 'v': 1343.2360994654653,\n 'f': \"1343.2360994654653\",\n },\n{\n 'v': 1329.5732088181987,\n 'f': \"1329.5732088181987\",\n },\n{\n 'v': -0.010171622585711929,\n 'f': \"-0.010171622585711929\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"mobile\",\nfalse,\n{\n 'v': 1639.110169663145,\n 'f': \"1639.110169663145\",\n },\n{\n 'v': 1597.0533109308935,\n 'f': \"1597.0533109308935\",\n },\n{\n 'v': -0.025658347749068344,\n 'f': \"-0.025658347749068344\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"desktop\",\ntrue,\n{\n 'v': 1376.4592624179481,\n 'f': \"1376.4592624179481\",\n },\n{\n 'v': 1352.7842097040073,\n 'f': \"1352.7842097040073\",\n },\n{\n 'v': -0.01719996614527644,\n 'f': \"-0.01719996614527644\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"mobile\",\ntrue,\n{\n 'v': 1577.7320062324136,\n 'f': \"1577.7320062324136\",\n },\n{\n 'v': 1532.340842273954,\n 'f': \"1532.340842273954\",\n },\n{\n 'v': -0.02876988219745421,\n 'f': \"-0.02876988219745421\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"avg_ttfb_2023\"], [\"number\", \"avg_ttfb_2024\"], [\"number\", \"ttfb_p75_relative_change\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-cddbec09-9ce4-4fff-861b-84484b9ebc43\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-cddbec09-9ce4-4fff-861b-84484b9ebc43')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-cddbec09-9ce4-4fff-861b-84484b9ebc43 button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 24 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"## Localized sites over time" | |
], | |
"metadata": { | |
"id": "FXfHNeQr9T9g" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"from google.cloud import bigquery\n", | |
"\n", | |
"client = bigquery.Client(project=project_id)\n", | |
"\n", | |
"query = f\"\"\"\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_GOOD(good FLOAT64,\n", | |
" needs_improvement FLOAT64,\n", | |
" poor FLOAT64)\n", | |
" RETURNS BOOL AS ( SAFE_DIVIDE(good, good + needs_improvement + poor) >= 0.75 );\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_NON_ZERO(good FLOAT64,\n", | |
" needs_improvement FLOAT64,\n", | |
" poor FLOAT64)\n", | |
" RETURNS BOOL AS ( good + needs_improvement + poor > 0 );\n", | |
"CREATE TEMP FUNCTION\n", | |
" IS_LOCALIZED(lang STRING)\n", | |
" RETURNS BOOL AS ( lang IS NOT NULL\n", | |
" AND lang != \"en\"\n", | |
" AND lang != \"en-us\" );\n", | |
"WITH\n", | |
" pages AS (\n", | |
" SELECT\n", | |
" client,\n", | |
" IS_LOCALIZED(REPLACE(TRIM(LOWER(JSON_VALUE(JSON_VALUE(payload, '$._almanac'), '$.html_node.lang'))), '_', '-' )) AS is_localized,\n", | |
" page AS url,\n", | |
" date\n", | |
" FROM\n", | |
" `httparchive.all.pages`,\n", | |
" UNNEST(technologies) AS t\n", | |
" WHERE\n", | |
" date > CAST(\"2023-12-01\" AS DATE)\n", | |
" AND is_root_page\n", | |
" AND t.technology = 'WordPress' ),\n", | |
" devices AS (\n", | |
" SELECT\n", | |
" date,\n", | |
" CONCAT(origin, '/') AS url,\n", | |
" IF\n", | |
" (device = 'desktop', 'desktop', 'mobile') AS client,\n", | |
" IS_NON_ZERO(fast_ttfb,\n", | |
" avg_ttfb,\n", | |
" slow_ttfb) AS any_ttfb,\n", | |
" IS_GOOD(fast_ttfb,\n", | |
" avg_ttfb,\n", | |
" slow_ttfb) AS good_ttfb\n", | |
" FROM\n", | |
" `chrome-ux-report.materialized.device_summary`\n", | |
" WHERE\n", | |
" date > CAST(\"2023-12-01\" AS DATE)\n", | |
" AND device IN ('desktop',\n", | |
" 'tablet',\n", | |
" 'phone') )\n", | |
"SELECT\n", | |
" date,\n", | |
" client,\n", | |
" is_localized,\n", | |
" SAFE_DIVIDE(COUNTIF(good_ttfb), COUNTIF(any_ttfb)) AS ttfb_passing_rate\n", | |
"FROM\n", | |
" devices\n", | |
" JOIN\n", | |
" pages\n", | |
" USING\n", | |
" (date,\n", | |
" client,\n", | |
" url)\n", | |
"GROUP BY\n", | |
" date,\n", | |
" is_localized,\n", | |
" client\n", | |
"ORDER BY\n", | |
" date DESC,\n", | |
" is_localized ASC,\n", | |
" client ASC\n", | |
" \"\"\"\n", | |
"\n", | |
"localize_or_not_over_time = client.query(query).to_dataframe()\n" | |
], | |
"metadata": { | |
"id": "l0-LQA-O9SdK" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"localize_or_not_over_time.head(1000)" | |
], | |
"metadata": { | |
"id": "ZMV3VS9c-EXL", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 670 | |
}, | |
"outputId": "4c1cbb48-74f2-4e9e-8145-b18dc57a8628" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
" date client is_localized ttfb_passing_rate\n", | |
"0 2024-10-01 desktop False 0.316738\n", | |
"1 2024-10-01 mobile False 0.221321\n", | |
"2 2024-10-01 desktop True 0.336921\n", | |
"3 2024-10-01 mobile True 0.270966\n", | |
"4 2024-09-01 desktop False 0.314923\n", | |
"5 2024-09-01 mobile False 0.216768\n", | |
"6 2024-09-01 desktop True 0.339019\n", | |
"7 2024-09-01 mobile True 0.270448\n", | |
"8 2024-08-01 desktop False 0.314144\n", | |
"9 2024-08-01 mobile False 0.220314\n", | |
"10 2024-08-01 desktop True 0.344376\n", | |
"11 2024-08-01 mobile True 0.275307\n", | |
"12 2024-07-01 desktop False 0.316714\n", | |
"13 2024-07-01 mobile False 0.216422\n", | |
"14 2024-07-01 desktop True 0.346693\n", | |
"15 2024-07-01 mobile True 0.272067\n", | |
"16 2024-06-01 desktop False 0.314890\n", | |
"17 2024-06-01 mobile False 0.213893\n", | |
"18 2024-06-01 desktop True 0.341167\n", | |
"19 2024-06-01 mobile True 0.268578\n", | |
"20 2024-05-01 desktop False 0.315471\n", | |
"21 2024-05-01 mobile False 0.211562\n", | |
"22 2024-05-01 desktop True 0.340405\n", | |
"23 2024-05-01 mobile True 0.268464\n", | |
"24 2024-04-01 desktop False 0.324895\n", | |
"25 2024-04-01 mobile False 0.217186\n", | |
"26 2024-04-01 desktop True 0.341155\n", | |
"27 2024-04-01 mobile True 0.269643\n", | |
"28 2024-03-01 desktop False 0.317695\n", | |
"29 2024-03-01 mobile False 0.215624\n", | |
"30 2024-03-01 desktop True 0.336752\n", | |
"31 2024-03-01 mobile True 0.267646\n", | |
"32 2024-02-01 desktop False 0.316770\n", | |
"33 2024-02-01 mobile False 0.201628\n", | |
"34 2024-02-01 desktop True 0.332696\n", | |
"35 2024-02-01 mobile True 0.255326\n", | |
"36 2024-01-01 desktop False 0.317181\n", | |
"37 2024-01-01 mobile False 0.204183\n", | |
"38 2024-01-01 desktop True 0.337619\n", | |
"39 2024-01-01 mobile True 0.262194" | |
], | |
"text/html": [ | |
"\n", | |
" <div id=\"df-4978e332-fa00-423d-a711-2d8a62f6ee16\" class=\"colab-df-container\">\n", | |
" <div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>date</th>\n", | |
" <th>client</th>\n", | |
" <th>is_localized</th>\n", | |
" <th>ttfb_passing_rate</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>2024-10-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.316738</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>2024-10-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.221321</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>2024-10-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.336921</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>2024-10-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.270966</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>2024-09-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.314923</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>5</th>\n", | |
" <td>2024-09-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.216768</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>6</th>\n", | |
" <td>2024-09-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.339019</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>7</th>\n", | |
" <td>2024-09-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.270448</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>8</th>\n", | |
" <td>2024-08-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.314144</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>9</th>\n", | |
" <td>2024-08-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.220314</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>10</th>\n", | |
" <td>2024-08-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.344376</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>11</th>\n", | |
" <td>2024-08-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.275307</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>12</th>\n", | |
" <td>2024-07-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.316714</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>13</th>\n", | |
" <td>2024-07-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.216422</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>14</th>\n", | |
" <td>2024-07-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.346693</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>15</th>\n", | |
" <td>2024-07-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.272067</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>16</th>\n", | |
" <td>2024-06-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.314890</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>17</th>\n", | |
" <td>2024-06-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.213893</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>18</th>\n", | |
" <td>2024-06-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.341167</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>19</th>\n", | |
" <td>2024-06-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.268578</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>20</th>\n", | |
" <td>2024-05-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.315471</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>21</th>\n", | |
" <td>2024-05-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.211562</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>22</th>\n", | |
" <td>2024-05-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.340405</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>23</th>\n", | |
" <td>2024-05-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.268464</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>24</th>\n", | |
" <td>2024-04-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.324895</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>25</th>\n", | |
" <td>2024-04-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.217186</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>26</th>\n", | |
" <td>2024-04-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.341155</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>27</th>\n", | |
" <td>2024-04-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.269643</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>28</th>\n", | |
" <td>2024-03-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.317695</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>29</th>\n", | |
" <td>2024-03-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.215624</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>30</th>\n", | |
" <td>2024-03-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.336752</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>31</th>\n", | |
" <td>2024-03-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.267646</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>32</th>\n", | |
" <td>2024-02-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.316770</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>33</th>\n", | |
" <td>2024-02-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.201628</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>34</th>\n", | |
" <td>2024-02-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.332696</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>35</th>\n", | |
" <td>2024-02-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.255326</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>36</th>\n", | |
" <td>2024-01-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>False</td>\n", | |
" <td>0.317181</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>37</th>\n", | |
" <td>2024-01-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>False</td>\n", | |
" <td>0.204183</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>38</th>\n", | |
" <td>2024-01-01</td>\n", | |
" <td>desktop</td>\n", | |
" <td>True</td>\n", | |
" <td>0.337619</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>39</th>\n", | |
" <td>2024-01-01</td>\n", | |
" <td>mobile</td>\n", | |
" <td>True</td>\n", | |
" <td>0.262194</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>\n", | |
" <div class=\"colab-df-buttons\">\n", | |
"\n", | |
" <div class=\"colab-df-container\">\n", | |
" <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-4978e332-fa00-423d-a711-2d8a62f6ee16')\"\n", | |
" title=\"Convert this dataframe to an interactive table.\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
" <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", | |
" <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", | |
" </svg>\n", | |
" </button>\n", | |
"\n", | |
" <style>\n", | |
" .colab-df-container {\n", | |
" display:flex;\n", | |
" gap: 12px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert {\n", | |
" background-color: #E8F0FE;\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: #1967D2;\n", | |
" height: 32px;\n", | |
" padding: 0 0 0 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-convert:hover {\n", | |
" background-color: #E2EBFA;\n", | |
" box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: #174EA6;\n", | |
" }\n", | |
"\n", | |
" .colab-df-buttons div {\n", | |
" margin-bottom: 4px;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert {\n", | |
" background-color: #3B4455;\n", | |
" fill: #D2E3FC;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-convert:hover {\n", | |
" background-color: #434B5C;\n", | |
" box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", | |
" filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", | |
" fill: #FFFFFF;\n", | |
" }\n", | |
" </style>\n", | |
"\n", | |
" <script>\n", | |
" const buttonEl =\n", | |
" document.querySelector('#df-4978e332-fa00-423d-a711-2d8a62f6ee16 button.colab-df-convert');\n", | |
" buttonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
"\n", | |
" async function convertToInteractive(key) {\n", | |
" const element = document.querySelector('#df-4978e332-fa00-423d-a711-2d8a62f6ee16');\n", | |
" const dataTable =\n", | |
" await google.colab.kernel.invokeFunction('convertToInteractive',\n", | |
" [key], {});\n", | |
" if (!dataTable) return;\n", | |
"\n", | |
" const docLinkHtml = 'Like what you see? Visit the ' +\n", | |
" '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", | |
" + ' to learn more about interactive tables.';\n", | |
" element.innerHTML = '';\n", | |
" dataTable['output_type'] = 'display_data';\n", | |
" await google.colab.output.renderOutput(dataTable, element);\n", | |
" const docLink = document.createElement('div');\n", | |
" docLink.innerHTML = docLinkHtml;\n", | |
" element.appendChild(docLink);\n", | |
" }\n", | |
" </script>\n", | |
" </div>\n", | |
"\n", | |
"\n", | |
"<div id=\"df-0d97e49e-eb68-4a86-be02-8870d7d40498\">\n", | |
" <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-0d97e49e-eb68-4a86-be02-8870d7d40498')\"\n", | |
" title=\"Suggest charts\"\n", | |
" style=\"display:none;\">\n", | |
"\n", | |
"<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", | |
" width=\"24px\">\n", | |
" <g>\n", | |
" <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", | |
" </g>\n", | |
"</svg>\n", | |
" </button>\n", | |
"\n", | |
"<style>\n", | |
" .colab-df-quickchart {\n", | |
" --bg-color: #E8F0FE;\n", | |
" --fill-color: #1967D2;\n", | |
" --hover-bg-color: #E2EBFA;\n", | |
" --hover-fill-color: #174EA6;\n", | |
" --disabled-fill-color: #AAA;\n", | |
" --disabled-bg-color: #DDD;\n", | |
" }\n", | |
"\n", | |
" [theme=dark] .colab-df-quickchart {\n", | |
" --bg-color: #3B4455;\n", | |
" --fill-color: #D2E3FC;\n", | |
" --hover-bg-color: #434B5C;\n", | |
" --hover-fill-color: #FFFFFF;\n", | |
" --disabled-bg-color: #3B4455;\n", | |
" --disabled-fill-color: #666;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart {\n", | |
" background-color: var(--bg-color);\n", | |
" border: none;\n", | |
" border-radius: 50%;\n", | |
" cursor: pointer;\n", | |
" display: none;\n", | |
" fill: var(--fill-color);\n", | |
" height: 32px;\n", | |
" padding: 0;\n", | |
" width: 32px;\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart:hover {\n", | |
" background-color: var(--hover-bg-color);\n", | |
" box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", | |
" fill: var(--button-hover-fill-color);\n", | |
" }\n", | |
"\n", | |
" .colab-df-quickchart-complete:disabled,\n", | |
" .colab-df-quickchart-complete:disabled:hover {\n", | |
" background-color: var(--disabled-bg-color);\n", | |
" fill: var(--disabled-fill-color);\n", | |
" box-shadow: none;\n", | |
" }\n", | |
"\n", | |
" .colab-df-spinner {\n", | |
" border: 2px solid var(--fill-color);\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" animation:\n", | |
" spin 1s steps(1) infinite;\n", | |
" }\n", | |
"\n", | |
" @keyframes spin {\n", | |
" 0% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" border-left-color: var(--fill-color);\n", | |
" }\n", | |
" 20% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 30% {\n", | |
" border-color: transparent;\n", | |
" border-left-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 40% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-top-color: var(--fill-color);\n", | |
" }\n", | |
" 60% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" }\n", | |
" 80% {\n", | |
" border-color: transparent;\n", | |
" border-right-color: var(--fill-color);\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" 90% {\n", | |
" border-color: transparent;\n", | |
" border-bottom-color: var(--fill-color);\n", | |
" }\n", | |
" }\n", | |
"</style>\n", | |
"\n", | |
" <script>\n", | |
" async function quickchart(key) {\n", | |
" const quickchartButtonEl =\n", | |
" document.querySelector('#' + key + ' button');\n", | |
" quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", | |
" quickchartButtonEl.classList.add('colab-df-spinner');\n", | |
" try {\n", | |
" const charts = await google.colab.kernel.invokeFunction(\n", | |
" 'suggestCharts', [key], {});\n", | |
" } catch (error) {\n", | |
" console.error('Error during call to suggestCharts:', error);\n", | |
" }\n", | |
" quickchartButtonEl.classList.remove('colab-df-spinner');\n", | |
" quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", | |
" }\n", | |
" (() => {\n", | |
" let quickchartButtonEl =\n", | |
" document.querySelector('#df-0d97e49e-eb68-4a86-be02-8870d7d40498 button');\n", | |
" quickchartButtonEl.style.display =\n", | |
" google.colab.kernel.accessAllowed ? 'block' : 'none';\n", | |
" })();\n", | |
" </script>\n", | |
"</div>\n", | |
"\n", | |
" </div>\n", | |
" </div>\n" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "dataframe", | |
"variable_name": "localize_or_not_over_time", | |
"summary": "{\n \"name\": \"localize_or_not_over_time\",\n \"rows\": 40,\n \"fields\": [\n {\n \"column\": \"date\",\n \"properties\": {\n \"dtype\": \"dbdate\",\n \"num_unique_values\": 10,\n \"samples\": [\n \"2024-02-01\",\n \"2024-09-01\",\n \"2024-05-01\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"client\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"mobile\",\n \"desktop\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"is_localized\",\n \"properties\": {\n \"dtype\": \"boolean\",\n \"num_unique_values\": 2,\n \"samples\": [\n true,\n false\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ttfb_passing_rate\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.049203231067423595,\n \"min\": 0.20162801193305455,\n \"max\": 0.3466925754999595,\n \"num_unique_values\": 40,\n \"samples\": [\n 0.2685784768692424,\n 0.3148897169608571\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" | |
}, | |
"application/vnd.google.colaboratory.module+javascript": "\n import \"https://ssl.gstatic.com/colaboratory/data_table/54ded79905fc55e4/data_table.js\";\n\n const table = window.createDataTable({\n data: [[{\n 'v': 0,\n 'f': \"0\",\n },\n\"2024-10-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.31673812458898926,\n 'f': \"0.31673812458898926\",\n }],\n [{\n 'v': 1,\n 'f': \"1\",\n },\n\"2024-10-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.22132055966815736,\n 'f': \"0.22132055966815736\",\n }],\n [{\n 'v': 2,\n 'f': \"2\",\n },\n\"2024-10-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.3369209730338933,\n 'f': \"0.3369209730338933\",\n }],\n [{\n 'v': 3,\n 'f': \"3\",\n },\n\"2024-10-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.270965663613118,\n 'f': \"0.270965663613118\",\n }],\n [{\n 'v': 4,\n 'f': \"4\",\n },\n\"2024-09-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.31492291314161674,\n 'f': \"0.31492291314161674\",\n }],\n [{\n 'v': 5,\n 'f': \"5\",\n },\n\"2024-09-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.2167678382883663,\n 'f': \"0.2167678382883663\",\n }],\n [{\n 'v': 6,\n 'f': \"6\",\n },\n\"2024-09-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.33901926234611307,\n 'f': \"0.33901926234611307\",\n }],\n [{\n 'v': 7,\n 'f': \"7\",\n },\n\"2024-09-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.2704479858853762,\n 'f': \"0.2704479858853762\",\n }],\n [{\n 'v': 8,\n 'f': \"8\",\n },\n\"2024-08-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.31414375895680596,\n 'f': \"0.31414375895680596\",\n }],\n [{\n 'v': 9,\n 'f': \"9\",\n },\n\"2024-08-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.22031431308036659,\n 'f': \"0.22031431308036659\",\n }],\n [{\n 'v': 10,\n 'f': \"10\",\n },\n\"2024-08-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.34437565571169165,\n 'f': \"0.34437565571169165\",\n }],\n [{\n 'v': 11,\n 'f': \"11\",\n },\n\"2024-08-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.2753073479156371,\n 'f': \"0.2753073479156371\",\n }],\n [{\n 'v': 12,\n 'f': \"12\",\n },\n\"2024-07-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.3167140063744162,\n 'f': \"0.3167140063744162\",\n }],\n [{\n 'v': 13,\n 'f': \"13\",\n },\n\"2024-07-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.21642178987929583,\n 'f': \"0.21642178987929583\",\n }],\n [{\n 'v': 14,\n 'f': \"14\",\n },\n\"2024-07-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.3466925754999595,\n 'f': \"0.3466925754999595\",\n }],\n [{\n 'v': 15,\n 'f': \"15\",\n },\n\"2024-07-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.27206664485469856,\n 'f': \"0.27206664485469856\",\n }],\n [{\n 'v': 16,\n 'f': \"16\",\n },\n\"2024-06-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.3148897169608571,\n 'f': \"0.3148897169608571\",\n }],\n [{\n 'v': 17,\n 'f': \"17\",\n },\n\"2024-06-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.21389310250276086,\n 'f': \"0.21389310250276086\",\n }],\n [{\n 'v': 18,\n 'f': \"18\",\n },\n\"2024-06-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.3411673235956017,\n 'f': \"0.3411673235956017\",\n }],\n [{\n 'v': 19,\n 'f': \"19\",\n },\n\"2024-06-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.2685784768692424,\n 'f': \"0.2685784768692424\",\n }],\n [{\n 'v': 20,\n 'f': \"20\",\n },\n\"2024-05-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.31547140573225085,\n 'f': \"0.31547140573225085\",\n }],\n [{\n 'v': 21,\n 'f': \"21\",\n },\n\"2024-05-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.21156238614823855,\n 'f': \"0.21156238614823855\",\n }],\n [{\n 'v': 22,\n 'f': \"22\",\n },\n\"2024-05-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.3404050314023541,\n 'f': \"0.3404050314023541\",\n }],\n [{\n 'v': 23,\n 'f': \"23\",\n },\n\"2024-05-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.2684636741917312,\n 'f': \"0.2684636741917312\",\n }],\n [{\n 'v': 24,\n 'f': \"24\",\n },\n\"2024-04-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.32489482257024893,\n 'f': \"0.32489482257024893\",\n }],\n [{\n 'v': 25,\n 'f': \"25\",\n },\n\"2024-04-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.217186363327539,\n 'f': \"0.217186363327539\",\n }],\n [{\n 'v': 26,\n 'f': \"26\",\n },\n\"2024-04-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.341155435440879,\n 'f': \"0.341155435440879\",\n }],\n [{\n 'v': 27,\n 'f': \"27\",\n },\n\"2024-04-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.2696428165039485,\n 'f': \"0.2696428165039485\",\n }],\n [{\n 'v': 28,\n 'f': \"28\",\n },\n\"2024-03-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.31769494986200153,\n 'f': \"0.31769494986200153\",\n }],\n [{\n 'v': 29,\n 'f': \"29\",\n },\n\"2024-03-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.21562364129410375,\n 'f': \"0.21562364129410375\",\n }],\n [{\n 'v': 30,\n 'f': \"30\",\n },\n\"2024-03-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.3367518431130297,\n 'f': \"0.3367518431130297\",\n }],\n [{\n 'v': 31,\n 'f': \"31\",\n },\n\"2024-03-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.26764605634527305,\n 'f': \"0.26764605634527305\",\n }],\n [{\n 'v': 32,\n 'f': \"32\",\n },\n\"2024-02-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.31677002838606316,\n 'f': \"0.31677002838606316\",\n }],\n [{\n 'v': 33,\n 'f': \"33\",\n },\n\"2024-02-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.20162801193305455,\n 'f': \"0.20162801193305455\",\n }],\n [{\n 'v': 34,\n 'f': \"34\",\n },\n\"2024-02-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.3326962175095445,\n 'f': \"0.3326962175095445\",\n }],\n [{\n 'v': 35,\n 'f': \"35\",\n },\n\"2024-02-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.2553257961197636,\n 'f': \"0.2553257961197636\",\n }],\n [{\n 'v': 36,\n 'f': \"36\",\n },\n\"2024-01-01\",\n\"desktop\",\nfalse,\n{\n 'v': 0.3171814483100353,\n 'f': \"0.3171814483100353\",\n }],\n [{\n 'v': 37,\n 'f': \"37\",\n },\n\"2024-01-01\",\n\"mobile\",\nfalse,\n{\n 'v': 0.20418311485408536,\n 'f': \"0.20418311485408536\",\n }],\n [{\n 'v': 38,\n 'f': \"38\",\n },\n\"2024-01-01\",\n\"desktop\",\ntrue,\n{\n 'v': 0.3376194277271884,\n 'f': \"0.3376194277271884\",\n }],\n [{\n 'v': 39,\n 'f': \"39\",\n },\n\"2024-01-01\",\n\"mobile\",\ntrue,\n{\n 'v': 0.26219391287437727,\n 'f': \"0.26219391287437727\",\n }]],\n columns: [[\"number\", \"index\"], [\"string\", \"date\"], [\"string\", \"client\"], [\"string\", \"is_localized\"], [\"number\", \"ttfb_passing_rate\"]],\n columnOptions: [{\"width\": \"1px\", \"className\": \"index_column\"}],\n rowsPerPage: 25,\n helpUrl: \"https://colab.research.google.com/notebooks/data_table.ipynb\",\n suppressOutputScrolling: true,\n minimumWidth: undefined,\n });\n\n function appendQuickchartButton(parentElement) {\n let quickchartButtonContainerElement = document.createElement('div');\n quickchartButtonContainerElement.innerHTML = `\n<div id=\"df-687d601f-799f-4eee-bd0c-0d2085b2b1f1\">\n <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-687d601f-799f-4eee-bd0c-0d2085b2b1f1')\"\n title=\"Suggest charts\"\n style=\"display:none;\">\n \n<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n width=\"24px\">\n <g>\n <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n </g>\n</svg>\n </button>\n \n<style>\n .colab-df-quickchart {\n --bg-color: #E8F0FE;\n --fill-color: #1967D2;\n --hover-bg-color: #E2EBFA;\n --hover-fill-color: #174EA6;\n --disabled-fill-color: #AAA;\n --disabled-bg-color: #DDD;\n }\n\n [theme=dark] .colab-df-quickchart {\n --bg-color: #3B4455;\n --fill-color: #D2E3FC;\n --hover-bg-color: #434B5C;\n --hover-fill-color: #FFFFFF;\n --disabled-bg-color: #3B4455;\n --disabled-fill-color: #666;\n }\n\n .colab-df-quickchart {\n background-color: var(--bg-color);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n display: none;\n fill: var(--fill-color);\n height: 32px;\n padding: 0;\n width: 32px;\n }\n\n .colab-df-quickchart:hover {\n background-color: var(--hover-bg-color);\n box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n fill: var(--button-hover-fill-color);\n }\n\n .colab-df-quickchart-complete:disabled,\n .colab-df-quickchart-complete:disabled:hover {\n background-color: var(--disabled-bg-color);\n fill: var(--disabled-fill-color);\n box-shadow: none;\n }\n\n .colab-df-spinner {\n border: 2px solid var(--fill-color);\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n animation:\n spin 1s steps(1) infinite;\n }\n\n @keyframes spin {\n 0% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n border-left-color: var(--fill-color);\n }\n 20% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 30% {\n border-color: transparent;\n border-left-color: var(--fill-color);\n border-top-color: var(--fill-color);\n border-right-color: var(--fill-color);\n }\n 40% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-top-color: var(--fill-color);\n }\n 60% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n }\n 80% {\n border-color: transparent;\n border-right-color: var(--fill-color);\n border-bottom-color: var(--fill-color);\n }\n 90% {\n border-color: transparent;\n border-bottom-color: var(--fill-color);\n }\n }\n</style>\n\n <script>\n async function quickchart(key) {\n const quickchartButtonEl =\n document.querySelector('#' + key + ' button');\n quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n quickchartButtonEl.classList.add('colab-df-spinner');\n try {\n const charts = await google.colab.kernel.invokeFunction(\n 'suggestCharts', [key], {});\n } catch (error) {\n console.error('Error during call to suggestCharts:', error);\n }\n quickchartButtonEl.classList.remove('colab-df-spinner');\n quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n }\n (() => {\n let quickchartButtonEl =\n document.querySelector('#df-687d601f-799f-4eee-bd0c-0d2085b2b1f1 button');\n quickchartButtonEl.style.display =\n google.colab.kernel.accessAllowed ? 'block' : 'none';\n })();\n </script>\n</div>`;\n parentElement.appendChild(quickchartButtonContainerElement);\n }\n\n appendQuickchartButton(table);\n " | |
}, | |
"metadata": {}, | |
"execution_count": 9 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# prompt: plot the ttfb_passing_rate by date\n", | |
"\n", | |
"import pandas as pd\n", | |
"import matplotlib.pyplot as plt\n", | |
"import seaborn as sns\n", | |
"\n", | |
"\n", | |
"df = localize_or_not_over_time.copy()\n", | |
"\n", | |
"# Plotting with Seaborn (highly recommended for clarity)\n", | |
"sns.set_theme(style=\"whitegrid\")\n", | |
"\n", | |
"# Create subplots for each client type\n", | |
"plt.figure(figsize=(12, 6))\n", | |
"for client_type in df['client'].unique():\n", | |
" plt.subplot(1, len(df['client'].unique()), list(df['client'].unique()).index(client_type) + 1)\n", | |
"\n", | |
" # Filter data for the specific client type\n", | |
" df_client = df[df['client'] == client_type]\n", | |
"\n", | |
" # Plot lines for localized and non-localized\n", | |
" sns.lineplot(x='date', y='ttfb_passing_rate', hue='is_localized', data=df_client, marker='o', palette=['blue', 'orange'])\n", | |
"\n", | |
" # Formatting\n", | |
" plt.title(f'TTFB Passing Rate - {client_type}')\n", | |
" plt.xlabel('Date')\n", | |
" plt.ylabel('TTFB Passing Rate')\n", | |
" plt.xticks(rotation=45)\n", | |
" plt.ylim(0, 1) # Set y-axis to 0-1 range\n", | |
" plt.legend(title='Localized', labels=['No', 'Yes'])\n", | |
"\n", | |
"plt.tight_layout()\n", | |
"plt.show()" | |
], | |
"metadata": { | |
"id": "mZNRTFs0-Icm", | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 601 | |
}, | |
"outputId": "5212d686-f239-4de5-d405-445f25201a36" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "display_data", | |
"data": { | |
"text/plain": [ | |
"<Figure size 1200x600 with 2 Axes>" | |
], | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAABJwAAAJICAYAAAAkUf7fAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAACdMklEQVR4nOzdd3gU9fbH8c+mF1IIvUozASlKES6gqAgKNrAB0m2AckWxIKgXxYrYKSoKCKIComLhKor6u6KgWBEVVHoRCT297s7vj3WXbOpmM0l2J+/X8+yT7LQ9Z0ty5ux3ZmyGYRgCAAAAAAAATBJU3QEAAAAAAADAWmg4AQAAAAAAwFQ0nAAAAAAAAGAqGk4AAAAAAAAwFQ0nAAAAAAAAmIqGEwAAAAAAAExFwwkAAAAAAACmouEEAAAAAAAAU9FwAgAAAAAAgKloOAGodklJSZozZ051h1EjjBo1SqNGjaqUbW/cuFFJSUlas2ZNpWwfAACUjHoqcL3zzjtKSkrSL7/8UuayhWu5/fv3KykpSe+8805lhgj4JKS6AwACTVJSkqnbe/XVV9WkSROdf/75xc4//fTT9eabb0qSpk6dqlWrVrnnBQcHq169eurSpYsmTpyoNm3alPl4BeO32WyqW7euEhMTNX78ePXo0aOC2QSW/fv3ezzvNptNsbGx6tSpkyZOnKjOnTv7tN3XX39dkZGRuuKKK8wK1VJ+/PFHrV+/XmPGjFFsbGx1hwMAqAbUU9ZBPQWgJDScgHKaNWuWx/333ntP69evLzLd4XAoKCiozOVat26t7OxsSdIll1yiPn36eMxPSEjwuB8WFqaHH35YkmS327V3714tX75cX375pf773/+qQYMGZebQu3dvDRo0SIZhaP/+/Vq2bJnGjBmj+fPn65xzzilzfbNt3rxZwcHBVf64Lq7n3eFwaPfu3XrjjTc0evRovfXWWz4VxMuWLVPt2rUpkErw008/ae7cubr88stpOAFADUU9ZT7qqZph4cKF1R0C4DUaTkA5DRo0yOP+zz//rPXr1xeZXlhpy+3fv1+SdNppp5W5nZCQkCLLnHHGGRo/fry++OILDRkypMwcWrRo4bGN/v3767LLLtOrr75aLQVSeHh4lT9mQYWf965du+rGG2/UsmXL9MADD1RfYAAAWBT1lPmop2qGsLCw6g4B8BrncAIsoG7dupLk87daSUlJql27trtQ+/777zVp0iSde+656tChg8455xw9+uij7m8OXQ4fPqxp06apT58+6tChg8466yzddNNN7u1I0i+//KLrr79ePXr0UKdOndS3b19NmzatyOMXPOfAnDlzlJSUpD179mjq1Knq1q2bunbtqmnTpikrK8tj3ezsbD388MPq0aOHOnfurAkTJig5OblC5zHo1q2bJGnfvn0e099++22NHj1aPXv2VIcOHXTRRRfpjTfe8Fimb9++2rZtm7799lslJSUpKSnJ4zj71NRUPfLIIzrnnHPUoUMH9e/fXy+99JIcDodPsZZmxYoV6tevnzp16qSrrrpK33//fbHL5ebmavbs2erfv7/79Z41a5Zyc3M9llu/fr2uueYadevWTZ07d9aFF16op59+utQYcnNzNX78eHXt2lU//vij5syZ4/5W+vzzz3c/R673TH5+vubNm6d+/fqpQ4cO6tu3r55++ukisfTt21fjx4/XV199pUGDBqljx4666KKL9Mknn/j6dAEAajjqKeqpwkaNGqVLLrlEv//+u0aOHKnTTz9d/fv3d5+v8ttvv9XVV1+tTp066cILL9SGDRuKbGPLli264YYb1KVLF3Xu3FljxozRpk2bin287OxsTZ8+XT169FCXLl00ZcoUpaSkFInJm/Nx7tixQ5MmTVL37t3VsWNHXXHFFfrss8/K/yQAFcAIJ8CPZGVl6dixYx7TYmJiFBoa6jHNtYzD4dC+ffv05JNPKj4+Xuedd55Pj5uSkqLU1FSdcsopkqQ1a9YoOztb11xzjeLj47V582a99tprOnjwoGbPnu1e75ZbbtH27ds1cuRINWnSRMeOHdP69ev1999/q2nTpjp69Kiuv/561a5dW+PGjVNsbKz279+vtWvXehXXbbfdpqZNm+r222/Xli1btHLlSiUkJOiuu+5yLzN16lR99NFHGjRokE4//XR99913GjdunE/Pg8tff/0lSUUO91q2bJlOPfVU9e3bVyEhIfq///s/zZgxQ4ZhaMSIEZKke+65Rw899JCioqI0YcIESScL2KysLI0cOVLJyckaNmyYGjVqpJ9++klPP/20Dh8+rHvvvbdCcRe0cuVKTZ8+3V3Y7Nu3TzfddJPi4uLUqFEj93IOh0M33XSTfvjhBw0ZMkStW7fWn3/+qSVLlmj37t16/vnnJUnbtm3T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o6NVr169IjVQafbu3SvDMPTcc8/pueeeK3aZo0ePenUlRqCiaDgBFtCwYUO1bNnS6290GjZsWGIhZrfbde211yolJUU33HCDWrVqpaioKCUnJ2vq1Kkeo1vGjh2rvn376tNPP9VXX32l5557Ti+99JKWLFmi0047TTabTbNnz9amTZv0f//3f/ryyy91zz336JVXXtGKFSsUHR1dapyFGxkuhmF4lae3Cham5513noKCgvTUU0+pR48e6tixoyTnP++xY8eqVatWmjp1qho1aqTQ0FB98cUXWrx4sVcnqXQ4HOrdu7duuOGGYue7miXFeeSRR7Rq1Sr3/e7du2vp0qXlyLLkmBITE4uceNTFVUxFRETo9ddf18aNG/W///1PX375pT788EOtWLFCixYt8jjB6vnnn68PP/xQL730kmbNmlXi61iS8pyjAAAAs1BPVYxV66mSTiJf0nSzn9fycj2H1113nc4+++xilyn85R5QWWg4ARZht9uVmZlZ4e38+eef2r17tx5//HENHjzYPX39+vXFLt+8eXNdd911uu6667R7924NHjxYixYt0pNPPule5owzztAZZ5yhyZMn64MPPtCdd96pDz/8UFdffXWFYm3cuLEcDof279/vUVzs2bOnQtu96aabtHLlSj377LNauHChJOnzzz9Xbm6uXnjhBY9vCl2HnBVUUsOkefPmyszMLPNb1+LccMMNuuyyy9z3C5+AsyBXfHv27PH49i8vL0/79+/3OKygefPm+v3339WzZ88yGz1BQUHuQwemTZumF198Uc8884w2btzokVO/fv101llnaerUqYqOjtaMGTM8tlPS4zRp0kQOh0N79uxR69at3dOPHDmi1NRUNWnSxGP5PXv2yDAMj+3t3r3bvS0AAMqLeqqFe3pNr6cqKiEhQZGRkcUeorlz504FBQV5XMhFcj7nrtMaSFJGRoYOHz6sPn36eP24rtHsoaGhPj1HgJk4hxNgAbt27dKuXbuKnJ/AF65vwQp+O2MYhl599VWP5bKyspSTk+MxrXnz5oqOjnZfwj4lJaXItzyu8/kUvsy9L8466yxJKnIp3ddee61C242NjdXQoUP11VdfaevWrZJOfotVMJ+0tDS9/fbbRdaPjIx0D6cuaODAgfrpp5/c50ooKDU1Vfn5+SXG1KZNG/Xq1ct969ChQ4nLdujQQQkJCVq+fLnH87xq1aoicQ0cOFDJycl68803i2wnOzvbXXSfOHGiyPzSXsvBgwfrvvvu0/Lly/XEE094zIuMjJSkIudpOOeccyRJS5Ys8Zj+yiuveMx3OXTokMcVetLT0/Xuu++qXbt2HE4HACg36inqKTMFBwerd+/e+uyzz7R//3739CNHjmj16tXq2rWr+2p2LitWrPA4T9eyZcuUn59froZTnTp11L17d61YsUKHDh0qMr+0Qw4BszHCCQgw+fn5eu+99yQ5/1nv379fy5cvl8Ph0MSJEyu8/VatWql58+Z6/PHHlZycrFq1aunjjz8u8g9/9+7dGjt2rAYMGKA2bdooODhYn376qY4cOeI+seKqVau0bNky9evXT82bN1dGRobefPNN1apVq1z/OEvSoUMHXXjhhVqyZIlOnDjhvoyva5RLRQ7NGj16tJYsWaKXXnpJzzzzjHr37q3Q0FBNmDBBw4YNU0ZGhlauXKk6deoUOUF1+/bttWzZMj3//PM65ZRTlJCQoJ49e+r666/X559/rgkTJujyyy9X+/btlZWVpT///FMff/yxPvvsMyUkJFTkKZHk/Ebrtttu0/Tp0zVmzBhddNFF2r9/v955550i53AaNGiQPvroI91///3auHGjunTpIrvdrp07d2rNmjVasGCBOnbsqHnz5un777/XOeecoyZNmujo0aN644031LBhQ3Xt2rXYOEaOHKn09HQ988wziomJcV/WuH379pKkZ555RhdddJFCQ0N13nnnqW3btrr88su1YsUKpaam6swzz9Qvv/yiVatWqV+/fh7f+EnOIfP33nuvfvnlF9WpU0dvv/22jh49qscee6zCzyEAwNqop06inqo8t912mzZs2KDhw4dr+PDhCg4O1ooVK5Sbm6u77rqryPJ5eXkaO3asBg4cqF27dumNN95Q165ddf7555frce+//34NHz5cl156qYYMGaJmzZrpyJEj2rRpkw4ePKj333/frBSBUtFwAgJMbm6upkyZ4r5fq1YtdezYUU888USJJ08sj9DQUL344ot6+OGHNX/+fIWHh6t///4aMWKEBg0a5F6uYcOGuvjii/X111/r/fffV3BwsFq1aqVnn31WF154oSTncfG//PKLPvzwQx05ckQxMTHq1KmTnnzyySKND189/vjjqlu3rv773/9q7dq16tWrl5555hkNGDDAqxNplqRBgwa69NJL9d5772nv3r1q1aqVZs+erWeffdb9mNdcc40SEhJ0zz33eKw7ceJEHThwQAsWLFBGRoa6d++unj17KjIyUkuXLtX8+fO1Zs0avfvuu6pVq5ZatGihW265pcyTZJbH0KFDZbfbtXDhQs2aNUuJiYl64YUXipw8MigoSPPmzdPixYv13nvvae3atYqMjFTTpk01atQo94ku+/btq7/++ktvv/22jh8/rtq1a6t79+5lxj1hwgSlpaW5m04jRoxQp06ddOutt2r58uX68ssv5XA49NlnnykqKkoPP/ywmjZtqlWrVunTTz9V3bp1NX78eP373/8usu0WLVroP//5j2bNmqVdu3apadOmeuaZZ0o8XwEAAC7UU56opyrHqaeeqtdff11PPfWU5s+fL8Mw1KlTJz3xxBMeV7hzmT59uj744APNnj1beXl5uvjii3XfffeVu+nXpk0bvf3225o7d65WrVqlEydOKCEhQaeddpopDVXAWzajus9qBgAm27p1qwYPHqwnnnjC4zh9WEffvn116qmnav78+dUdCgAAlkQ9BaCiOIcTgIBW8NK2LkuWLFFQUJDOPPPMaogIAAAgsFBPAagMfnVI3Z49e7Rw4UL9/PPP2rZtm1q1aqXVq1eXuZ5hGHr55Zf1xhtv6NixY2rXrp2mTZumM844o/KDBlCtFixYoF9//VX/+te/FBwcrHXr1mndunUaOnRokSt/AIDVUDsBMAP1FIDK4FcNp23btumLL77Q6aefLofDUeRqDCV5+eWXNXv2bN15551KSkrS66+/ruuuu07vvfeeacc1A/BPnTt31vr16/X8888rMzNTjRo10i233OI+QTUAWBm1EwAzUE8BqAx+dQ4nh8PhvoTo1KlT9euvv5b5LV1OTo569eqlESNG6Pbbb5fkPAnggAED1KdPHz3wwAOVHTYAAEC1oHYCAAD+yq/O4eQqmMrjxx9/VHp6ugYOHOieFhYWpv79+2vdunVmhgcAAOBXqJ0AAIC/8quGky927twpSWrVqpXH9NatW+vAgQPFngAPAACgpqJ2AgAAVcGvzuHki9TUVIWFhSk8PNxjemxsrAzDUEpKiiIiIsq93Z9++kmGYSg0NNSsUAEAQDXLy8uTzWZT586dqzuUakPtBAAAvFWR2ingG06VxTAMGYah3Nzc6g4FAADA71E7AQCAggK+4RQbG6vc3Fzl5OR4fFOXmpoqm82muLg4n7YbGhoqwzDUpk0bs0J1y8rK0u7du9WiRQtFRkaavv2qFuj5BHr8hVklH6vk4WKVfKyShwv5+KfKzGP79u2y2WymbjPQUDtVv0DPJ9DjL8wq+VglDxer5GOVPFzIxz/5a+0U8A0n1/kHdu3apbZt27qn79y5U40bN/ZpSLiLzWZTVFRUhWMsSWRkZKVuv6oFej6BHn9hVsnHKnm4WCUfq+ThQj7+qTLyqOnNJonayZ8Eej6BHn9hVsnHKnm4WCUfq+ThQj7+yd9qp4A/aXiXLl1Uq1YtffTRR+5peXl5+uSTT9SnT59qjAwAAMD/UDsBAICq4FcjnLKysvTFF19Ikv766y+lp6drzZo1kqTu3bsrISFBY8aM0YEDB7R27VpJUnh4uMaPH685c+YoISFBiYmJWrZsmU6cOKHrr7++2nIBAACobNROAADAX/lVw+no0aO69dZbPaa57r/66qvq0aOHHA6H7Ha7xzI33nijDMPQokWLdOzYMbVr104LFy5Us2bNqix2AACAqkbtBAAA/JVfNZyaNm2qP/74o9Rlli5dWmSazWbT+PHjNX78+MoKDQAAwO9QOwEAAH/lVw0nAABqCrvdrry8PFO3mZOT4/4ZFBS4p2n0NY/Q0FAFBwdXVlgAAKAaUTuVzF9rJxpOAABUIcMwdPDgQZ04ccL0bTscDoWEhOjAgQMBXTRVJI/4+Hg1bNiQq9EBAGAR1E5l89faiYYTAABVyFUw1a9fX1FRUab+c7fb7crJyVF4eHhAj/TxJQ/DMJSZmalDhw5Jkho1alSZIQIAgCpC7VQ2f62daDgBAFBF7Ha7u2CqU6dOpWxfkiIiIgK+aJLKn0dkZKQk6dChQ6pfv35APwcAAIDayVv+WjsF7pgxAAACjOu8A1FRUdUciXW5nluzz/EAAACqHrVT5avM2omGEwAAVYzzC1UenlsAAKyH/++VpzKfWxpOAAAAAAAAMBUNJwAAUKqkpCTNmTPHff+dd95RUlKS9u/fX6Vx9O3bV1OnTq3SxwQAACgvaicnGk4AAPgJVzHyyy+/VHcoAAAAfo/ayb/RcAIAAOUyaNAgbd68WU2aNKnuUAAAAPxeTa2dQqo7AAAAEFiCg4MD+tLBAAAAVamm1k6McAIAIIBs2bJFN9xwg7p06aLOnTtrzJgx2rRpU5HlUlNT9eijj6pv377q0KGD+vTpoylTpujYsWOSpNzcXD333HO64oor1LVrV51xxhkaPny4vvnmmzJjKHwegjlz5igpKanYW8HzBjgcDi1evFgXX3yxOnbsqF69emn69OlKSUnx2L5hGFqwYIHOO+88nX766Ro1apS2bdtWgWcNAADUVNRO1YcRTgAABIht27ZpxIgRio6O1g033KCQkBCtWLFCo0aN0muvvaYOHTpIkjIyMjRixAjt2LFDV155pU477TQdP35cn3/+uZKTk5WQkKD09HStXLlSl1xyia6++mplZGTorbfe0g033KCVK1eqXbt2XsfVv39/NW/e3GPab7/9piVLlighIcE9bfr06Vq1apWuuOIKjRo1Svv379frr7+uLVu2aNmyZQoNDZXkLMJefPFF9enTR+eee65+++03XXfddcrLyzPhWQQAADUFtVP11k40nAAACBDPPvus8vLytGzZMjVr1kySNHjwYA0YMEBPPPGElixZIklatGiR/vzzT82dO1f9+/d3r3/zzTfLMAxJUlxcnD7//HOFhYW55w8ZMkQDBw7U0qVL9eijj3odV9u2bdW2bVv3/WPHjunZZ59VYmKi/v3vf0uSvv/+e61cuVJPPvmkLr30UveyPXr00A033KA1a9bo0ksv1bFjx7Rw4UKdddZZeuGFFxQS4ixVnnnmGb344ovlfcoAAEANRu1UvbUTh9QBABAA7Ha71q9fr379+rkLJkmqX7++LrnkEv3www9KT0+XJK1du1Zt27b1KJhcbDabJOe5BFwFk8Ph0IkTJ5Sfn68OHTpoy5YtFYrzjjvuUEZGhubNm6eoqChJ0po1axQTE6PevXvr2LFj7lv79u0VFRWljRs3SpI2bNigvLw8DRs2zB2rJI0ZM8bnmAAAQM1D7VT9tRMjnAAACADHjh1TVlaWWrZsWWRe69at5XA49Pfff6tZs2bat2+fLrjggjK3uWrVKi1atEi7du3yGHLdtGlTn+N89tln9c0332j+/PkeQ8X37NmjtLQ09ezZs9j1jh49Kkk6cOCAJBUZZp6QkKC4uDif4wIAADULtVP11040nAAAqIHee+89TZ06Vf369dP111+vOnXqKDg4WPPnz9e+fft82uann36ql19+Wbfeeqv69OnjMc/hcKhOnTp68skni1234PkKAAAA/A21U/nRcAIAIAAkJCQoMjJSu3btKjJv586dCgoKUqNGjSRJzZo1K/PKJB9//LGaNWumuXPnegy/nj17tk/x7dq1S3fffbf69eunCRMmFJnfvHlzff311+rSpYsiIiJK3E7jxo0lSXv37lWbNm3c048dO1bkiiwAAAAloXaq/tqJczgBABAAgoOD1bt3b3322WfuS+pK0pEjR7R69Wp17dpVtWrVkuS88snvv/+utWvXFtmO68SXwcHBHvcl6eeffy72MsFlycjI0L///W81aNBAM2fO9CjCXAYOHCi73a7nn3++yLz8/HylpqZKknr16qWQkBAtX77cIzbXST0BAAC8Qe1U/bUTI5wAAPAzb7/9tr788ssi02+55RZt2LBBw4cP1/DhwxUcHKwVK1YoNzdXd911l3u56667TmvXrtWtt96qK6+8Uu3bt1dKSoo+//xzzZgxQ23bttW5556rTz75RBMnTtS5556r/fv3a/ny5WrTpo0yMzPLFe/cuXO1fft23XTTTfrss8885jVv3lydO3dW9+7dNXToUM2fP19bt25V7969FRoaqt27d2vNmjW69957NWDAACUkJOjaa6/Vyy+/rJtuuknnnnuutmzZonXr1ql27dq+PaEAAMDSqJ38s3ai4QQAgJ9ZtmxZsdOvuOIKvf7663rqqac0f/58GYahTp066YknntDpp58uu90uSYqOjtbrr7+uOXPmaO3atVq1apXq1Kmjnj17qkGDBu5tHTlyRCtWrNBXX32lNm3a6IknntCaNWv07bfflive48ePS5JeeOGFIvMuv/xyde7cWZL04IMPqkOHDlq+fLmeeeYZBQcHq0mTJrrsssvUpUsX9zq33nqrgoOD9fbbb+vbb79Vp06dtGjRIo0fP75ccQEAgJqB2sk/ayebUXDMFdx++eUXSVLHjh1N33ZmZqa2bt2qdu3auS95GMgCPZ9Aj78wq+RjlTxcrJKPVfJwqep8srOztWvXLrVs2bLUY/F9ZbfblZ2drYiICPew70BUkTzKeo4r8/97TUft5L1AzyfQ4y/MKvlYJQ8Xq+RjlTxcqJ38k7/WTpzDCQAAAAAAAKai4QQAAAAAAABT0XACAAAAAACAqWg4AQAAAAAAwFQ0nAAAAAAAAGAqGk4AAAAAAAAwFQ0nAAAAAAAAmIqGEwAAAAAAAExFwwkAAAAAAACmouEEAAAAAAAAU9FwAgAAAAAAgKloOAEAAFPMmTNHSUlJGjFiRJF5jzzyiPr27VsNUQEAAPgnq9dONJwAAICpvv/+e23cuLG6wwAAAAgIVq2daDgBAGAhdnu47PYgHTok5eZKGRlV+/hRUVHq1KmTnn/++ap9YAAAAB9QO1UeGk4AAFhEXl6QnnoqWA0a2NSggdSggTRrlpSdXbVx3Hzzzfrmm2/0448/lrjMX3/9pUmTJqlr164644wzdP311+uPP/6owigBAEBNR+1UuUKqOwAAAODJMKTMzPKtY7dLTz0lPfigzT3txAnpwQedv99xhxQc7N22oqIkm63s5Upy3nnn6bTTTtO8efO0cOHCIvPT09M1atQoBQUFacaMGQoPD9cLL7ygkSNH6v3331f9+vV9f3AAAFDjUDv5Z+3ECCcAAPyIYUhnnSXVquX9rUULZ0E0e3bxlc7s2c75LVp4t72zz3bGURE33XSTvvrqK23evLnIvHfeeUcHDhzQ/Pnzdckll6h///5atGiR8vPztWTJkoo9MAAAqFGonfy3dqLhBACAnynvN2QNG0qHDjm/lSvOiRPS4cPO5apK//79lZiYqHnz5hWZ9/333+vUU09V69at3dPi4+PVq1cv/fDDD1UXJAAAsARqJ//EIXUAAPgRm0368svyDwsPDZXi44svnOLjpcaNpW++8W5bFR0WLkk2m00TJkzQ7bffrt9++81jXmpqqurWrVtknTp16mjbtm0Ve2AAAFCjUDv5b+3ECCcAAPyMzSZFR5fvlpcnTZpU/FjuSZOc873dVkULJpeBAweqZcuWRa66EhcXp6NHjxZZ/ujRo4qLizPnwQEAQI1B7eSfaDgBAGAB0dHStGnS9OmG4uOd0+LjpenTndOjo6s+pqCgIE2YMEGfffaZx1VUunbtqj///FM7d+50T0tJSdGGDRvUtWvXqg8UAADUONROlY+GEwAAFhEa6tAdd9iVnGzo0CEpOVmaMkWKiKi+mC699FI1a9ZMGzdudE+74oor1LhxY40fP17//e9/9emnn+q6665TSEiIxowZU33BAgCAGoXaqXLRcAIAwEKCg3MUHOxQvXpSWFj1fDvnGU+wxo0b5zGtVq1aWrp0qdq2bav//Oc/uvPOOxUXF6fXXntNjRo1qqZIAQBATUTtVHk4aTgAADDFLbfcoltuuaXI9KuvvlpXX321x7QmTZpozpw5VRUaAACA37F67cQIJwAAAAAAAJiKhhMAAAAAAABMRcMJAAAAAAAApqLhBAAAAAAAAFPRcAIAAAAAAICpaDgBAAAAAADAVDScAAAAAAAAYCoaTgAAAAAAADAVDScAAAAAAACYioYTAACosFGjRmngwIHKzc0tMm/SpEk655xzlJGRUQ2RAQAA+J+aUDuFVHcAAACgqNxcKT+/fOvY7VJ2tuRwSMHBvj92SIgUFla+dWbMmKFBgwZpwYIFuvnmm93T161bp48//ljz5s1TdHS070EBAACUgtrJ/9BwAgDAz+TmSt9+K6Wnl289u13KywtSaGjFiqZataTu3ctXOLVq1Urjx4/Xiy++qEsvvVTNmjVTTk6OHnroIZ1//vnq16+f7wEBAACUgtrJP9FwAgDAz+TnOwumsDApPNz79ex2Z8EVFuZ70ZST43zs/Pzyf1M3btw4rV69WjNmzNCCBQv04osv6siRI1q6dKkOHjyoJ598Ul9++aWysrLUsWNHTZs2TR06dHCv/9lnn2nevHnauXOngoODdcopp+jWW2/VOeec41syAACgRqB28s/aiYYTAAB+Kjxciojwfnm7XQoKqljRJDkLL1+EhYXpwQcf1KhRo/T8889rwYIFuuOOOxQZGanLL79cUVFR+s9//qOYmBgtXbpUY8aM0SeffKI6depo7969uvXWW3XxxRdr8uTJys7O1q5du5SSkuJ7IgAAoEahdvKv2omGEwAAME337t11xRVX6LnnnlP79u01atQozZs3T6mpqVq5cqXq1KkjSerZs6cuvPBCLVy4UFOmTNGWLVuUl5en//znP4qMjFR2drb69u2r4IpUfwAAAH7OyrUTV6kDAACmGjdunCTp2muvVXBwsNavX68ePXooLi5O+fn5ys/PV1BQkM4880z98ssvkqSkpCQFBwfrzjvv1P/93/8pLS2tOlMAAACoMlatnRjhBAAATBUaGurx8/jx49q0aZPat29fZNnmzZtLklq2bKkXX3xR8+fP16RJk2Sz2XT22Wdr+vTpaty4cdUFDwAAUMWsWjvRcAIAAJUqLi5OZ599tm699dYi88IKnF2zT58+6tOnj1JSUvT555/r6aef1rRp07RkyZKqDBcAAKBaWaV2ouEEAAAqVa9evfT++++rdevWioqKKnP5WrVq6YIL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zbr55pvNjAcAAMCSqJ0AAEBN4tMIp9GjR+vrr78ucf4333yj0aNH+xwUAACAlVA7AQCAmsanhtO3336rI0eOlDj/2LFj+u6773wOCgAAwEqonQAAQE3jU8NJOnllleLs2bNH0dHRvm4aAADAcqidAABATeL1OZxWrVqlVatWue+/8MILevPNN4ssl5aWpj/++EN9+vQxJ0IAAIAARO0EAABqMq8bTllZWTp+/Lj7fkZGhoKCig6QioqK0rBhwzRx4kRzIgQAAAhA1E4AAKAm87rhNHz4cA0fPlyS1LdvX9177706//zzKy0wAACAQEbtBAAAajKvG04Fff7552bHAQAAYFnUTgAAoKbxqeFUUHp6utLT0+VwOIrMa9y4cUU3DwAAYCnUTgAAoCbwueH0xhtvaPHixdq3b1+Jy2zdutXXzQMAAFgKtRMAAKhJip650gvLli3Tgw8+qObNm+u2226TYRgaM2aMxo0bp7p166pt27Z65JFHzI4VAAAgIFE7AQCAmsanhtNrr72ms846SwsWLNCQIUMkSeecc44mT56sDz/8UBkZGTpx4oSZcQIAAAQsaicAAFDT+NRw2rt3r8477zxJUmhoqCQpLy9PkhQTE6OrrrpKb7zxhkkhAgAABDZqJwAAUNP41HCKiYmR3W6XJNWqVUuRkZE6ePCge350dLSOHDliToQAAAABjtoJAADUND41nE499VT9/vvv7vunn366li1bpuTkZP39999asWKFWrRoYVaMAAAAAY3aCQAA1DQ+NZwuu+wybdu2Tbm5uZKkW265RTt27NC5556rvn37ateuXbrtttt8CmjHjh269tprdcYZZ6h3796aNWuW+3HKkpycrLvvvlv/+te/1KlTJw0cOFDvv/++T3EAAACYhdoJAADUNCG+rHTllVfqyiuvdN/v2rWr/vvf/+rzzz9XcHCwevfurZYtW5Z7uykpKRozZoxatGihOXPmKDk5WTNnzlR2dramT59e6rqHDh3S0KFD1bJlSz300EOqVauWR2EHAABQXaidAABATeNTw6k4zZo105gxY9z39+3bp2bNmpVrG8uXL1dGRobmzp2r+Ph4SZLdbteMGTM0fvx4NWjQoMR1n3jiCTVs2FALFixQcHCwJKlnz57lTwQAAKAKUDsBAAAr8+mQutL8/vvvuuOOOzRw4MByr7tu3Tr17NnTXTBJ0sCBA+VwOLR+/foS10tPT9dHH32k4cOHuwsmAACAQEDtBAAArKhcI5y2bdumZcuWae/evYqLi9OAAQPUv39/SdJvv/2mZ599Vl999ZVCQkJ06aWXljuYnTt3egw3l6TY2FjVq1dPO3fuLHG93377TXl5eQoJCdHIkSP1008/KT4+XoMHD9Ztt93mvvwwAABAVaJ2AgAANZXXDadNmzZpzJgxysnJcU/78MMPNXXqVNntdj355JOKjo7W9ddfr9GjR6t+/frlDiY1NVWxsbFFpsfFxSklJaXE9VyXEb7vvvs0ZMgQ/fvf/9bmzZs1e/ZsBQUF6Y477ih3LJJkGIYyMzN9Wrc0WVlZHj8DXaDnE+jxF2aVfKySh4tV8rFKHi7k458qMw/DMGSz2UzfbnGoncxjlfe2S6DnE+jxF2aVfKySh4tV8rFKHi7k45/8tXbyuuE0b948hYeHa+7cuerWrZv279+vadOmafbs2crJydHYsWN10003KSYmxqdAKsLhcEiSevXqpalTp0qS/vWvfykjI0OLFi3SxIkTFRERUe7t5uXlaevWrabGWtDu3bsrbdvVIdDzCfT4C7NKPlbJw8Uq+VglDxfy8U+VlUdYWFilbLcwaifzWeW97RLo+QR6/IVZJR+r5OFilXyskocL+fgnf6udvG44bd68WcOHD9fZZ58tSTr11FM1depUjRw5Utdee62mTJniUwAFxcbGKi0trcj0lJQUxcXFlbqe5CyUCurZs6defPFF7dmzR0lJSeWOJzQ0VG3atCn3emXJysrS7t271aJFC0VGRpq+/aoW6PkEevyFWSUfq+ThYpV8rJKHC/n4p8rMY/v27aZurzTUTuaxynvbJdDzCfT4C7NKPlbJw8Uq+VglDxfy8U/+Wjt53XBKTU1VixYtPKa5Lt9buFjxVatWrYqcbyAtLU2HDx9Wq1atSlyvrMKm4FD28rDZbIqKivJpXW9ERkZW6varWqDnE+jxF2aVfKySh4tV8rFKHi7k458qI4+qOpxOonaqDFZ5b7sEej6BHn9hVsnHKnm4WCUfq+ThQj7+yd9qJ6+vUmcYRpGrmAQFOVc3a2h6nz59tGHDBqWmprqnrVmzRkFBQerdu3eJ6zVp0kSJiYnasGGDx/QNGzYoIiKiUr5pAwAAKA21EwAAqMnKdZW6L774wn2SSck5bMtms2nNmjX6/fffPZa12WwaO3ZsuYIZNmyYli5dqokTJ2r8+PFKTk7WrFmzNGzYMDVo0MC93JgxY3TgwAGtXbvWPW3y5Mm6+eab9cgjj+jcc8/VL7/8okWLFun666+3RKcSAAAEHmonAABQU5Wr4bR69WqtXr26yPQVK1YUmeZL0RQXF6clS5booYce0sSJExUdHa2rrrpKkydP9ljO4XDIbrd7TOvbt6+efvppPf/881q2bJnq16+vW265RePGjStXDAAAAGahdgIAADWV1w2nzz77rDLjcGvdurUWL15c6jJLly4tdvpFF12kiy66qBKiAgAAKB9qJwAAUJN53XBq0qRJZcYBAABgKdROAACgJvP6pOEAAAAAAACAN2g4AQAAAAAAwFQ0nAAAAAAAAGAqGk4AAAAAAAAwFQ0nAAAAAAAAmIqGEwAAAAAAAEwV4stKc+fOLXW+zWZTeHi4GjZsqDPPPFMNGjTwKTgAAAAroHYCAAA1jc8NJ5vNJkkyDMNjXuHpwcHBuvrqqzV9+nQFBTGgCgAA1DzUTgAAoKbxqeH0xRdfaPz48WrXrp1GjRql5s2bS5L27Nmj1157TX/88YeeeeYZZWZmasmSJVqxYoXq16+vm2++2dTgAQAAAgG1EwAAqGl8+tpsxowZatWqlR577DGddtppqlWrlmrVqqX27dvrscce0ymnnKKnnnpK7dq108yZM3XWWWfpvffeMzt2AACAgEDtBAAAahqfGk7ffPONzjzzzBLnn3nmmVq/fr37/jnnnKMDBw748lAAAAABj9oJAADUND41nMLCwrR58+YS5//8888KDQ1138/Pz1dUVJQvDwUAABDwqJ0AAEBN49M5nC655BK9/vrrio+P1zXXXKOmTZtKkvbv36833nhD77//vkaMGOFefuPGjWrTpo05EQMAAAQYaicAAFDT+NRwuuuuu3TkyBG98sorWrx4sfsKKg6HQ4Zh6IILLtBdd90lScrJyVH79u3VpUsX86IGAAAIINROAACgpvGp4RQeHq5nn31WW7Zs0Zdffqm//vpLktSkSROdddZZat++vcey//73v82JFgAAIABROwEAgJrGp4aTy2mnnabTTjvNrFgAAAAsjdoJAADUFBVqOElSRkaGUlNTZRhGkXmNGzeu6OYBAAAshdoJAADUBD41nHJycjR37ly99dZbOnHiRInLbd261de4AAAALIPaCQAA1DQ+NZweeOABvfvuu+rXr5+6du2quLg4s+MCAACwDGonAABQ0/jUcFq7dq2uvvpqPfjgg2bHAwAAYDnUTgAAoKYJ8mUlm83GCS8BAAC8RO0EAABqGp8aTueff742bNhgdiwAAACWRO0EAABqGp8aTjfffLP279+v//znP/r111917NgxnThxosgNAAAA1E4AAKDm8ekcThdccIEkacuWLXrrrbdKXI4rrQAAAFA7AQCAmsenhtPEiRNls9nMjgUAAMCSqJ0AAEBN41PD6ZZbbjE7DgAAAMuidgIAADWNT+dwAgAAAAAAAEri1QinuXPnymaz6aabblJQUJDmzp1b5jo2m00TJ06scIAAAACBhtoJAADUdOVqON14440KCwujaAIAACgFtRMAAKjpvGo4/f7776XeBwAAwEnUTgAAoKbjHE4AAAAAAAAwlU9XqStOVlaW/vvf/yo3N1fnnHOOmjRpYtamAQAALIfaCQAAWJlPDad77rlHmzdv1urVqyVJubm5GjJkiLZt2yZJiomJ0ZIlS3TaaaeZFykAAECAonYCAAA1jU+H1G3cuFH9+/d331+9erW2bdumJ598UqtXr1bdunW9OjkmAABATUDtBAAAahqfGk5HjhzxGPb96aefqkOHDrrkkkvUpk0bDRkyRJs3bzYtSAAAgEBG7QQAAGoanxpOkZGRSktLkyTl5+fr22+/1VlnneWeHx0d7Z4PAABQ01E7AQCAmsanczi1b99eb775pnr06KHPP/9cGRkZ6tu3r3v+3r17VadOHdOCBAAACGTUTgAAoKbxqeF022236YYbbtCVV14pwzB04YUXqlOnTu75a9euVZcuXUwLEgAAIJBROwEAgJrGp4ZTx44d9dFHH+nHH39UbGysunfv7p6Xmpqq4cOHe0wDAACoyaidAABATeNTw0mSEhIS1K9fvyLTY2NjNWbMmAoFBQAAYDXUTgAAoCbxqeF04MABHThwQN26dXNP+/3337Vo0SLl5ubqkksuKbagAgAAqImonQAAQE3jU8Pp4YcfVmZmphYvXizJeanf0aNHKy8vT9HR0fr444/13HPP6YILLjAzVgAAgIBE7QQAAGqaIF9W2rx5s3r16uW+/+677yo7O1vvvfee1q1bp549e2rRokWmBQkAABDIqJ0AAEBN41PDKSUlxePSvf/73/905plnqnnz5goKClL//v21c+dO04IEAAAIZNROAACgpvGp4ZSQkKADBw5Icl5ZZdOmTTr77LPd8+12u/Lz882JEAAAIMBROwEAgJrGp3M49erVS0uXLlWtWrW0ceNGGYah888/3z1/+/btatSokWlBAgAABDJqJwAAUNP41HC64447tGvXLj3++OMKDQ3VlClT1KxZM0lSbm6uPvroI1166aWmBgoAABCoqJ0AAEBN41PDqW7dulq+fLnS0tIUHh6usLAw9zyHw6ElS5aoYcOGpgUJAAAQyKidAABATeNTw8klJiamyLSIiAi1bdu2IpsFAACwJGonAABQU1So4XTw4EFt2bJFaWlpMgyjyPzBgwdXZPMAAACWQu0EAABqCp8aTjk5Obr77rv1ySefyOFwyGazuYsmm83mXo6iCQAAgNoJAADUPEG+rPT0009r7dq1uu2227R06VIZhqGZM2dq0aJF6tOnj9q2bav33nvP7FgBAAACErUTAACoaXxqOH388ce64oorNG7cOLVp00aS1KBBA/Xq1Uvz589XTEyMXn/9dVMDBQAACFTUTgAAoKbxqeF09OhRderUSZLzRJeSlJWV5Z5/4YUXau3atSaEBwAAEPionQAAQE3jU8Opbt26On78uCQpMjJScXFx2rVrl3t+enq6cnJyzIkQAAAgwFE7AQCAmsank4Z36tRJP/74o/v+eeedp4ULF6pevXpyOBxavHixzjjjDLNiBAAACGjUTgAAoKbxqeE0atQorVmzRrm5uQoLC9Ott96qn376SVOmTJEkNW/eXPfee6+pgQIAAAQqaicAAFDT+NRw6tatm7p16+a+36hRI3300Uf6888/FRQUpFatWikkxKdNAwAAWA61EwAAqGnKVdl8+eWXWrJkifbv36/atWtrwIABGjNmjCQpKChIbdu2rZQgAQAAAhG1EwAAqKm8bjh9++23GjdunAzDUO3atbVv3z5t2rRJycnJ7uHgAAAAcKJ2AgAANZnXV6mbP3++6tSpo/fff19ff/21NmzYoB49euiNN95QdnZ2ZcYIAAAQcKidAABATeZ1w+nPP//U8OHDlZiYKEmKi4vT7bffruzsbG3btq3SAgQAAAhE1E4AAKAm87rhdOTIETVt2tRjmut+RkaGuVEBAAAEOGonAABQk3ndcDIMQzabzWOa675hGOZGBQAA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t+uLL77Q3r179eijjyomJkZ2u13BwcHVHZ7X0tPTdeWVV6pWrVqKj4+v7nAqLCMjQ1dddZXq1Kmjiy++WA0bNqzukHySnp6uSy+9VDabTeHh4fr666+VlJQUcO8vl/T0dI0bN05HjhzRgQMHVK9ePd16660aPHhwwO04paen67bbblNycrIOHjyorl276rLLLtNFF11U3aGVW3p6um6++WYdP35cf/31lzp37qxBgwbpsssuq+7QUE2onfwLtZN/onbyT9RO/ovaqXwY4RQAsrOzNWLECD377LN64403tHPnzuoOqUIyMjI0bNgwHThwQL169dIVV1yhDRs26Pnnn9e+ffuqO7wyZWRkaMiQIcrOzta4ceN07733Kj8/X8uWLVN6enp1h+eT/Px8RUVFqXHjxkpOTtadd94ZcN/Wpaen67LLLlOjRo30/PPPq06dOtUdUoUYhqEnn3xSDRo00KxZs9SvXz+FhYVVd1jllp6erkGDBqlFixb64IMPdN5552nRokXu91egyc7O1ujRoxUWFqaHHnpIzz33nDp37qxFixYpOTm5usMrl+zsbF1zzTXKysrSiBEjdNNNNyklJUW33367nnvuOaWlpVV3iF7Lzc3V6NGjJUk33XST7rjjDkVERGjKlCnu0QeoWaid/Au1k3+idvJP1E7+i9qp/Bjh5OccDodeeuklpaWl6ZJLLtHKlSuVnZ2tCRMmqHXr1tUdXrnl5+frgQceUEJCgh599FE1adJEktS6dWs98MAD2rVrl5o1a1bNUZYsNzdXd911lzt+V6w5OTl66aWXqjk634WGhqp3797au3ev+vTpo3feeUd33nmnnnjiCcXExMjhcCgoyNmfNgzD776JyMrK0jXXXKNatWrphRdeUEREhCQpOTlZKSkpMgxDtWvXVv369as5Uu/ZbDbt27dPXbt2VYMGDRQcHKwffvhBGzZsUHZ2ttq1a6eLL77Y716LgtLS0twF06OPPqro6GgNGjRIX375pV5//XXdeOON7vdVoPjkk0+Ul5ene++9V6eeeqok5+f/66+/VmhoaDVHVz6ffPKJcnJy9MADD7hz6dWrl1544QW98MILysvL07hx4xQbG+uXn/uCfv31V2VkZOiBBx5Qp06dJEkXXHCBevTooVmzZik1NVVTpkxRTExMNUeKqkDt5F+onaidqgq1k3+idvJP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++23eu655/THH39owYIFmj59up588slq/eNZUh4XXXSROnTooKuvvlpdunRxHy5R8D1mt9uVkJCgyMjIaou/sOLyGTFihAYOHKgOHTpoxowZCg4O1scff6ylS5fqpptucp/DIycnR9HR0YqNja3mLMr/ee/Xr5+6d++uuXPnqlu3bn53ZZyy3mdnn3228vPzlZmZWeT5z8nJUe3atVW7du1qit5Tcblcc801uuKKK3TaaafppZde0pw5c/Tzzz8rJydHo0eP1sSJEyVJKSkpio6OVkiIf5QLGRkZmjRpki6//HJdcsklHsO7ExISdPfdd+v+++/XmDFj9Pzzz+vUU091L1OvXj3VrVs3YK4eBe9QO1E7VSZqJ2qnykTtdBK1U+Wp7trJP54FKC8vTxMnTlRcXJwefPBBORwObdq0SU8//bS2bt2qkSNH6vzzz/foSgYFBWnQoEE6duyYHn/8ccXExGjlypXF/hP353zsdruCg4NVv3595efn69ChQ3r22Wf10Ucf6bXXXquW8yx4G78kdyHrKiSOHTumDz/8UAkJCapXr16Vx14cb/Pp1auXEhISdO655yooKEhPPfWUzj77bJ111lkKCwvTeeedV60FU1l5DB8+XP3793e/Z/Ly8twnKDx27Ji+++47tWnTxm+KptLy+e233zR69Gj3ORYMw9Bbb72lvLw8XX311bLZbHrrrbeUkZGhHj16+G0exf39stlsCg8PV9++ffXcc89p06ZN7s+TP/A2n5CQEDVs2FAvvfSSzj77bDVt2lTHjh3Tq6++Kknq2rVrNWdSei5btmzR2LFjdd555+nBBx9URkaG7Ha7uwg8duyYtmzZopYtWyo/P1/BwcHVel6FnJwc3Xzzzdq4caP27t2rkJAQDRgwwOP/yBlnnKH7779fjz/+uMaMGaNJkyape/fuCgsL06pVqxQaGqqEhIRqywHmonaidqpM1E7UTtWVB7VT9aJ2Mrl28vlgPJjq2LFjxoABA4xVq1Z5TP/222+Niy66yBg6dKixdu1aj3kOh8PYs2ePMXnyZKNbt24ex5FWN1/y+eSTT4zu3bsbt9xyi9GxY0fjt99+q8KIPfkSv2E4j9+dNm2a0b17d+PPP/+somjL5k0+n3zyiWEYhjF79mxj5MiRxpdfflnkON/q5uvrsnnzZmPatGlG165dA+p1GTJkiMc5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6znXe1yf34ulh6XDYulh6bCYetQizNjWhOs9rs/vxdLD0mGx9LB0WEw9anGTLhreBfs+ywsvvBBbtmzBu+++iw0bNiA3NzfOk/WO6z2uz+/F0sPSYbH0sHRYTD1qEWZsa8L1Htfn92LpYemwWHpYOiymHrU4yki3vPPOO+aaa64xhw4divcovnC9x/X5vVh6WDoslh6WDoupRy3CjG1NuN7j+vxeLD0sHRZLD0uHxdSjFrckGEN0CfQ+1tLSgoEDB8Z7DN+43uP6/F4sPSwdFksPS4fF1KMWYca2JlzvcX1+L5Yelg6LpYelw2LqUYs7dOAkIiIiIiIiIiK+0kXDRURERERERETEVzpwEhERERERERERX+nASUREREREREREfKUDJxERERERERER8ZUOnERERERERERExFc6cBIREREREREREV/pwElERERERERERHyVHO8BREQ+jc2bN2PRokWxXw8YMABDhw5FTk4ObrjhBhQWFiIjI6PH3/cf//gH9u3bh29/+9sYMmSInyOLiIiIxI32TiLSX3TgJCIUfvjDHyIrKwttbW04duwY3njjDSxbtgzPPvssnnjiCYwePbpH3++tt97C6tWrUVBQoE2TiIiI0NHeSUT6mg6cRITC9ddfjyuuuCL263nz5qG0tBT33HMP5s+fjxdffBEDBw6M44QiIiIiwaG9k4j0NV3DSURoXXPNNZg/fz5qa2uxfft2AMB7772HhQsXYsqUKbjiiiswefJkLFq0CMePH4993eOPP44VK1YAAKZMmYKcnBzk5OSgpqYm9pht27ahsLAQ48aNQ15eHn70ox/hww8/7N9AERERER9p7yQiftIrnESE2m233YZVq1bh9ddfR1FREf7617+iuroahYWFuOCCC3Dw4EGUlJTg0KFDKCkpQUJCAm666SZUVlbihRdewKJFi5CZmQkAOP/88wEAa9euxW9+8xtMmzYN06dPR319PdavX49Zs2Zh69atehm5iIiIOEt7JxHxiw6cRITa8OHDMXjwYFRXVwMAZs6ciTlz5nR4zJe+9CXcd999+Pvf/44JEyZg9OjRyM3NxQsvvID8/HxkZWXFHltbW4vHH38cxcXFuOeee2Ifnzp1KgoKCrBhw4YOHxcRERFxifZOIuIXvaVOROilp6ejubkZADpci6C1tRX19fW48sorAQDvvPNOl99r165diEajmDZtGurr62P/fPazn8XFF1+MsrKyvokQERER6SfaO4mIH/QKJxGhd/LkSXzmM58BAJw4cQKrV6/Giy++iLq6ug6PC4VCXX6vyspKGGMwderUs34+OVl/rIqIiIjbtHcSET/od7eIUDt8+DBCoRBGjhwJACguLsZbb72Fu+++G2PGjEF6ejqi0Si++93vwhjT5feLRqNISEjAU089haSkpE6fT09P971BREREpL9o7yQiftGBk4hQ27ZtGwDg2muvRUNDA0pLS/GDH/wA3//+92OPqays7PR1CQkJZ/1+I0eOhDEGWVlZyM7O7pOZRUREROJFeycR8Yuu4SQitEpLS/HEE08gKysL3/jGN876UzUAWLduXaePpaWlAej8UvGpU6ciKSkJq1ev7vRTPWNMh1sEi4iIiLhEeycR8ZNe4SQiFF599VW8//77iEQiOHbsGMrKyrBv3z5cdNFFWLt2LVJTU5GamoqJEyfi97//PU6fPo1hw4Zh3759qKmp6fT9xo4dCwD49a9/jZtvvhkpKSm48cYbMXLkSBQXF2PlypWora1Ffn4+Bg0ahJqaGrz88ssoKirC3Xff3d/5IiIiIj2ivZOI9DUdOIkIhcceewwAkJKSgvPOOw+XX345HnzwQRQWFiIjIyP2uJUrV2Lp0qXYsGEDjDGYPHkynnrqKVx33XUdvt+4ceOwYMECbNy4Ea+99hqi0SheeeUVpKenY+7cufjCF76AZ599FmvWrAFw5hbCkydPxte+9rX+ixYRERHpJe2dRKSvJZjuXOlNRERERERERESkm3QNJxERERERERER8ZUOnERERERERERExFc6cBIREREREREREV/pwElERERERERERHylAycREREREREREfGVDpxERERERERERMRXOnASERERERERERFf6cBJRERERERERER8pQMnERERERERERHxlQ6cRERERERERETEVzpwEhERERERERERX+nASUREREREREREfKUDJxERERERERER8dX/AW4CpkRofkppAAAAAElFTkSuQmCC\n" | |
}, | |
"metadata": {} | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# Before / after comparisons" | |
], | |
"metadata": { | |
"id": "QvyFgvmUH9tx" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get the localized site origins.\n", | |
"localized_sites = get_localized_sites('2024-09-01')\n", | |
"count_localized_sites = localized_sites.count()\n", | |
"print(count_localized_sites)" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "KxXviXQXKOgM", | |
"outputId": "a0abcc31-2cce-4a4c-df39-29c87bee22c1" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"origin 3475800\n", | |
"dtype: int64\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get the non-localized site origins.\n", | |
"non_localized_sites = get_non_localized_sites('2024-09-01')\n", | |
"count_non_localized_sites = non_localized_sites.count()\n", | |
"print(count_non_localized_sites)" | |
], | |
"metadata": { | |
"id": "pdF3nqoXIBBG", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "df0151d9-c50a-490c-ca3f-d355fce17051" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"origin 2143546\n", | |
"dtype: int64\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get the CWV changes for localized sites\n", | |
"#@markdown This shows how much each metric has changed for localized sites between the before and after dates. Metrics in order:\n", | |
"#@markdown * pct_eligible_origins_with_good_cwv_change\n", | |
"#@markdown * pct_eligible_origins_with_good_lcp_change\n", | |
"#@markdown * pct_eligible_origins_with_good_cls_change\n", | |
"#@markdown * pct_eligible_origins_with_good_inp_change\n", | |
"#@markdown * pct_eligible_origins_with_good_ttfb_change\n", | |
"cwv_changes_localized_sites = get_cwv_change_before_after(localized_sites, '2024-01-01', '2024-09-01' )\n", | |
"print(cwv_changes_localized_sites)" | |
], | |
"metadata": { | |
"id": "OOGavQ78JRZ9", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "9df694bd-20ec-4528-d81d-168645c62857" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Dataset wpp-research.temp_dataset already exists.\n", | |
"[0.04945737967421521, 0.033642347609904144, 0.021581152887447885, 0.07416415274440302, -0.003210042653351619]\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get the CWV changes for non_localized sites\n", | |
"#@markdown This shows how much each metric has changed for non-localized sites between the before and after dates.\n", | |
"#@markdown * pct_eligible_origins_with_good_cwv_change\n", | |
"#@markdown * pct_eligible_origins_with_good_lcp_change\n", | |
"#@markdown * pct_eligible_origins_with_good_cls_change\n", | |
"#@markdown * pct_eligible_origins_with_good_inp_change\n", | |
"#@markdown * pct_eligible_origins_with_good_ttfb_change\n", | |
"cwv_changes_non_localized_sites = get_cwv_change_before_after(non_localized_sites, '2024-02-01', '2024-07-01' )\n", | |
"print(cwv_changes_non_localized_sites)" | |
], | |
"metadata": { | |
"id": "SNnFoTNYJebT", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "717c8357-1f64-458c-ea64-a26a8cc735bf" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Dataset wpp-research.temp_dataset already exists.\n", | |
"[0.03785168110090148, 0.03379085700032103, 0.021574287521065383, 0.03713313843194688, 0.000680431590357411]\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get the difference between localized and non-localized sites\n", | |
"#@markdown This step calculates the difference in changes for each metric between the localized and non-localized sites.\n", | |
"final_results = calculate_feature_impact(cwv_changes_localized_sites, cwv_changes_non_localized_sites)\n", | |
"print(final_results)\n" | |
], | |
"metadata": { | |
"id": "M851TSUcKfbN", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "cd3fd24f-cc7f-479d-bf96-c991af7fdda9" | |
}, | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"{'pct_good_cwv_change': '1.16%', 'pct_good_lcp_change': '-0.01%', 'pct_good_cls_change': '0.00%', 'pct_good_inp_change': '3.70%', 'pct_good_ttfb_change': '-0.39%'}\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# Helpers" | |
], | |
"metadata": { | |
"id": "m9CDTSoUGvfR" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get sites at `after_date` with localization.\n", | |
"from google.cloud import bigquery\n", | |
"import pandas as pd\n", | |
"\n", | |
"\n", | |
"# Get sites with the localization on a specific date\n", | |
"def get_localized_sites(after_date):\n", | |
" client = bigquery.Client(project=project_id)\n", | |
" # 1. Identify localized Sites\n", | |
" localized_sites_query = f\"\"\"\n", | |
" CREATE TEMP FUNCTION\n", | |
" IS_LOCALIZED(lang STRING)\n", | |
" RETURNS BOOL AS ( lang IS NOT NULL\n", | |
" AND lang != \"en\"\n", | |
" AND lang != \"en-us\" );\n", | |
" SELECT\n", | |
" DISTINCT page AS origin\n", | |
" FROM\n", | |
" `httparchive.all.pages`,\n", | |
" UNNEST(technologies) AS technologies\n", | |
" WHERE\n", | |
" technologies.technology = 'WordPress'\n", | |
" AND date = PARSE_DATE('%Y-%m-%d', '{after_date}' )\n", | |
" AND is_root_page = TRUE\n", | |
" AND client = 'mobile'\n", | |
" AND IS_LOCALIZED(REPLACE(TRIM(LOWER(JSON_VALUE(JSON_VALUE(payload, '$._almanac'), '$.html_node.lang'))), '_', '-' )) = TRUE\n", | |
" \"\"\"\n", | |
"\n", | |
" localized_sites_df = client.query(localized_sites_query).to_dataframe()\n", | |
" return localized_sites_df" | |
], | |
"metadata": { | |
"id": "ntnEK4tkv7Y1" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get sites at `after_date` without localization.\n", | |
"from google.cloud import bigquery\n", | |
"import pandas as pd\n", | |
"\n", | |
"\n", | |
"# Get sites with the localization on a specific date\n", | |
"def get_non_localized_sites(after_date):\n", | |
" client = bigquery.Client(project=project_id)\n", | |
" # 1. Identify localized Sites\n", | |
" localized_sites_query = f\"\"\"\n", | |
" CREATE TEMP FUNCTION\n", | |
" IS_LOCALIZED(lang STRING)\n", | |
" RETURNS BOOL AS ( lang IS NOT NULL\n", | |
" AND lang != \"en\"\n", | |
" AND lang != \"en-us\" );\n", | |
" SELECT\n", | |
" DISTINCT page AS origin\n", | |
" FROM\n", | |
" `httparchive.all.pages`,\n", | |
" UNNEST(technologies) AS technologies\n", | |
" WHERE\n", | |
" technologies.technology = 'WordPress'\n", | |
" AND date = PARSE_DATE('%Y-%m-%d', '{after_date}' )\n", | |
" AND is_root_page = TRUE\n", | |
" AND client = 'mobile'\n", | |
" AND IS_LOCALIZED(REPLACE(TRIM(LOWER(JSON_VALUE(JSON_VALUE(payload, '$._almanac'), '$.html_node.lang'))), '_', '-' )) = FALSE\n", | |
" \"\"\"\n", | |
"\n", | |
" localized_sites_df = client.query(localized_sites_query).to_dataframe()\n", | |
" return localized_sites_df" | |
], | |
"metadata": { | |
"id": "CiJADzDJIujD" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Get CWV changes for a set of sites between before and after dates\n", | |
"#@markdown\n", | |
"#@markdown Note: sites_df is a dataframe with an origin column containing the URLs.\n", | |
"#@markdown\n", | |
"#@markdown Returns:\n", | |
"#@markdown * pct_eligible_origins_with_good_cwv_change\n", | |
"#@markdown * pct_eligible_origins_with_good_lcp_change\n", | |
"#@markdown * pct_eligible_origins_with_good_cls_change\n", | |
"#@markdown * pct_eligible_origins_with_good_inp_change\n", | |
"#@markdown * pct_eligible_origins_with_good_ttfb_change\n", | |
"#@markdown\n", | |
"\n", | |
"\n", | |
"from google.cloud.exceptions import NotFound\n", | |
"\n", | |
"import pdb\n", | |
"# Get the CWV change before/after for sites\n", | |
"def get_cwv_change_before_after(sites_df, before_date, after_date):\n", | |
" client = bigquery.Client(project=project_id)\n", | |
" # 0. Ensure the 'temp_dataset' dataset exists, or create it\n", | |
" dataset_id = f\"{project_id}.temp_dataset\"\n", | |
" try:\n", | |
" client.get_dataset(dataset_id) # Check if dataset exists\n", | |
" print(f\"Dataset {dataset_id} already exists.\")\n", | |
" except NotFound:\n", | |
" print(f\"Creating dataset {dataset_id}...\")\n", | |
" dataset = bigquery.Dataset(dataset_id)\n", | |
" dataset.location = \"US\" # Set the location (adjust if needed)\n", | |
" client.create_dataset(dataset)\n", | |
"\n", | |
" # 1. Create a temporary table with the list of origins\n", | |
" schema = [bigquery.SchemaField(\"origin\", \"STRING\")]\n", | |
" job_config = bigquery.LoadJobConfig(schema=schema)\n", | |
" job = client.load_table_from_dataframe(sites_df, f\"{project_id}.temp_dataset.origins\", job_config=job_config)\n", | |
" job.result() # Wait for the job to complete\n", | |
"\n", | |
"\n", | |
" # 2. Collect CWV Data and Calculate Baselines\n", | |
" cwv_query = f\"\"\"\n", | |
" CREATE TEMP FUNCTION IS_GOOD(good FLOAT64, needs_improvement FLOAT64, poor FLOAT64)\n", | |
" RETURNS BOOL\n", | |
" AS (\n", | |
" good / (good + needs_improvement + poor) >= 0.75\n", | |
" );\n", | |
"\n", | |
" CREATE TEMP FUNCTION IS_NON_ZERO(good FLOAT64, needs_improvement FLOAT64, poor FLOAT64)\n", | |
" RETURNS BOOL\n", | |
" AS (\n", | |
" good + needs_improvement + poor > 0\n", | |
" );\n", | |
"\n", | |
"\n", | |
" SELECT\n", | |
" date,\n", | |
" COUNT(DISTINCT origin) AS origins,\n", | |
" SAFE_DIVIDE(COUNTIF(good_cwv), COUNTIF(any_lcp AND any_cls)) AS pct_eligible_origins_with_good_cwv,\n", | |
" SAFE_DIVIDE(COUNTIF(good_lcp), COUNTIF(any_lcp)) AS pct_eligible_origins_with_good_lcp,\n", | |
" SAFE_DIVIDE(COUNTIF(good_cls), COUNTIF(any_cls)) AS pct_eligible_origins_with_good_cls,\n", | |
" SAFE_DIVIDE(COUNTIF(good_inp), COUNTIF(any_inp)) AS pct_eligible_origins_with_good_inp,\n", | |
" SAFE_DIVIDE(COUNTIF(good_ttfb), COUNTIF(any_ttfb)) AS pct_eligible_origins_with_good_ttfb\n", | |
" FROM\n", | |
" (\n", | |
" SELECT\n", | |
" date AS date,\n", | |
" origin,\n", | |
" # Device phone or tablet as mobile, otherwise desktop.\n", | |
" IF(device = 'phone' OR device = 'tablet', 'mobile', device) AS device,\n", | |
" IS_NON_ZERO(fast_ttfb, avg_ttfb, slow_ttfb) AS any_ttfb,\n", | |
" IS_GOOD(fast_ttfb, avg_ttfb, slow_ttfb) AS good_ttfb,\n", | |
" IS_NON_ZERO(fast_inp, avg_inp, slow_inp) AS any_inp,\n", | |
" IS_GOOD(fast_inp, avg_inp, slow_inp) AS good_inp,\n", | |
" IS_NON_ZERO(small_cls, medium_cls, large_cls) AS any_cls,\n", | |
" IS_GOOD(small_cls, medium_cls, large_cls) AS good_cls,\n", | |
" IS_NON_ZERO(fast_lcp, avg_lcp, slow_lcp) AS any_lcp,\n", | |
" IS_GOOD(fast_lcp, avg_lcp, slow_lcp) AS good_lcp,\n", | |
" (IS_GOOD(fast_inp, avg_inp, slow_inp) OR fast_inp IS NULL) AND IS_GOOD(small_cls, medium_cls, large_cls) AND IS_GOOD(fast_lcp, avg_lcp, slow_lcp) AS good_cwv\n", | |
" FROM\n", | |
" `chrome-ux-report.materialized.device_summary` AS cwvs\n", | |
" WHERE\n", | |
" (\n", | |
" date = PARSE_DATE('%Y-%m-%d', '{before_date}') OR\n", | |
" date = PARSE_DATE('%Y-%m-%d', '{after_date}' )\n", | |
" )\n", | |
" AND cwvs.device IN ('desktop', 'tablet', 'phone')\n", | |
" # Restrict to sites that are in both dates\n", | |
" AND CONCAT(cwvs.origin, '/') IN (SELECT origin FROM `{project_id}.temp_dataset.origins`)\n", | |
"\n", | |
" )\n", | |
" GROUP BY\n", | |
" date\n", | |
" ORDER BY\n", | |
" date\n", | |
" \"\"\"\n", | |
"\n", | |
" cwv_data = client.query(cwv_query).to_dataframe()\n", | |
"\n", | |
" # select the data from the after_date (by date column)\n", | |
" cwv_after = cwv_data[cwv_data['date'] == pd.to_datetime(after_date)]\n", | |
" cwv_before = cwv_data[cwv_data['date'] == pd.to_datetime(before_date)]\n", | |
"\n", | |
" # subtract the 'pct_eligible_origins_with_good_cwv' value at cwv_before from cwv_after\n", | |
" pct_eligible_origins_with_good_cwv_change = cwv_after['pct_eligible_origins_with_good_cwv'].values[0] - cwv_before['pct_eligible_origins_with_good_cwv'].values[0]\n", | |
" pct_eligible_origins_with_good_lcp_change = cwv_after['pct_eligible_origins_with_good_lcp'].values[0] - cwv_before['pct_eligible_origins_with_good_lcp'].values[0]\n", | |
" pct_eligible_origins_with_good_cls_change = cwv_after['pct_eligible_origins_with_good_cls'].values[0] - cwv_before['pct_eligible_origins_with_good_cls'].values[0]\n", | |
" pct_eligible_origins_with_good_inp_change = cwv_after['pct_eligible_origins_with_good_inp'].values[0] - cwv_before['pct_eligible_origins_with_good_inp'].values[0]\n", | |
" pct_eligible_origins_with_good_ttfb_change = cwv_after['pct_eligible_origins_with_good_ttfb'].values[0] - cwv_before['pct_eligible_origins_with_good_ttfb'].values[0]\n", | |
"\n", | |
" # 3. Clean up: Delete the temporary table (optional but good practice)\n", | |
" client.delete_table(f\"{project_id}.temp_dataset.origins\")\n", | |
"\n", | |
" return [\n", | |
" pct_eligible_origins_with_good_cwv_change,\n", | |
" pct_eligible_origins_with_good_lcp_change,\n", | |
" pct_eligible_origins_with_good_cls_change,\n", | |
" pct_eligible_origins_with_good_inp_change,\n", | |
" pct_eligible_origins_with_good_ttfb_change\n", | |
" ]" | |
], | |
"metadata": { | |
"id": "WVcPDbM75Sz_" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Calculate impact minus baseline\n", | |
"\n", | |
"# calculate the impact by subracting the baseline from the change\n", | |
"def calculate_feature_impact(change, baseline):\n", | |
" cwv_change = change[0] - baseline[0]\n", | |
" lcp_change = change[1] - baseline[1]\n", | |
" cls_change = change[2] - baseline[2]\n", | |
" inp_change = change[3] - baseline[3]\n", | |
" ttfb_change = change[4] - baseline[4]\n", | |
" return {\n", | |
" 'pct_good_cwv_change': \"{:.2%}\".format(cwv_change),\n", | |
" 'pct_good_lcp_change': \"{:.2%}\".format(lcp_change),\n", | |
" 'pct_good_cls_change': \"{:.2%}\".format(cls_change),\n", | |
" 'pct_good_inp_change': \"{:.2%}\".format(inp_change),\n", | |
" 'pct_good_ttfb_change': \"{:.2%}\".format(ttfb_change)\n", | |
" }" | |
], | |
"metadata": { | |
"id": "gF8s3t5L6Vjg" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"#@markdown ## Measure feature performance impact minus baseline\n", | |
"def query_cwv_compare_feature_to_baseline(generator_tag, before_date, after_date):\n", | |
" active_sites = get_sites_with_feature_active(generator_tag, after_date)\n", | |
" count_active_sites = active_sites.count()\n", | |
" inactive_sites = get_sites_with_feature_inactive(generator_tag, after_date)\n", | |
" count_inactive_sites = inactive_sites.count()\n", | |
"\n", | |
" # Count feature active sites that were also feature active at the before date.\n", | |
" active_at_from_date = get_active_sites_also_active_at_before_date(generator_tag, before_date, active_sites)\n", | |
" count_active_at_from_date = active_at_from_date.count()\n", | |
"\n", | |
" # Calculate the percentage of count_active_at_from_date (which might be 0 so use safe divide)\n", | |
" if count_active_sites['origin'] > 0:\n", | |
" percent_of_active_sites_also_active_at_from_date = (count_active_at_from_date['origin'] / count_active_sites['origin']) * 100\n", | |
" else:\n", | |
" percent_of_active_sites_also_active_at_from_date = 0\n", | |
"\n", | |
" inactive_to_active_percent = 100 - percent_of_active_sites_also_active_at_from_date;\n", | |
"\n", | |
" # Calculate CWV change\n", | |
" cwv_changes_active_sites = get_cwv_change_before_after(active_sites, before_date, after_date )\n", | |
" cwv_changes_inactive_sites = get_cwv_change_before_after(inactive_sites, before_date, after_date )\n", | |
"\n", | |
" final_results = calculate_feature_impact(cwv_changes_active_sites, cwv_changes_inactive_sites)\n", | |
" final_results['feature_active_sites'] = count_active_sites['origin']\n", | |
" final_results['feature_inactive_sites'] = count_inactive_sites['origin']\n", | |
" final_results['inactive_to_active_percent'] = inactive_to_active_percent\n", | |
"\n", | |
" return final_results" | |
], | |
"metadata": { | |
"id": "JL0yN8uu76cq" | |
}, | |
"execution_count": null, | |
"outputs": [] | |
} | |
], | |
"metadata": { | |
"colab": { | |
"provenance": [], | |
"name": "Performant Translations Colab", | |
"collapsed_sections": [ | |
"4G2WkwMPzxbT" | |
], | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"display_name": "Python 3", | |
"name": "python3" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment