Kirjoittaja: Vectura Solutions Oy · Data-analytiikan ja raportoinnin toteutuksia vuodesta 2018.
Aihe: Koneoppiminen
Oppaan ydinkohdat
- Myynti kuvaa toteutuneita ostoja. Se ei yksin paljasta kysyntää, joka jäi toteutumatta esimerkiksi saatavuusongelman vuoksi.
- Ennuste arvioidaan myöhemmällä ajanjaksolla ja sitä verrataan yksinkertaiseen lähtötasoon, kuten viimeiseen tunnettuun viikkoon.
- Käyttäjä tarvitsee ennusteen lisäksi epävarmuuden, päivitysajankohdan ja tiedon siitä, mihin päätökseen ennustetta voi käyttää.
Mitä ennustetaan ja minkä päätöksen tueksi?
Aloittakaa päätöksestä, joka pitää tehdä ennen toteuman selviämistä. Hankinta tarvitsee arvion toimitusajan yli, työvuorosuunnittelu tulevien viikkojen kuormasta ja talous kuukausien myynnistä. Näihin ei välttämättä sovi sama aikajänne tai sama tarkkuustaso. Sopikaa myös, miten paljon liian pieni ja liian suuri arvio haittaavat toimintaa.
Valitkaa ennustettava suure täsmällisesti: tilatut kappaleet, toimitetut kappaleet, tilaukset vai myynti euroissa. Tilaushetki ja toimituspäivä kuvaavat eri asioita. Euromääräiseen myyntiin vaikuttavat määrän lisäksi hinnat, alennukset, palautukset ja valuutat. Käyttäkää samaa määritelmää lähdedatassa, arvioinnissa ja raportilla.
Ensimmäinen pilotti kannattaa rajata muutamaan riittävän säännölliseen tuoteryhmään tai palveluun. Vähän myyvien tuotteiden satunnaisia ostoja voi olla järkevämpää tarkastella viikkotasolla tai ryhmänä. Sopiva rajaus arvioidaan oman toiminnan perusteella.
Myyntihistoria ei aina kerro koko kysyntää
Jos tuotetta ei ole ollut saatavilla, pieni myyntimäärä voi johtua varaston loppumisesta. Pelkistä myyntiluvuista opetettu malli oppii tällöin toteutuneen myynnin tason. Se ei automaattisesti arvioi menetettyjä tilauksia. Liittäkää tarkasteluun saatavuus, sulkupäivät, valikoimamuutokset ja tunnetut kampanjat.
Erottakaa aito nollamyynti puuttuvasta aineistosta. Vahvistettu päivä ilman ostoja voi saada arvon nolla. Katkennut tiedonsiirto jätetään puutteeksi ja korjataan ennen mallintamista. Älkää täyttäkö kaikkia puuttuvia päiviä nolliksi vain saadaksenne yhtenäisen sarjan.
Tämän esimerkin kohteena on kirjattu kappalemyynti valituissa tuoteryhmissä, joiden historia ja saatavuus on tarkistettu. Se ei sisällä menetetyn kysynnän arviointia. Palautukset käsitellään erikseen, joten esimerkin kappalemäärät ovat kokonaislukuja ja vähintään nolla.
Valmistelkaa päiväkohtainen lähtötaulu
Oletamme valmiiksi rakennetun taulun oma-projekti.analytics.sales_daily. Siinä on yksi rivi tuoteryhmää ja paikallista myyntipäivää kohti. Kentät ovat series_id (STRING), sales_date (DATE), units (INT64) ja is_complete (BOOL). Viimeinen kenttä kertoo, että lähteen kyseisen päivän lataus on tarkistettu valmiiksi; se ei yksin vahvista datan liiketoiminnallista oikeellisuutta.
Rajataan harjoitus kahteen ennalta valittuun sarjaan, joiden tunnisteet ovat ryhma_a ja ryhma_b. Vaihtakaa ne, projektitunnus ja päivät omaan aineistoonne. Luokaa ml_demo-dataset lähteen kanssa samaan BigQuery-sijaintiin ja varmistakaa laskutus sekä tarvittavat käyttöoikeudet. CREATE OR REPLACE korvaa samannimisen taulun tai mallin, joten käyttäkää erillistä kokeiluympäristöä.
Jäädytämme historian ajalta 1.8.2025–31.8.2026. Tarkistukset vaativat kummaltakin sarjalta yhden hyväksytyn rivin joka päivälle. Vuoden mittainen historia on tämän harjoituksen rajaus, ei yleinen vähimmäisvaatimus tai lupaus riittävästä ennustetarkkuudesta.
CREATE OR REPLACE TABLE `oma-projekti.ml_demo.sales_daily_snapshot` AS
SELECT series_id, sales_date, units, is_complete
FROM `oma-projekti.analytics.sales_daily`
WHERE sales_date BETWEEN DATE '2025-08-01' AND DATE '2026-08-31'
AND series_id IN ('ryhma_a', 'ryhma_b');
ASSERT (
SELECT COUNT(DISTINCT series_id) = 2
FROM `oma-projekti.ml_demo.sales_daily_snapshot`
) AS 'Molemmat valitut sarjat tarvitaan';
ASSERT (
SELECT COUNTIF(units IS NULL OR units < 0
OR NOT COALESCE(is_complete, FALSE)) = 0
FROM `oma-projekti.ml_demo.sales_daily_snapshot`
) AS 'Tarkista maarat ja latauksen valmius';
ASSERT (
SELECT COUNT(*) = 0 FROM (
SELECT series_id
FROM `oma-projekti.ml_demo.sales_daily_snapshot`
GROUP BY series_id
HAVING COUNT(*) != DATE_DIFF(DATE '2026-08-31', DATE '2025-08-01', DAY) + 1
OR COUNT(DISTINCT sales_date) != COUNT(*)
)
) AS 'Jokaiselle sarjalle tarvitaan yksi rivi joka paivalle';Opettakaa kokeilumalli ennen testijaksoa
Jätämme viimeiset 28 päivää, 4.–31.8.2026, arviointiin. Mallille annetaan vain sitä edeltävä historia. ARIMA_PLUS käyttää tässä kunkin sarjan aiempia arvoja; sarjat erotellaan TIME_SERIES_ID_COL-asetuksella. Kampanjabudjetti tai tuleva hinnanmuutos ei ole tämän mallin syöte.
Koodi luo kaksi erillistä aikasarjaennustetta samaan BigQuery ML -malliin. Arvioikaa tulokset sarjoittain: hyvä yhteistulos voi peittää yhden tärkeän tuoteryhmän suuren virheen. Säilyttäkää myös kuvaus siitä, mitä lähteen korjauksia oli saatavilla aineistoa jäädytettäessä.
CREATE OR REPLACE MODEL `oma-projekti.ml_demo.sales_arima_backtest`
OPTIONS (
MODEL_TYPE = 'ARIMA_PLUS',
TIME_SERIES_TIMESTAMP_COL = 'sales_date',
TIME_SERIES_DATA_COL = 'units',
TIME_SERIES_ID_COL = 'series_id',
DATA_FREQUENCY = 'DAILY',
HORIZON = 28,
AUTO_ARIMA = TRUE,
AUTO_ARIMA_MAX_ORDER = 2
) AS
SELECT series_id, sales_date, units
FROM `oma-projekti.ml_demo.sales_daily_snapshot`
WHERE sales_date <= DATE '2026-08-03';Verratkaa ennustetta viimeiseen tunnettuun viikkoon
Vertailuennuste toistaa opetuksen viimeisen viikon 28.7.–3.8.2026 viikonpäiväkohtaiset myynnit koko testijaksolle. Se käyttää vain ennustushetkellä tunnettua tietoa. Jos neljän viikon ennustetta verrattaisiin aina seitsemän päivää aiempaan toteumaan, myöhemmille testipäiville päätyisi testijakson aikana selvinnyttä tietoa.
Alla MAE kertoo keskimääräisen absoluuttisen virheen kappaleina. WAPE suhteuttaa absoluuttisten virheiden summan toteutuneeseen määrään; nollasummalla tulos on NULL. Tarkistakaa, että forecast_days on 28 jokaiselle sarjalle. Puuttuvia ennusteita ei saa hyväksyä sen perusteella, että jäljelle jääneiden päivien keskiarvo näyttää hyvältä.
CREATE OR REPLACE TABLE `oma-projekti.ml_demo.sales_backtest_forecast` AS
SELECT *
FROM ML.FORECAST(
MODEL `oma-projekti.ml_demo.sales_arima_backtest`,
STRUCT(28 AS horizon, 0.95 AS confidence_level)
);
SELECT
a.series_id,
COUNT(*) AS actual_days,
COUNT(f.forecast_value) AS forecast_days,
AVG(ABS(a.units - f.forecast_value)) AS model_mae,
AVG(ABS(a.units - b.units)) AS baseline_mae,
SAFE_DIVIDE(SUM(ABS(a.units - f.forecast_value)), SUM(a.units)) AS model_wape
FROM `oma-projekti.ml_demo.sales_daily_snapshot` AS a
LEFT JOIN `oma-projekti.ml_demo.sales_backtest_forecast` AS f
ON a.series_id = f.series_id
AND a.sales_date = DATE(f.forecast_timestamp)
LEFT JOIN `oma-projekti.ml_demo.sales_daily_snapshot` AS b
ON a.series_id = b.series_id
AND EXTRACT(DAYOFWEEK FROM a.sales_date) = EXTRACT(DAYOFWEEK FROM b.sales_date)
AND b.sales_date BETWEEN DATE '2026-07-28' AND DATE '2026-08-03'
WHERE a.sales_date BETWEEN DATE '2026-08-04' AND DATE '2026-08-31'
GROUP BY a.series_id;Tarkastelkaa myös yli- ja aliennustamista, kampanjapäiviä ja ennustevälien osuvuutta. Kappalemäärän mallista voi tulla negatiivisia arvoja. Jos tuotantokäyttö edellyttää niiden rajaamista, määritelkää käsittelysääntö ja arvioikaa samalla tavalla käsitelty ennuste jo testissä.
Yksi kuukausi on ensimmäinen tarkistus. Toistakaa arviointi useilla ajankohdilla ja säilyttäkää viimeinen jakso lopulliseen testiin, jos valitsette menetelmää tai asetuksia aiempien testitulosten perusteella. Jälkikäteen korjattu historia voi antaa optimistisemman kuvan kuin alun perin käytettävissä ollut aineisto.
Muodostakaa hyväksytystä mallista raportoitava ennuste
Kun arviointi ja rajaukset on hyväksytty, opetetaan uusi malli koko jäädytetyllä historialla. Se tuottaa tässä syyskuun 2026 ensimmäisten 28 päivän ennusteen. Mallin nimen päiväys ilmaisee historian päättymisen. Vaihtakaa päivät ja versiot yhdessä, kun siirrytte omaan aineistoon.
Tallennamme piste-ennusteen lisäksi päiväkohtaisen ennustevälin, historian viimeisen päivän ja ajankohdan, jolloin tulos kirjoitettiin tauluun. Muodostusajankohta ei ole sama kuin lähdeaineiston tuoreus. Ennusteväli kuvaa mallin epävarmuutta omilla oletuksillaan; se ei takaa toteuman pysymistä rajojen sisällä.
CREATE OR REPLACE MODEL `oma-projekti.ml_demo.sales_arima_20260831`
OPTIONS (
MODEL_TYPE = 'ARIMA_PLUS',
TIME_SERIES_TIMESTAMP_COL = 'sales_date',
TIME_SERIES_DATA_COL = 'units',
TIME_SERIES_ID_COL = 'series_id',
DATA_FREQUENCY = 'DAILY',
HORIZON = 28,
AUTO_ARIMA = TRUE,
AUTO_ARIMA_MAX_ORDER = 2
) AS
SELECT series_id, sales_date, units
FROM `oma-projekti.ml_demo.sales_daily_snapshot`;
CREATE OR REPLACE TABLE `oma-projekti.ml_demo.sales_forecast_current` AS
SELECT
series_id,
DATE(forecast_timestamp) AS forecast_date,
forecast_value AS forecast_units,
prediction_interval_lower_bound AS lower_units,
prediction_interval_upper_bound AS upper_units,
confidence_level,
DATE '2026-08-31' AS trained_through,
CURRENT_TIMESTAMP() AS generated_at,
'sales_arima_20260831' AS model_version
FROM ML.FORECAST(
MODEL `oma-projekti.ml_demo.sales_arima_20260831`,
STRUCT(28 AS horizon, 0.95 AS confidence_level)
);Kampanjat, hinnat ja hankintapäätökset
Jos kysyntään vaikuttavat tunnetut kampanjat tai hinnat, seuraava kokeilu voi käyttää niitä lisämuuttujina. BigQuery ML:n ARIMA_PLUS_XREG on tähän yksi vaihtoehto. Myös tulevien ennustepäivien lisämuuttujat pitää tällöin toimittaa mallille. Toteutunutta kampanjamyyntiä ei voi käyttää tulevan kampanjan syötteenä.
Suunniteltu budjetti tai hinta on skenaario, joka voi muuttua. Tallentakaa oletukset ennusteen yhteyteen. Mallin arvio hinnan ja myynnin yhteydestä ei yksin kerro, paljonko hinnan muuttaminen aiheuttaisi lisämyyntiä.
Ennustetta ei kopioida suoraan ostotilaukseksi. Hankinta huomioi lisäksi nykyisen varaston, avoimet tilaukset, toimitusajan ja sovitun palvelutavoitteen. Päivittäisiä ennustevälien rajoja ei voi sellaisenaan summata koko hankintajakson vastaavaksi ennusteväliksi, koska päivien virheet voivat riippua toisistaan.
Ajastus ja liiketoimintahyödyn seuranta
Tuotannossa lähteen valmius tarkistetaan ennen laskentaa. Uusi data ei päivitä opetettua ARIMA_PLUS-mallia itsestään. Sovitaan mallin uudelleenopetus, ennustehorisontti ja se, miten uusi tulos hyväksytään raportille. Säilyttäkää aiemmat ennusteversiot ennen nykyisen taulun korvaamista, jotta arviointi ei perustu jälkikäteen muuttuneeseen ennusteeseen.
Seuratkaa teknisen toiminnan lisäksi ennustevirhettä ja suunnittelun tuloksia. Esimerkiksi saatavuus, kiireelliset lisähankinnat tai suunnitteluun käytetty aika voivat kertoa hyödystä. Vertailussa huomioidaan myös valikoiman, hintojen ja toimintatapojen muutokset.
Vectura Solutions Oy voi yhdistää myynti- ja saatavuustiedot, toteuttaa rajatun ennustekokeilun ja tuoda hyväksytyn tuloksen BI-raportointiin. Toimituksen sisältö ja onnistumisen arviointi sovitaan oman suunnittelutarpeenne perusteella.
Tarvitsetteko ennusteen hankinnan tai kapasiteetin suunnitteluun?
Vectura Solutions Oy auttaa rajaamaan ennustettavan tarpeen, tarkistamaan aineiston ja vertaamaan mallia nykyiseen toimintatapaan. Ensimmäinen keskustelu on maksuton.
Keskustellaan toteutuksesta