Opas

Asiakaspoistuman ennustaminen BigQuery ML:llä

Asiakaspoistuman ennustaminen auttaa kohdistamaan huomiota asiakkuuksiin, joiden ostaminen tai palvelun käyttö on hiipumassa. Toimiva ratkaisu tarvitsee selkeän poistuman määritelmän, päätöshetkeä vastaavan aineiston ja keinon hyödyntää havaintoja. Tässä oppaassa rakennamme BigQuery ML:llä esimerkin, joka arvioi aiemmin ostaneen asiakkaan todennäköisyyttä olla ostamatta seuraavien 60 päivän aikana.

Julkaistu 2026-09-19 · Lukuaika 11 min

Kirjoittaja: · Data-analytiikan ja raportoinnin toteutuksia vuodesta 2018.

Aihe: Koneoppiminen

Oppaan ydinkohdat

  • Poistuma määritellään liiketoiminnan ostorytmin mukaan. Ostotauko ei automaattisesti tarkoita asiakkuuden päättymistä.
  • Mallin syötteet kuvaavat tarkasteluhetkeä. Tulevat ostot muodostavat opetettavan vastauksen vasta sovitun seuranta-ajan kuluttua.
  • Suuri poistumariski ei kerro, kuka hyötyy yhteydenotosta. Mallin osuvuus ja asiakkuustoimien vaikutus arvioidaan erikseen.

Mitä asiakaspoistuma tarkoittaa omassa liiketoiminnassa?

Sopimuspalvelussa poistuma voi tarkoittaa irtisanomista tai sopimuksen uusiutumatta jäämistä. Ilman jatkuvaa sopimusta asiakas ei yleensä ilmoita lähtöään. Tällöin on sovittava havaittava määritelmä, kuten ostojen puuttuminen tietyn ajanjakson aikana. Tarkastelujakso riippuu tavallisesta ostovälistä: kuukausittain ostava ja vuosittain tilaava asiakas tarvitsevat erilaisen arvioinnin.

Tässä esimerkissä mukana ovat asiakkaat, joilla on vähintään yksi hyväksytty osto tarkastelupäivään päättyvien 90 kalenteripäivän aikana. Tavoite churn_60d saa arvon 1, jos seuraavina 60 päivänä ei tule yhtään hyväksyttyä ostoa, ja arvon 0, jos osto syntyy. Se on ostotauon ennuste tämän rajauksen sisällä, ei varma tieto asiakassuhteen päättymisestä.

Sopikaa myös asiakkuuden yksikkö. Yritys, toimipiste, sopimus ja yksittäinen ostaja eivät ole sama asia. Jos samat ostot kirjautuvat usealle tunnisteelle, yhdistäminen pitää ratkaista ennen mallintamista.

Valmistelkaa tarkasteluhetkeä vastaavat lähtötiedot

Oletamme taulun oma-projekti.analytics.customer_churn_features, jossa on yksi rivi asiakasta ja tarkastelupäivää kohti. Piirteet lasketaan vain siihen mennessä käytettävissä olleista tiedoista. Jälkikäteen muuttuva nykyinen asiakaskortti ei riitä historian kuvaamiseen, jos sen vanhoja arvoja ei voida palauttaa.

Esimerkin recency_days ja orders_90d ovat kokonaislukuja. spend_90d on samassa sovitussa valuutassa oleva vähintään nollan suuruinen NUMERIC-arvo. Ostojen ja palautusten käsittely sovitaan yhteisesti. Tunnisteita ja tarkastelupäivää säilytetään tulosten yhdistämiseen, mutta niitä ei anneta tämän mallin ennustaviksi muuttujiksi.

  • customer_key (STRING): yrityksen sisäinen asiakasavain; ei nimi tai sähköpostiosoite.
  • snapshot_date (DATE): päivä, jonka päättymishetken tiedoilla ennuste tehtäisiin.
  • recency_days (INT64): päivät viimeisestä hyväksytystä ostosta; esimerkin kohderyhmässä 0–89.
  • orders_90d (INT64) ja spend_90d (NUMERIC): ostojen määrä ja arvo viimeisen 90 kalenteripäivän aikana tarkastelupäivä mukaan lukien.
  • churn_60d (INT64): toteutunut vastaus 0 tai 1 seuraavilta 60 päivältä, tarkastelupäivää seuraavasta päivästä alkaen.
  • label_complete (BOOL): tieto siitä, että koko 60 päivän seurantaikkunan ostoaineisto on tarkistettu valmiiksi.

