Skip to content

Latest commit

 

History

History
1325 lines (1209 loc) · 60.5 KB

kilde.org

File metadata and controls

1325 lines (1209 loc) · 60.5 KB

Bekledning av brukere fra hva vi vet

Innledning

NRK TV ønsker seg mer informasjon om brukerne våre basert på det vi vet. Dette har sitt utspring i at førsteparts data som vi får gjennom sporing med Snowplow ikke gir oss data på om det er flere som ser et innhold, slik TVOV-undersøkelsen gjør. Kan vi klare å inferere hvilket innhold som konsumeres av flere samtidig på samme skjerm? Det skal vi prøve å undersøke i dette dokumentet.

Kort oppsummert

Her kommer en oppsummering av funnene.

  1. I løpet av de siste tretti dagene er det ca. 1,35 millioner TV-klienter som som er logget på med kun én bruker. Circa 90 000 av klientene konsumerer kun barneprogrammer. Disse kan helt sikkert regnes som en del av en familie.
  2. I løpet av samme periode er det ca. 256 000 klienter hvor det konsumeres både barne- og voksenprogrammer.

Fremgangsmåte

Vi begrenser oss til å se på konsum på storskjerm fra påloggede brukere. Videre bruker vi innhold med en stor samseingsverdi som Maskorama, ESC og Kakemesterskapet til å filtrere ut brukere som muligens ser sammen med flere i familien. Deretter undersøker vi om disse brukerne har barneprofiler tilknyttet seg, og om klienten har blitt logget på av andre voksenbrukere. Deretter sjekker vi hvilket annet innhold som konsumeres av denne profilen, og om de andre profilene konsumerer noe innhold. Denne innsikten blir grunnlaget for å identifisere annet innhold som fungerer for samseing.

Del 1

Finner tidsperioden for Maskorama

#standardSQL
SELECT publishedDate, firstTransmissionDate, id, seriesTitleOrTitle
  FROM `nrk-datahub.metadata_views.metadata_programs`
 WHERE seriesTitleOrTitle LIKE '%askor%'
   AND EXTRACT(YEAR FROM publishedDate) = 2024
#standardSQL
SELECT COUNT(DISTINCT visitorId) `TV-klienter som har spilt av Maskorama` --partitionDate, content.id, nrkUserId, 
  FROM `nrk-datahub.snowplow_processed.playback_v02`
       JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
 WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
   AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
   AND platform = 'tv'
TV-klienter som har spilt av Maskorama
152006
#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT visitorId, COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY 1)

  SELECT COUNT(visitorId) `TV-klienter med to eller flere påloggede`
    FROM BRUKERE
   WHERE Voksne + Barn > 1
TV-klienter med to eller flere påloggede
29860

Nå ser vi på sammensetningen av barne- og voksenprofiler på klientene som har spilt av Maskorama.

#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'),

  BRUKERE AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY 1),

  BRUKERGRUPPERING AS (
    SELECT COUNT(visitorId) klienter,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
      FROM BRUKERE
     GROUP BY ALL)

  SELECT CASE
           WHEN voksnei = 0 THEN '0'
           WHEN voksnei = 1 THEN '1'
           WHEN voksnei = 2 THEN '2-3'
           ELSE '> 3'
         END voksne,
         CASE
           WHEN barni = 0 THEN '0'
           WHEN barni = 1 THEN '1-3'
           ELSE '> 3'
         END barn,
         klienter
    FROM BRUKERGRUPPERING
   ORDER BY voksnei, barni
voksnebarnklienter
01-3369
0> 31
10126943
11-326516
1> 3195
2-301839
2-31-31098
2-3> 374
> 3010
> 31-31

Her ser vi på antall menn, kvinner, voksne, gutter, jenter og barn og fordelingen av TV-klienter.

#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
SELECT visitorId,
       COUNT(DISTINCT IF(gender = 'M' AND userOrProfile = 'user', nrkUserId, NULL)) menn,
       COUNT(DISTINCT IF(gender = 'F' AND userOrProfile = 'user', nrkUserId, NULL)) kvinner,
       COUNT(DISTINCT IF(gender IS NULL OR gender = 'O' AND userOrProfile = 'user', nrkUserId, NULL)) voksne,
       COUNT(DISTINCT IF(gender = 'M' AND userOrProfile != 'user', nrkUserId, NULL)) gutter,
       COUNT(DISTINCT IF(gender = 'F' AND userOrProfile != 'user', nrkUserId, NULL)) jenter,
       COUNT(DISTINCT IF(gender IS NULL OR gender = 'O' AND userOrProfile != 'user', nrkUserId, NULL)) barn
  FROM `nrk-datahub.snowplow_processed.views_v02`
       JOIN KLIENTER USING(visitorId)
       JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
 WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
   AND platform = 'tv'
 GROUP BY ALL)

  SELECT menn, kvinner, gutter, jenter, voksne, barn, COUNT(visitorId) Klienter
    FROM BRUKERE
   GROUP BY ALL
 ORDER BY 1, 2, 3, 4, 5, 6

Nå skal vi se på hvor mye tid som brukes på konsum og hvordan det fordeler seg på de ulike profilene.