Erottakaa opetus, valinta ja lopullinen testi ajallisesti

Uusimmalle tarkastelupäivälle ei ole vielä oikeaa vastausta. Myös ne asiakkaat, joilla on jo uusi osto, otetaan opetukseen vasta samalla valmistumissäännöllä kuin muut. Muuten mukaan tulisi tuoreelta jaksolta valikoidusti vain nopeasti ostaneita asiakkaita. Puuttuvaa lopputulosta ei merkitä poistumaksi.

Tämän harjoituksen opetusjakso on vuosi 2025. Ensimmäinen arviointipäivä on 1.4.2026 ja sen vastausjakso päättyy 31.5.2026. Mallin ja käsittelyrajan valinnat tehdään tällä arviointiaineistolla. Lopullinen testi on 1.7.2026, jonka 60 päivän vastaukset ovat valmiita aikaisintaan 30.8.2026. Aineiston mahdollinen toimitusviive lisätään näihin päivämääriin.

Käyttäkää esimerkiksi kuukausittaisia tarkastelupäiviä, jotta sama asiakas ei painotu opetuksessa mielivaltaisesti päivittäisten havaintojen määrän vuoksi. Olemassa olevan asiakkaan ennustamisessa sama asiakas voi esiintyä eri ajankohtina, mutta tulevat tiedot eivät saa päätyä aiempaan havaintoon. Jos tavoitteena on toimivuus kokonaan uusilla asiakkailla, testatkaa myös asiakkaan perusteella erotetulla aineistolla.

Jäädyttäkää ja tarkistakaa opetusaineisto

Vaihtakaa projektitunnus ja esimerkkipäivät omiin tietoihinne. Luokaa ml_demo-dataset lähteen kanssa samaan sijaintiin ja varmistakaa oikeudet sekä laskutus. CREATE OR REPLACE korvaa samannimisen kokeilutaulun tai mallin. Säilyttäkää kokeilussa käytetty aineisto muuttumattomana.

Alla tarkistetaan, että kummastakin vastausluokasta löytyy havaintoja, asiakas–päivä-avaimet ovat yksikäsitteisiä ja valittu asiakasjoukko vastaa sovittua määritelmää. Kaksi luokkaa on tekninen perustarkistus; hyödyllinen malli tarvitsee riittävästi erilaisia tapauksia kummastakin luokasta.

Opetusaineisto ja perustarkistukset
CREATE OR REPLACE TABLE `oma-projekti.ml_demo.churn_training` AS
SELECT customer_key, snapshot_date, recency_days,
       orders_90d, spend_90d, churn_60d, label_complete
FROM `oma-projekti.analytics.customer_churn_features`
WHERE snapshot_date BETWEEN DATE '2025-01-01' AND DATE '2025-12-31';

ASSERT (
  SELECT COUNT(*) > 0 AND COUNT(DISTINCT churn_60d) = 2
  FROM `oma-projekti.ml_demo.churn_training`
) AS 'Tarvitaan havaintoja molemmista vastausluokista';

ASSERT (
  SELECT COUNTIF(
    customer_key IS NULL OR churn_60d IS NULL OR churn_60d NOT IN (0, 1)
    OR NOT COALESCE(label_complete, FALSE)
    OR recency_days IS NULL OR recency_days < 0 OR recency_days >= 90
    OR orders_90d IS NULL OR orders_90d < 1
    OR spend_90d IS NULL OR spend_90d < 0
  ) = 0
  FROM `oma-projekti.ml_demo.churn_training`
) AS 'Tarkista piirteet ja vastausjakson valmius';

ASSERT (
  SELECT COUNT(*) = 0 FROM (
    SELECT customer_key, snapshot_date
    FROM `oma-projekti.ml_demo.churn_training`
    GROUP BY customer_key, snapshot_date
    HAVING COUNT(*) > 1
  )
) AS 'Yksi rivi asiakasta ja tarkastelupaivaa kohti';

Opettakaa ensimmäinen luokittelumalli BigQuery ML:llä

Logistinen regressio on selkeä lähtökohta kaksiluokkaiseen ennusteeseen. Tässä ostojen määrä ja arvo muunnetaan logaritmiselle asteikolle, jotta suurimmat arvot eivät hallitse syötteiden vaihtelua yhtä voimakkaasti. Sama muunnos tehdään arvioinnissa ja uuden aineiston pisteytyksessä.