#standardSQL
WITH
  KLIENTER AS (
    SELECT DISTINCT visitorId
      FROM `nrk-datahub.snowplow_processed.playback_v02`
     WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
       AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
       AND platform = 'tv'),

  BRUKERE AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY 1),

  INNHOLD AS (
    SELECT visitorId, seriesTitleOrTitle, --nrkUserId, userOrProfile, 
           SUM(secondsConsumed) Konsum
      FROM BRUKERE
           JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(visitorId)
           JOIN `nrk-datahub.metadata_views.metadata_programs` ON content.id = id
           LEFT JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
       AND Voksne + Barn > 1
     GROUP BY ALL),

  TOTALT AS (
    SELECT visitorId, SUM(Konsum) / 3600 Tot_konsum_timer
      FROM INNHOLD
     GROUP BY ALL),
  
  RANGERING AS (
    SELECT visitorId, seriesTitleOrTitle,
           SAFE_DIVIDE(Konsum / 3600, Tot_konsum_timer) Andel_av_tot,
           Tot_konsum_timer,
           ROW_NUMBER() OVER(PARTITION BY visitorId ORDER BY Konsum DESC) plass
      FROM INNHOLD
           JOIN TOTALT USING(visitorId)),
  
  ANTALL AS (
    SELECT plass, seriesTitleOrTitle,
           SUM(Andel_av_tot) snittandel,
           COUNT(DISTINCT visitorId) `TV-klienter`
      FROM RANGERING
     GROUP BY ALL)

  SELECT plass, seriesTitleOrTitle,
         SAFE_DIVIDE(snittandel, `TV-klienter`) snittandel,
         `TV-klienter`
     FROM ANTALL
    ORDER BY 1, 4 DESC

Del 2

Hensikten med denne øvelsen er å finne ut om vi kan si noe om hvor vidt flere publikummere ser på samme TV-skjerm samtidig (samtitting). Vi har ikke data på dette, så vi må gjøre en del gjetninger på indirekte mål vi kan bruke som kanskje korrelerer med samtititting. Her er en liste:

  • Samtitting foregår i større grad på TV-klienter som logges på med flere profiler.
  • Samtitting foregår i større grad på visse typer programmer.
  • Samtitting med barn skjer tidligere på kvelden, mens samtitting med kun voksne skjer senere på kvelden.

Siden vi ikke kan korrelere disse gjetningene med data på samtitting, må vi forsøke å finne ut om det er forskjeller på krysstabulerte grupper. For eksempel kan vi undersøke om det forskjell mellom klienter med én pålogget profil og flere påloggede profiler i typen programmer som blir sett, eller når på kvelden programmene blir sett.

Det enkleste er å starte med å se på besøksstatistikk for brukerne som har vært logget på klientene fordelt på antall brukere som har vært pålogget klienten.

#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT DISTINCT visitorId, nrkUserId, userOrProfile,
           daysVisited, rfv.secondsConsumed
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
           -- Her mister vi nok noen klienter hvor brukerne ikke har vært logget på etter 15. nov 2024(?)
           JOIN (SELECT nrkUserId, last28Days.daysVisited,
                        last28Days.secondsConsumed
                   FROM `nrk-datahub.snowplow_aggregate.total_rfv`
                  WHERE partitionDate = '2024-12-13') rfv USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'),

  KLIENTAGG AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
           SUM(daysVisited) dager_besok, -- husk at dette er dager med besøk i NRK, ikke bare på klienten
           SUM(secondsConsumed) konsum_sek -- samme som over
      FROM BRUKERE
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM KLIENTAGG
     GROUP BY ALL),

  AGG AS (
  SELECT voksnes, barns, voksnei, barni,
         SUM(dager_besok) / SUM(voksne + barn) snitt_besok,
         SUM(konsum_sek) / SUM(voksne + barn) / 3600 snitt_konsum,
         COUNT(visitorId) klienter
    FROM BRUKERGRUPPERING
   GROUP BY ALL)

  SELECT voksnes voksne, barns barn,
         snitt_besok `Besøksdager per profil`,
         snitt_konsum `Timer konsum per profil`,
         klienter
    FROM AGG
   ORDER BY voksnei, barni
voksnebarnsnitt_besoksnitt_konsumklienter
01-312.17341040462427815.702509633911369369
0> 311.2511.1740972222222231
1019.66022545551940635.37026535531695126943
11-315.19300138739016517.49543542640837426516
1> 312.27101879327398711.982737113968568195
2-3017.2109581789306523.636721810481741839
2-31-314.83345911949685515.3672322851153051098
2-3> 311.91880341880341910.62355769230769474
> 3016.1520.59910416666666710
> 31-315.211.5741111111111121

Vi ser at det er et skille mellom både antall besøksdager og timer med konsum per profil i løpet av en fireukersperiode mellom profiler som har logget på klienter hvor det har vært logget på kun voksne og der det også har vært logget på barn. Husk at besøksdagene og konsumet gjelder alle NRKs tjenester for disse profilene. Vi kan derfor anta at barneprofilene trekker antallet besøksdager ned, siden de naturlig er på færre tjenester enn voksne. La oss derfor sammenligne disse metrikkene kun for de voksne.

#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT DISTINCT visitorId, nrkUserId, userOrProfile,
           daysVisited, rfv.secondsConsumed
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
           -- Her mister vi nok noen klienter hvor brukerne ikke har vært logget på etter 15. nov 2024(?)
           JOIN (SELECT nrkUserId, last28Days.daysVisited,
                        last28Days.secondsConsumed
                   FROM `nrk-datahub.snowplow_aggregate.total_rfv`
                  WHERE partitionDate = '2024-12-13') rfv USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'),

  KLIENTAGG AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
           SUM(IF(userOrProfile = 'user', daysVisited, NULL)) dager_besok_voksen, -- husk at dette er dager med besøk i NRK, ikke bare på klienten
           SUM(IF(userOrProfile = 'user', secondsConsumed, NULL)) konsum_sek_voksen -- samme som over
      FROM BRUKERE
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM KLIENTAGG
     GROUP BY ALL),

  AGG AS (
    SELECT voksnes, barns, voksnei, barni,
           SUM(dager_besok_voksen) / SUM(voksne) snitt_besok_voksen,
           SUM(konsum_sek_voksen) / SUM(voksne) / 3600 snitt_konsum_voksen,
           COUNT(visitorId) klienter
      FROM BRUKERGRUPPERING
     WHERE voksne > 0
     GROUP BY ALL)

  SELECT voksnes voksne, barns barn,
         snitt_besok_voksen `Besøksdager per profil`,
         snitt_konsum_voksen `Timer konsum per profil`,
         klienter
    FROM AGG
   ORDER BY voksnei, barni
voksnebarnBesøksdager per profilTimer konsum per profilklienter
1019.66022545551940635.37026535531695126943
11-320.41695580027153424.99739320913159426516
1> 320.74358974358974520.367146723646727195
2-3017.2109581789306523.636721810481741839
2-31-318.065382892969118.7222016967706641098
2-3> 317.8523489932885915.01933818046234174
> 3016.1520.59910416666666710
> 31-315.7513.109513888888891

Vi ser altså at antall besøksdager holder seg høyt når vi kun ser på voksenprofiler, men at timer med konsum er lavere der det også er barneprofiler med.

Det kan være interessant å gjøre denne øvelsen spesifikt for besøk hos NRK TV.

#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT DISTINCT visitorId, nrkUserId, userOrProfile,
           daysVisited, rfv.secondsConsumed
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
           -- Her mister vi nok noen klienter hvor brukerne ikke har vært logget på etter 15. nov 2024(?)
           JOIN (SELECT nrkUserId, last28Days.daysVisited,
                        last28Days.secondsConsumed
                   FROM `nrk-datahub.snowplow_aggregate.rfv_v01`
                  WHERE partitionDate = '2024-12-13'
                    AND nrkService = 'nrktv') rfv USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'),

  KLIENTAGG AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
           SUM(IF(userOrProfile = 'user', daysVisited, NULL)) dager_besok_voksen, -- husk at dette er dager med besøk i NRK, ikke bare på klienten
           SUM(IF(userOrProfile = 'user', secondsConsumed, NULL)) konsum_sek_voksen, -- samme som over
           SUM(IF(userOrProfile != 'user', daysVisited, NULL)) dager_besok_barn, -- husk at dette er dager med besøk i NRK, ikke bare på klienten
           SUM(IF(userOrProfile != 'user', secondsConsumed, NULL)) konsum_sek_barn -- samme som over
      FROM BRUKERE
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM KLIENTAGG
     GROUP BY ALL),

  SA AS (
    SELECT voksnes, barns,
           STDDEV(IF(userOrProfile = 'user', daysVisited, NULL)) sa_besok_voks,
           STDDEV(IF(userOrProfile != 'user', daysVisited, NULL)) sa_besok_barn,
           STDDEV(IF(userOrProfile = 'user', secondsConsumed / 3600, NULL)) sa_konsum_voks,
           STDDEV(IF(userOrProfile != 'user', secondsConsumed / 3600, NULL)) sa_konsum_barn,
           STDDEV(secondsConsumed / 3600) sa_konsum,
           STDDEV(daysVisited) sa_besok
      FROM BRUKERGRUPPERING
           JOIN BRUKERE USING(visitorId)
     GROUP BY ALL
    ),

  AGG AS (
    SELECT voksnes, barns, voksnei, barni,
           SUM(dager_besok_voksen) / SUM(voksne) snitt_besok_voksen,
           SUM(konsum_sek_voksen) / SUM(voksne) / 3600 snitt_konsum_voksen,
           SUM(dager_besok_barn) / SUM(barn) snitt_besok_barn,
           SUM(konsum_sek_barn) / SUM(barn) / 3600 snitt_konsum_barn,
           SUM(dager_besok_barn + dager_besok_voksen) / SUM(barn + voksne) snitt_besok,
           SUM(konsum_sek_barn + dager_besok_voksen) / SUM(barn + voksne) / 3600 snitt_konsum,             
           COUNT(visitorId) klienter
      FROM BRUKERGRUPPERING
     GROUP BY ALL)

  SELECT voksnes voksne, barns barn,
         snitt_besok_voksen `Besøksdager per voksen`,
         snitt_besok_barn `Besøksdager per barn`,
         snitt_besok `Besøksdager per profil`,
         snitt_konsum_voksen `Timer konsum per voksen`,
         snitt_konsum_barn `Timer konsum per barn`,
         snitt_konsum `Timer konsum per profil`,
         sa_besok_voks,
         sa_besok_barn,
         sa_besok,
         sa_konsum_voks,
         sa_konsum_barn,
         sa_konsum,
         klienter
    FROM AGG
         JOIN SA USING(voksnes, barns)
   ORDER BY voksnei, barni