NO_SPLIT tarkoittaa, että kaikki kyselyn palauttamat rivit käytetään opetukseen. Se ei korvaa erillistä arviointia: harjoituksen myöhemmät arviointi- ja testipäivät annetaan erikseen seuraavassa vaiheessa. Esimerkki ei käytä luokkien automaattista painotusta. Jos painotusta muutetaan, arvioikaa myös pisteiden tulkinta todennäköisyyksinä uudelleen.

Poistumamallin opettaminen ilman tunnisteita tai tulevia tietoja
CREATE OR REPLACE MODEL `oma-projekti.ml_demo.churn_logistic_v1`
OPTIONS (
  MODEL_TYPE = 'LOGISTIC_REG',
  INPUT_LABEL_COLS = ['churn_60d'],
  DATA_SPLIT_METHOD = 'NO_SPLIT',
  AUTO_CLASS_WEIGHTS = FALSE
) AS
SELECT
  recency_days,
  LN(1 + orders_90d) AS log_orders_90d,
  LN(1 + spend_90d) AS log_spend_90d,
  churn_60d
FROM `oma-projekti.ml_demo.churn_training`;

Arvioikaa osuvuutta ja käsittelykapasiteettia

Tarkistakaa arviointiaineistolle samat avain-, kohderyhmä- ja piirresäännöt kuin opetusaineistolle. Alla pysäytetään arviointi, jos päivä puuttuu tai sen vastausjakso ei ole kokonaan valmistunut. Kynnys 0,5 on esimerkin lähtöarvo, ei suositus yhteydenottojen rajaksi.

Poistumaluokan precision kertoo, kuinka suuri osa poistuviksi luokitelluista kuuluu toteutuneeseen poistumaluokkaan. Sen recall kertoo, kuinka suuren osan kaikista poistuneista malli löytää. ML.EVALUATE palauttaa näistä luokkien makrokeskiarvot, joten alla lasketaan erikseen myös luokan 1 luvut. Verratkaa lisäksi samaan käsittelymäärään rajattuja listoja: jos tiimi ehtii arvioida 100 asiakasta, löytääkö malli tästä joukosta enemmän poistuvia kuin viimeisen oston iän perusteella tehty järjestys?

Myöhemmän päivän arviointi; lopulliseen testiin vaihdetaan 2026-07-01
DECLARE evaluation_date DATE DEFAULT DATE '2026-04-01';

ASSERT (
  SELECT COUNT(*) > 0 AND COUNTIF(
    NOT COALESCE(label_complete, FALSE)
    OR churn_60d IS NULL OR churn_60d NOT IN (0, 1)
  ) = 0
  FROM `oma-projekti.analytics.customer_churn_features`
  WHERE snapshot_date = evaluation_date
) AS 'Arviointipaivan vastaukset eivat ole valmiita';

SELECT *
FROM ML.EVALUATE(
  MODEL `oma-projekti.ml_demo.churn_logistic_v1`,
  (
    SELECT recency_days,
      LN(1 + orders_90d) AS log_orders_90d,
      LN(1 + spend_90d) AS log_spend_90d,
      churn_60d
    FROM `oma-projekti.analytics.customer_churn_features`
    WHERE snapshot_date = evaluation_date
  ),
  STRUCT(0.5 AS threshold)
);

-- Poistumaluokan (1) precision ja recall samalla kynnyksella.
WITH scored AS (
  SELECT churn_60d,
    (SELECT probability FROM UNNEST(predicted_churn_60d_probs)
     WHERE CAST(label AS STRING) = '1') AS churn_score
  FROM ML.PREDICT(
    MODEL `oma-projekti.ml_demo.churn_logistic_v1`,
    (
      SELECT recency_days,
        LN(1 + orders_90d) AS log_orders_90d,
        LN(1 + spend_90d) AS log_spend_90d,
        churn_60d
      FROM `oma-projekti.analytics.customer_churn_features`
      WHERE snapshot_date = evaluation_date
    )
  )
)
SELECT
  COUNT(*) AS evaluated_customers,
  COUNTIF(churn_score >= 0.5) AS flagged_customers,
  SAFE_DIVIDE(COUNTIF(churn_score >= 0.5 AND churn_60d = 1),
              COUNTIF(churn_score >= 0.5)) AS churn_precision,
  SAFE_DIVIDE(COUNTIF(churn_score >= 0.5 AND churn_60d = 1),
              COUNTIF(churn_60d = 1)) AS churn_recall
FROM scored;