voksnebarnBesøksdager per voksenBesøksdager per barnBesøksdager per profilTimer konsum per voksenTimer konsum per barnTimer konsum per profilsa_besok_vokssa_besok_barnsa_besoksa_konsum_vokssa_konsum_barnsa_konsumklienter
01-310.8689788053949913.8546820809248557.8649167520334787.86491675203347818.374927316492218.3749273164922369
0> 310.7510.56902777777777811.61536338935061811.61536338935061811.93928257433911911.9392825743391191
1016.9287633032148328.5041600342060777.49314699762228557.493146997622285538.8602008507371338.86020085073713126943
11-317.1870568713229779.5744120561088812.54140588870047818.4140622328656910.1487205303807225.9929058330335896.8457930617347237.75081935947605958.23217242168358817.59376978063779314.69655332868820416.43351158701652226516
1> 317.5846153846153868.72303921568627410.3719090009891214.9361182336182338.6705296840958616.9214575777557977.2507070361381767.2434701292832698.02621764568626413.15974738181909313.52153326167141113.645782883527305195
2-3013.528321863419816.8816115963766837.6272688968276017.62726889682760121.51170724335196721.5117072433519671839
2-31-313.3461710703090019.26291618828932311.43672955974842712.2356344230482169.6157311200408224.215926415094347.3914397120978927.8363267012287517.82786798901392715.17824727573548513.98330107593341514.719122711069431098
2-3> 312.8456375838926187.2225705329153619.01282051282051310.5023900074571217.0628361198188794.8153341642924987.0014376094759966.1887354129761036.96566724695575210.72951568035173210.90495416713568310.9529862125194774
> 3012.47517.366090277777788.796469049925028.7964690499250223.82778912408680223.82778912408680210
> 31-314.513.014.213.1029861111111115.43251.089722222222222311.0905365064094189.62808392152872714.73198557528765213.211389808760181

Konsum

La oss nå se på hvilke titler som konsumeres på TV-klienter med de ulike profilsammensetningene.

#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT DISTINCT visitorId, nrkUserId, userOrProfile,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'),

  AVSPILLINGER AS (
    SELECT nrkuserId, visitorId, seriesTitleOrTitle, SUM(secondsConsumed) konsum_sek
      FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(nrkUserId, visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY ALL),

  KLIENTAGG AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
           COUNT(seriesTitleOrTitle) titler,
           SUM(konsum_sek) konsum
      FROM BRUKERE
           JOIN AVSPILLINGER USING(nrkUserId, visitorId)
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM KLIENTAGG
     GROUP BY ALL),

  AGG AS (
    SELECT voksnes, barns, voksnei, barni,
           SUM(titler) / SUM(voksne + barn) snitt_titler,
           SUM(konsum) / SUM(voksne + barn) / 3600 snitt_konsum,
           COUNT(visitorId) klienter
      FROM BRUKERGRUPPERING
     GROUP BY ALL),

  SA AS (
    SELECT voksnes, barns,
           -- STDDEV(IF(userOrProfile = 'user', daysVisited, NULL)) sa_besok_voks,
           -- STDDEV(IF(userOrProfile != 'user', daysVisited, NULL)) sa_besok_barn,
           -- STDDEV(IF(userOrProfile = 'user', secondsConsumed / 3600, NULL)) sa_konsum_voks,
           -- STDDEV(IF(userOrProfile != 'user', secondsConsumed / 3600, NULL)) sa_konsum_barn,
           STDDEV(konsum_sek / 3600) sa_konsum,
           STDDEV(titler) sa_titler
      FROM BRUKERGRUPPERING
           JOIN AVSPILLINGER USING(visitorId)
     GROUP BY ALL)
  
  SELECT voksnes voksne, barns barn,
         snitt_titler `Titler per profil`,
         snitt_konsum `Timer konsumert per profil`,
         sa_titler `Standardavvik i titler`,
         sa_konsum `Standardavvik i konsum`
    FROM AGG
         JOIN SA USING(voksnes, barns)
   ORDER BY voksnei, barni
voksnebarnTitler per profilTimer konsumert per profilStandardavvik i titlerStandardavvik i konsum
01-310.30663221360895911.78323834816728833.2817190689287943.41146853363906
0> 313.211.23302222222222144.813721712508471.6538476973155098
1023.03217975849620227.5792957111809633.562835707251932.88865756907981
11-314.3249741898957614.11001322420932232.0681890180380052.141899249311868
1> 311.56670746634026910.48196076431388436.5388814690816162.2709013056628824
2-3014.79613052266820715.20482248852953531.173850872588372.1257942638623706
2-31-311.78485214242607210.92254584925903633.9679534091314751.9511222553859124
2-3> 310.2354740061162088.53596075433231342.9155556398145351.62301483892852
> 3012.1510.11363888888888834.164409720735191.5452092875633243
#standardSQL
WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT DISTINCT visitorId, nrkUserId, userOrProfile,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'),

  AVSPILLINGER AS (
    SELECT nrkuserId, visitorId, seriesTitleOrTitle, SUM(secondsConsumed) konsum_sek
      FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(nrkUserId, visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY ALL),

  KLIENTAGG AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
           COUNT(IF(userOrProfile = 'user', seriesTitleOrTitle, NULL)) titler,
           SUM(IF(userOrProfile = 'user', konsum_sek, NULL)) konsum
      FROM BRUKERE
           JOIN AVSPILLINGER USING(nrkUserId, visitorId)
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM KLIENTAGG
     GROUP BY ALL),

  AGG AS (
    SELECT voksnes, barns, voksnei, barni,
           SUM(titler) / SUM(voksne) snitt_titler,
           SUM(konsum) / SUM(voksne) / 3600 snitt_konsum,
           COUNT(visitorId) klienter
      FROM BRUKERGRUPPERING
     WHERE voksnei > 0
     GROUP BY ALL),

  SA AS (
    SELECT voksnes, barns,
           STDDEV(IF(userOrProfile = 'user', titler, NULL)) sa_titler,
           -- STDDEV(IF(userOrProfile != 'user', daysVisited, NULL)) sa_besok_barn,
           STDDEV(IF(userOrProfile = 'user', konsum_sek / 3600, NULL)) sa_konsum,
           -- STDDEV(IF(userOrProfile != 'user', secondsConsumed / 3600, NULL)) sa_konsum_barn,
      FROM BRUKERE
	   JOIN BRUKERGRUPPERING USING(visitorId)    	   
           JOIN AVSPILLINGER USING(visitorId)
     GROUP BY ALL)
  
  SELECT voksnes voksne, barns barn,
         snitt_titler `Titler per voksen`,
         snitt_konsum `Timer konsumert per voksen`,
         sa_titler `Standardavvik i titler`,
         sa_konsum `Standardavvik i konsum`
    FROM AGG
         JOIN SA USING(voksnes, barns)
   ORDER BY voksnei, barni
voksnebarnTitler per voksenTimer konsumert per voksenStandardavvik i titlerStandardavvik i konsum
1023.03217975849620227.5792957111809633.557029450482432.8884246278508505
11-319.3895888861965918.88223032155004721.5262376851014642.142384619316234
1> 318.08227848101265815.18513185654008316.6228803085933632.2979223333929033
2-3014.79613052266820715.20482248852953530.9474371070642962.1210745269955815
2-31-312.91288081239978611.42024704554902424.5976099724551531.9599117531888546
2-3> 312.69230769230769210.82419604700854524.8463467059167731.6207195281011462
> 3012.1510.11363888888888834.113073238360781.5428874090352245
#standardSQL
  WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT DISTINCT visitorId, nrkUserId, userOrProfile,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'),

  AVSPILLINGER AS (
    SELECT nrkuserId, visitorId, seriesTitleOrTitle, SUM(secondsConsumed) konsum_sek
      FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(nrkUserId, visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY ALL),

  KLIENTAGG AS (
    SELECT visitorId,
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
           COUNT(IF(userOrProfile != 'user', seriesTitleOrTitle, NULL)) titler,
           SUM(IF(userOrProfile != 'user', konsum_sek, NULL)) konsum
      FROM BRUKERE
           JOIN AVSPILLINGER USING(nrkUserId, visitorId)
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM KLIENTAGG
     GROUP BY ALL),

  AGG AS (
    SELECT voksnes, barns, voksnei, barni,
           SUM(titler) / SUM(barn) snitt_titler,
           SUM(konsum) / SUM(barn) / 3600 snitt_konsum,
           COUNT(visitorId) klienter
      FROM BRUKERGRUPPERING
     WHERE barni > 0
     GROUP BY ALL),

  SA AS (
    SELECT voksnes, barns,
           STDDEV(IF(userOrProfile != 'user', titler, NULL)) sa_titler,
           STDDEV(IF(userOrProfile != 'user', konsum_sek / 3600, NULL)) sa_konsum,
      FROM BRUKERE
	   JOIN BRUKERGRUPPERING USING(visitorId)    	   
           JOIN AVSPILLINGER USING(visitorId)
     GROUP BY ALL)
  
  SELECT voksnes voksne, barns barn,
         snitt_titler `Titler per barn`,
         snitt_konsum `Timer konsumert per barn`,
         sa_titler `Standardavvik i titler`,
         sa_konsum `Standardavvik i konsum`
    FROM AGG
         JOIN SA USING(voksnes, barns)
   ORDER BY voksnei, barni
voksnebarnTitler per barnTimer konsumert per barnStandardavvik i titlerStandardavvik i konsum
01-310.30663221360895911.78323834816728833.828559925817772.952172369745312
0> 313.211.23302222222222145.224391071102411.6882289543973037
11-310.77147795534398810.7616725304444224.374865680949752.068292480541051
1> 310.0045523520485589.35434159500927429.4749326059986782.3320390296632354
2-31-310.32224532224532310.2772243397243423.250487386049021.9434231057606755
2-3> 39.0896860986547087.46880169407075226.2610025907579041.6011315056872737

Her har vi et annet perspektiv der vi ser på første, andre og tredje kvartil for fordelingen av antall titler og konsum.

#standardSQL
  WITH
  KLIENTER AS (
  SELECT DISTINCT visitorId
    FROM `nrk-datahub.snowplow_processed.playback_v02`
   WHERE partitionDate BETWEEN '2024-11-09' AND '2024-12-12'
     AND REGEXP_CONTAINS(content.id, 'KMTE60005[1:6]24')
     AND platform = 'tv'
  ),

  BRUKERE AS (
    SELECT visitorId, 
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile != 'user', nrkUserId, NULL)) Barn,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN KLIENTER USING(visitorId)
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM BRUKERE
     GROUP BY ALL),

  AVSPILLINGER AS (
    SELECT visitorId, seriesTitleOrTitle, SUM(secondsConsumed) konsum_sek
      FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
     WHERE partitionDate  BETWEEN '2024-11-09' AND '2024-12-12'
       AND platform = 'tv'
     GROUP BY ALL),

  KLIENTAGG AS (
    SELECT visitorId, voksnes, barns, voksnei, barni,
           COUNT(DISTINCT seriesTitleOrTitle) titler,
           SUM(konsum_sek) / 3600 konsum
      FROM BRUKERGRUPPERING
           JOIN AVSPILLINGER USING(visitorId)
     GROUP BY ALL),

  STATS AS (
    SELECT DISTINCT voksnes, barns, voksnei, barni,
           PERCENTILE_DISC(titler, .25) OVER(PARTITION BY voksnes, barns, voksnei, barni) kv1_titler,
           PERCENTILE_DISC(titler, .5) OVER(PARTITION BY voksnes, barns, voksnei, barni) med_titler,
           PERCENTILE_DISC(titler, .75) OVER(PARTITION BY voksnes, barns, voksnei, barni) kv3_titler,
           PERCENTILE_CONT(konsum, .25) OVER(PARTITION BY voksnes, barns, voksnei, barni) kv1_konsum,
           PERCENTILE_CONT(konsum, .5) OVER(PARTITION BY voksnes, barns, voksnei, barni) med_konsum,
           PERCENTILE_CONT(konsum, .75) OVER(PARTITION BY voksnes, barns, voksnei, barni) kv3_konsum,
           COUNT(visitorId) OVER(PARTITION BY voksnes, barns, voksnei, barni) klienter
      FROM KLIENTAGG)
  
  SELECT voksnes voksne, barns barn,
         kv1_titler, med_titler, kv3_titler,
         kv1_konsum, med_konsum, kv3_konsum,
         klienter
    FROM STATS
   ORDER BY voksnei, barni