Sopikaa kynnys tai käsittelymäärä arviointivaiheessa. Lukitkaa valinnat ennen heinäkuun lopullista testiä. Tarkastelkaa tuloksia myös asiakkuuden keston, tuoteryhmän ja markkinan mukaan sekä riittävän pitkällä ajanjaksolla.

Jos riskipiste esitetään prosenttina, tarkistakaa kalibrointi: vastaako esimerkiksi samantasoisten pisteiden joukossa toteutunut poistuma mallin arviota? Luokkien painotus, aineiston valikoituminen ja asiakkaiden käyttäytymisen muutos voivat heikentää tätä vastaavuutta.

Tuokaa riskipisteet hallittuun asiakkuustyöhön

Alla näytetään, miten mallin pisteet haetaan uudelle tarkastelupäivälle. Tulevaa churn_60d-vastausta ei anneta syötteeksi. Asiakasavain kulkee mukana tuloksessa yhdistämistä varten, mutta se ei ollut opetuksen piirre. Tarkistakaa uuden aineiston laatu ennen ajoa kuten opetuksessa.

Tallentakaa pisteet yhdessä tarkastelupäivän, malliversion ja ajoajankohdan kanssa. Tuotannossa käytetään arvioitua, hyväksyttyä malliversiota ja sovittua päivitysrytmiä. Nykyinen esimerkki näyttää laskentatavan; opetusjaksoa ei pidetä loputtomasti samana.

Uuden asiakasjoukon pisteytys ja malliversion säilyttäminen
CREATE OR REPLACE TABLE `oma-projekti.ml_demo.customer_churn_scores` AS
SELECT
  customer_key,
  snapshot_date,
  (SELECT probability
   FROM UNNEST(predicted_churn_60d_probs)
   WHERE CAST(label AS STRING) = '1') AS churn_score,
  'churn_logistic_v1' AS model_version,
  CURRENT_TIMESTAMP() AS scored_at
FROM ML.PREDICT(
  MODEL `oma-projekti.ml_demo.churn_logistic_v1`,
  (
    SELECT customer_key, snapshot_date, recency_days,
      LN(1 + orders_90d) AS log_orders_90d,
      LN(1 + spend_90d) AS log_spend_90d
    FROM `oma-projekti.analytics.customer_churn_features`
    WHERE snapshot_date = DATE '2026-09-01'
  )
);

Tuotannossa säilytetään myös aikaisemmat pisteytysversiot ennen nykyisen taulun korvaamista. Raportissa näytetään riskijakauma ja seurannan kattavuus. Asiakasvastuullisen työlistalle tuodaan vain hänen tarvitsemansa tiedot ja sovitaan ihmisen arvio ennen yhteydenottoa.

Riskien tunnistaminen ja asiakkuuden säilyttäminen ovat eri arvioita

Korkea riski ei tarkoita, että juuri tämä asiakas vastaisi tarjoukseen tai yhteydenottoon. Osa asiakkaista jatkaisi muutenkin ja osan tilannetta toimenpide ei muuta. Arvioikaa valittujen asiakkuustoimien vaikutus erillisellä vertailulla, esimerkiksi jakamalla soveltuva asiakasjoukko satunnaisesti toimenpide- ja vertailuryhmään.

Seuratkaa saman määritelmän mukaista ostamista sekä toimenpiteen kustannuksia, katetta ja asiakkaiden palautetta. Pelkkä pisteytettyjen asiakkaiden ostaminen toimenpiteen jälkeen ei osoita lisähyötyä. Malli voi myös oppia aiemman palvelun ja yhteydenottojen vaikutuksia, joten dokumentoikaa toimintatavan muutokset.

Vectura Solutions Oy voi yhdistää asiakkuustiedot, rakentaa poistumakokeilun ja tuoda riskipisteet raportointiin tai sovittuun järjestelmään. Pilotti rajataan asiakaskannan, ostorytmin ja käytettävissä olevan seurannan perusteella.

Haluatteko tunnistaa hiipuvat asiakkuudet ajoissa?

Vectura Solutions Oy auttaa määrittelemään poistuman, arvioimaan aineiston ja toteuttamaan kokeilun, jonka tulokset voidaan yhdistää asiakkuustyöhön. Ensimmäinen keskustelu on maksuton.

Keskustellaan toteutuksesta

Keskustellaan seuraavasta kehitysaskeleesta

Kertokaa tavoitteistanne ja nykyisestä ympäristöstänne. Arvioimme yhdessä sopivan aloituskohdan ja yhteistyömallin. Ensimmäinen keskustelu on maksuton.