Innhold konsumert

Identifisere brukere som representerer flere publikummere

Jeg skal her forsøke å identifisere brukere som representerer flere publikummere. Før jeg kan gjøre det må jeg undersøke i hvilken grad det er trolig at én bruker brukses av flere publikummere. Det enkleste er å identifisere brukere som representerer både voksne og barn. Dette kan lett gjøres ved å undersøke hva som er blitt konsumert, og hvor ofte og hvor mye det konsumeres. Derimot er det vesentlig vanskeligere å skille ut brukere som brukes av flere voksne eller flere barn. Man må huske på her at det er kliente med kun én bruker som er av interesse i denne omgang. Vi må også undersøke om det er konsum på klienten som ikke er gjort at en pålogget bruker. Dette må jeg jobbe videre med neste uke.

#standardSQL
WITH
  BRUKERE AS (
    SELECT visitorId, 
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile = 'profile', nrkUserId, NULL)) Barn,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM BRUKERE
     GROUP BY ALL),
  
  AVSPILLINGER AS (
    SELECT visitorId, nrkUserId, seriesTitleOrTitle tittel, SUM(secondsConsumed) / 3600 konsum
      FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'
     GROUP BY ALL),

  KRONOLOGI AS (
    SELECT visitorId, nrkUserId,
	         LAG(nrkUserId) OVER(PARTITION BY visitorId ORDER BY partitionDate) IS NOT NULL AND nrkUserId IS NULL pa_av
           FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'),

  KRONOLOGISJEKK AS (
    SELECT DISTINCT visitorId,
           LOGICAL_AND(pa_av) OVER(PARTITION BY visitorId) pa_av
      FROM KRONOLOGI),

  SJEKK AS (
    SELECT visitorId, pa_av,
           COUNT(IF(nrkUserId IS NULL, tittel, NULL)) ikke_pl_titler,
           COUNT(IF(nrkUserId IS NOT NULL, tittel, NULL)) pl_titler,
           SUM(IF(nrkUserId IS NULL, konsum, NULL)) ikke_pl_konsum,
           SUM(IF(nrkUserId IS NOT NULL, konsum, NULL)) pl_konsum
      FROM AVSPILLINGER
           JOIN BRUKERGRUPPERING USING(visitorId)
           JOIN KRONOLOGISJEKK USING(visitorId)
     WHERE voksnei = 1 AND barni = 0
     GROUP BY ALL)

SELECT DISTINCT COUNTIF(SAFE_DIVIDE(pl_titler, pl_titler + ikke_pl_titler) < 1) OVER() / COUNT(visitorId) OVER() `Andel klienter med ikke- og pålogget konsum`,
       COUNT(IF(pa_av, visitorId, NULL)) OVER() `Antall som logger av etter å ha logget på`,
       PERCENTILE_CONT(SAFE_DIVIDE(pl_titler, pl_titler + ikke_pl_titler), .01) OVER() `Andel påloggede titler for første persentil`,
       PERCENTILE_DISC(IF(SAFE_DIVIDE(pl_titler, pl_titler + ikke_pl_titler) < .5, ikke_pl_titler, NULL), .5) OVER() `Median antall ikke-påloggede titler`,
       PERCENTILE_DISC(IF(SAFE_DIVIDE(pl_titler, pl_titler + ikke_pl_titler) > .5, pl_titler, NULL), .5) OVER() `Median antall påloggede titler`,
       COUNT(visitorId) OVER() `Antall klienter`
  FROM SJEKK
Andel klienter med ikke- og pålogget konsumAntall som logger av etter å ha logget påAndel påloggede titler for første persentilMedian antall ikke-påloggede titlerMedian antall påloggede titlerAntall klienter
0.0342973474261903500.5841259456

Som vi ser er det 3,4 % av klientene med kun én pålogget voksenprofil som også har konsum på ikke påloggete brukere. Det tyder på at alle disse er brukere som har gått over fra å bruke klienten avlogget til å bruke den pålogget. For 1 % er andelen bruk som blir gjort av ikke-påloggete brukere større enn bruk som blir gjort av påloggede brukere. Median antall titler som blir konsumert av ikke-påloggede brukere der andelen konsumerte titler er større enn andelen påloggede konsumerte titler, er åtte. Til sammenligning er den bare fire for påloggede. Videre kommer jeg til å se bort fra klientene med ikke-pålogget konsum. Jeg tenker derfor at den avloggede bruken kan ses som del av den påloggede bruken, og at jeg kan se klientene vi har tittet på over under ett.

Skille ut brukere som brukes av barn og voksne

Utgangspunktet for undersøkelsen er følgende spørring.

#standardSQL
WITH
  BRUKERE AS (
    SELECT visitorId, 
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile = 'profile', nrkUserId, NULL)) Barn,
           2025 - birthYear alder,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM BRUKERE
     GROUP BY ALL),

  AVSPILLINGER AS (
    SELECT visitorId, 
           COUNT(DISTINCT IF(isInSuperUniverse, seriesTitleOrTitle, NULL)) barnetitler,
           SUM(IF(isInSuperUniverse, secondsConsumed, NULL)) / 3600 barnetittelkonsum,
           COUNT(DISTINCT IF(NOT isInSuperUniverse, seriesTitleOrTitle, NULL)) voksentitler,
           SUM(IF(NOT isInSuperUniverse, secondsConsumed, NULL)) / 3600 voksentittelkonsum,
      FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'
     GROUP BY ALL)
  
  SELECT alder IS NULL har_alder,
         COUNT(IF(barnetitler > 0 AND voksentitler > 0, visitorId, NULL)) / COUNT(visitorId) `Andel klienter med barne og voksne`,
         COUNT(IF(barnetitler = 0 AND voksentitler > 0, visitorId, NULL)) / COUNT(visitorId) `Andel klienter med kun voksne`,
         COUNT(IF(barnetitler > 0 AND voksentitler = 0, visitorId, NULL)) / COUNT(visitorId) `Andel klienter med kun barn`,
         COUNT(visitorId) Klienter
    FROM AVSPILLINGER
         JOIN BRUKERGRUPPERING USING(visitorId)
   WHERE voksnei = 1 AND barni = 0
   GROUP BY ALL
har_alderAndel klienter med barne og voksneAndel klienter med kun voksneAndel klienter med kun barnKlienter
false0.197040678122514770.7360305513409640.056632349787883146736858
true0.18880227778896040.71826646494685380.08178580472569785616036

I første omgang er det klienter med barn og voksne som antakelig kan enklest vise seg å bli brukt av flere publikummere. Neste steg er å se på fordelingen mellom konsum av barneinnhold og vokseninnhold

Tidligere forsøk

Dette gjør jeg ved å sammenligne brukere som er pålogget som eneste bruker på en klient med klienter som har flere påloggede brukere. Tanken er at klienter med flere påloggede brukere vil ha lignende bruksmønster som klienter med kun én pålogget bruker der denne brukeren representerer flere publikummere.

#standardSQL
WITH
  BRUKERE AS (
    SELECT visitorId, 
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile = 'profile', nrkUserId, NULL)) Barn,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM BRUKERE
     GROUP BY ALL)--,

  SELECT voksne, barn, klienter
  FROM (SELECT voksnes voksne, barns barn, voksnei, barni, COUNT(visitorId) klienter
          FROM BRUKERGRUPPERING
         GROUP BY ALL)
  ORDER BY voksnei, barni

Her er det klientene med flere enn én pålogget profil som kan brukes som grunnlag for å modellere hvor vidt de klientene med kun én pålogget profil i virkeligheten representerer flere publikummere. Hvordan skal vi gå frem for å modellere hvilke av brukerne som representerer flere publikummere? Dersom vi hadde hatt klienter med én pålogget bruker som vi visste representerte én publikummer, og klienter med flere påloggede brukere som vi visste representrte én publikummer hver, kunne vi brukt disse som modell for klienter som brukes av kun én bruker og klienter som brukes av flere brukere. Problemet er at vi ikke vet om klienter med kun én pålogget bruker egentlig representerer flere publikummere. Derimot er det tydeligere at klienter med flere påloggede brukere representerer flere publikummere. Så hvordan bruker vi denne informasjonen? Hvis vi kan lage en modell som er trent på å skille klienter som brukes av flere publikummere fra dem som ikke gjør det, vil vi i prinsippet sitte igjen med dem som brukes av kun én publikummer.

Hvilke variabler skal vi så bruke for å modellere dette? Fra tidligere undersøkelser vet vi at det konsumeres flere ulike titler på klienter med flere påloggede profiler, og at total konsumtid er lengre. Antakelig vil det også konsumeres på flere tidspunkt i døgnet på klienter som brukes av flere publikummere. Dette må ennå undersøkes. Antakelsen som dette hviler på er at profiler som brukes på klienter med flere påloggede profiler i større grad representerer kun én bruker.

Utforskning av variabler

La oss starte med å se på sannsynlighetsfordelingene til variablene vi tenker å bruke. For antall titler og timer konsum bruker jeg denne spørringen.

#standardSQL
  WITH
  BRUKERE AS (
    SELECT visitorId, 
           COUNT(DISTINCT IF(userOrProfile = 'user', nrkUserId, NULL)) Voksne,
           COUNT(DISTINCT IF(userOrProfile = 'profile', nrkUserId, NULL)) Barn,
      FROM `nrk-datahub.snowplow_processed.views_v02`
           JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'
     GROUP BY ALL),

  BRUKERGRUPPERING AS (
    SELECT *,
           CASE
             WHEN Voksne = 0 THEN Voksne
             WHEN Voksne = 1 THEN Voksne
             WHEN Voksne < 4 THEN 2
             ELSE 4
           END voksnei,
           CASE
             WHEN Barn = 0 THEN Barn
             WHEN Barn < 4 THEN 1
             ELSE 4
           END barni,
           CASE
             WHEN Voksne = 0 THEN '0'
             WHEN Voksne = 1 THEN '1'
             WHEN Voksne < 4 THEN '2-3'
             ELSE '> 3'
           END voksnes,
           CASE
             WHEN Barn = 0 THEN '0'
             WHEN Barn < 4 THEN '1-3'
             ELSE '> 3'
           END barns,
      FROM BRUKERE
     GROUP BY ALL),

  AVSPILLINGER AS (
    SELECT visitorId, nrkUserId, userOrProfile, COUNT(seriesTitleOrTitle) titler, SUM(secondsConsumed) konsum_sek
      FROM BRUKERE
           LEFT JOIN `nrk-datahub.snowplow_processed.playback_v02` USING(visitorId)
           LEFT JOIN `nrk-datahub.metadata_views.metadata_programs` ON id=content.id
	   JOIN `nrk-datahub.prod.registered_users_v01` USING(nrkUserId)
     WHERE partitionDate > CURRENT_DATE - 30
       AND platform = 'tv'
       AND nrkService = 'nrktv'
     GROUP BY ALL)

  SELECT sammensetning, userOrProfile, titler_per_bruker, konsum_per_bruker, brukere
    FROM (SELECT CONCAT('voksne: ', voksnes, ', barn: ', barns) sammensetning,
                 voksnei, barni, userOrProfile,
		 titler titler_per_bruker,
                 CAST(konsum_sek / 1800 AS INT64) / 2 konsum_per_bruker,
                 COUNT(nrkUserId) brukere
            FROM BRUKERGRUPPERING
                 JOIN AVSPILLINGER USING(visitorId)
           GROUP BY ALL)
   ORDER BY voksnei, barni, brukere DESC

Antall titler

import pandas as pd
import matplotlib.pyplot as plt
import pandas_gbq
import numpy as np
df = pandas_gbq.read_gbq(spørring, dialect = "standard")
fig_s = df[["sammensetning", "userOrProfile", "titler_per_bruker", "brukere"]] \
    .groupby(["sammensetning", "userOrProfile", "titler_per_bruker"]) \
    .sum()
fig,ax = plt.subplots(figsize=(11,7))
sammensetninger = df.sammensetning.unique().tolist()
enslige_voksne = ["voksne: 1, barn: 0"]
enslige_voksne_ind = sammensetninger.index(enslige_voksne[0])
voksne_uten_barn_ind = [sammensetninger.index("voksne: 2-3, barn: 0"), sammensetninger.index("voksne: > 3, barn: 0")]
voksne_uten_barn = [sammensetninger[voksne_uten_barn_ind[0]]] + [sammensetninger[voksne_uten_barn_ind[1]]]
voksne_med_barn = sammensetninger[1+enslige_voksne_ind:voksne_uten_barn_ind[0]] + \
    sammensetninger[1+voksne_uten_barn_ind[0]:voksne_uten_barn_ind[1]] + \
    sammensetninger[1+voksne_uten_barn_ind[1]:]
grupper = [enslige_voksne, voksne_uten_barn, voksne_med_barn]
for g, l zip(grupper, ["Enslige voksne", "Voksne uten barn", "Voksne med barn"]):
    d = fig_s.loc[g].groupby("titler_per_bruker").sum()
    d = d / d.sum()
    ax.plot(d.index, d, label=l)
    # print(f"g: {g}\nl: {l}\n")

ax.legend()
ax.set_xlim([0,200])
fig

Timer med konsum

fig_s = df[["sammensetning", "konsum_per_bruker", "brukere"]].groupby(["sammensetning", "konsum_per_bruker"]).sum()
fig,ax = plt.subplots(figsize=(11,7))
sammensetninger = df.sammensetning.unique().tolist()
grupper = sammensetninger[1+sammensetninger.index("voksne: 1, barn: 0"):] # tar ikke med voksne: 0, siden det stort sett kun er én barneprofil på disse
for g, l in zip(grupper, ["Enslige voksne", "Voksne uten barn", "Voksne med barn"]):
    d = fig_s.loc[g].groupby("konsum_per_bruker").sum()
    d = d / d.sum()
    ax.plot(d.index, d, label=l)
    # print(f"g: {g}\nl: {l}\n")

ax.legend()
ax.set_xlim([0,200])
fig

Notater

  • Hvilke titler har klientene på 1. - 10. plass?
  • Når på døgnet konsumeres de ulike titlene?
  • Hvilken profil konsumeres titlene på?
  • Hvordan er sammensetningen av ulike profiler på TV-klientene, og hva konsumeres på disse klientene?
  • Hvor stor andel av total konsum på klienten består av topp tre titler?
  • Hvordan fordeler konsumet på klienten seg på påloggede profiler?