{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Päivitetty 2025-08-26 / Aki Taanila\n" ] } ], "source": [ "from datetime import datetime\n", "print(f'Päivitetty {datetime.now().date()} / Aki Taanila')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Lehtikauppiaan ongelma\n", "\n", "Lehtikauppias on tilastoinut iltapäivälehden kysyntää. Kysyntä vaihtelee jonkin verran viikonpäivän \n", "mukaan. Lehtikauppias on laskenut tilaston perusteella kunkin viikonpäivän kysynnälle keskiarvon \n", "ja keskihajonnan. Tietyn viikonpäivän kysynnän voidaan olettaa noudattavan normaalijakaumaa.\n", "\n", "Lehtikauppiaan täytyy ilmoittaa etukäteen tilattavien lehtien lukumäärä. Lehtikauppias pyrkii\n", "tietenkin tyydyttämään kysynnän mahdollisimman hyvin ja toisaalta hankkimaan itselleen \n", "mahdollisimman korkean voiton. Simulointimallissa simuloidaan kysynnän määriä normaalijakaumasta ja lasketaan simulaatiokierrosten tilastolliset tunnusluvut voitolle ja puuttuvien lehtien määrälle.\n", "\n", "Lehtikauppias voisi solmia nk. palautussopimuksen, jolloin myymättömistä lehdistä saa täyden \n", "hyvityksen lehtitalolta. Tässä tapauksessa lehden hinta on kauppiaalle korkeampi. Simulointimallissa on laskettu voiton tunnusluvut myös palautussopimusta käyttäen." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(Palautus, 510) 331.348433\n", "(Ei palautusta, 510) 365.813892\n", "(Ilman lehteä, 510) 25.882100\n", "(Palautus, 520) 334.866469\n", "(Ei palautusta, 520) 368.184756\n", "(Ilman lehteä, 520) 19.023700\n", "(Palautus, 530) 338.444001\n", "(Ei palautusta, 530) 370.651524\n", "(Ilman lehteä, 530) 15.274600\n", "(Palautus, 540) 341.452100\n", "(Ei palautusta, 540) 372.200400\n", "(Ilman lehteä, 540) 12.062500\n", "(Palautus, 550) 343.010587\n", "(Ei palautusta, 550) 371.412588\n", "(Ilman lehteä, 550) 8.725700\n", "(Palautus, 560) 344.390988\n", "(Ei palautusta, 560) 370.337712\n", "(Ilman lehteä, 560) 6.315000\n", "(Palautus, 570) 345.762277\n", "(Ei palautusta, 570) 369.248148\n", "(Ilman lehteä, 570) 4.274200\n", "(Palautus, 580) 346.699674\n", "(Ei palautusta, 580) 367.459176\n", "(Ilman lehteä, 580) 2.655400\n", "(Palautus, 590) 347.688393\n", "(Ei palautusta, 590) 365.752932\n", "(Ilman lehteä, 590) 1.905100\n", "dtype: float64" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "TOISTOJA = 10000 #simulointikierrosten lukumäärä\n", "KESKIARVO = 520 #päivämyynnin keskiarvo\n", "KESKIHAJONTA = 50 #päivämyynnin keskihajonta\n", "OSTOHINTA_EI_PALAUTUSTA = 0.25\n", "OSTOHINTA_PALAUTUS = 0.33\n", "MYYNTIHINTA = 1\n", "yhteenveto = pd.DataFrame()\n", "\n", "# Alustan satunnaislukugeneraattorin:\n", "rng = np.random.default_rng()\n", "\n", "for tilaus in range(510, 600, 10):\n", " kysyntä = rng.normal(loc = KESKIARVO, scale = KESKIHAJONTA, size = TOISTOJA)\n", " kysyntä = np.round(kysyntä)\n", "\n", " myynti = (kysyntä > tilaus) * tilaus + (kysyntä <= tilaus) * kysyntä\n", "\n", " voitto_palautus = myynti * (MYYNTIHINTA-OSTOHINTA_PALAUTUS)\n", "\n", " voitto_ei_palautusta = myynti * (MYYNTIHINTA - OSTOHINTA_EI_PALAUTUSTA) - (tilaus-myynti) * OSTOHINTA_PALAUTUS \n", " \n", " ilman_lehteä = kysyntä - myynti\n", "\n", " yhteenveto['Palautus', tilaus] = voitto_palautus\n", " yhteenveto['Ei palautusta', tilaus] = voitto_ei_palautusta\n", " yhteenveto['Ilman lehteä', tilaus] = ilman_lehteä \n", "\n", "yhteenveto.mean() #voittojen ja ilman lehteä jääneiden keskiarvot eri tapauksissa" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
| \n", " | ('Palautus', 510) | \n", "('Ei palautusta', 510) | \n", "('Ilman lehteä', 510) | \n", "('Palautus', 520) | \n", "('Ei palautusta', 520) | \n", "('Ilman lehteä', 520) | \n", "('Palautus', 530) | \n", "('Ei palautusta', 530) | \n", "('Ilman lehteä', 530) | \n", "('Palautus', 540) | \n", "('Ei palautusta', 540) | \n", "('Ilman lehteä', 540) | \n", "('Palautus', 550) | \n", "('Ei palautusta', 550) | \n", "('Ilman lehteä', 550) | \n", "('Palautus', 560) | \n", "('Ei palautusta', 560) | \n", "('Ilman lehteä', 560) | \n", "('Palautus', 570) | \n", "('Ei palautusta', 570) | \n", "('Ilman lehteä', 570) | \n", "('Palautus', 580) | \n", "('Ei palautusta', 580) | \n", "('Ilman lehteä', 580) | \n", "('Palautus', 590) | \n", "('Ei palautusta', 590) | \n", "('Ilman lehteä', 590) | \n", "
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "10000 | \n", "
| mean | \n", "331 | \n", "366 | \n", "26 | \n", "335 | \n", "368 | \n", "19 | \n", "338 | \n", "371 | \n", "15 | \n", "341 | \n", "372 | \n", "12 | \n", "343 | \n", "371 | \n", "9 | \n", "344 | \n", "370 | \n", "6 | \n", "346 | \n", "369 | \n", "4 | \n", "347 | \n", "367 | \n", "3 | \n", "348 | \n", "366 | \n", "2 | \n", "
| std | \n", "17 | \n", "28 | \n", "33 | \n", "19 | \n", "31 | \n", "28 | \n", "21 | \n", "35 | \n", "25 | \n", "24 | \n", "38 | \n", "23 | \n", "26 | \n", "42 | \n", "19 | \n", "28 | \n", "45 | \n", "17 | \n", "29 | \n", "47 | \n", "13 | \n", "30 | \n", "48 | \n", "10 | \n", "31 | \n", "50 | \n", "9 | \n", "
| min | \n", "218 | \n", "184 | \n", "0 | \n", "218 | \n", "179 | \n", "0 | \n", "216 | \n", "174 | \n", "0 | \n", "211 | \n", "162 | \n", "0 | \n", "227 | \n", "185 | \n", "0 | \n", "228 | \n", "182 | \n", "0 | \n", "226 | \n", "177 | \n", "0 | \n", "226 | \n", "173 | \n", "0 | \n", "221 | \n", "162 | \n", "0 | \n", "
| 25% | \n", "326 | \n", "357 | \n", "0 | \n", "326 | \n", "353 | \n", "0 | \n", "326 | \n", "351 | \n", "0 | \n", "328 | \n", "350 | \n", "0 | \n", "326 | \n", "344 | \n", "0 | \n", "326 | \n", "340 | \n", "0 | \n", "326 | \n", "337 | \n", "0 | \n", "326 | \n", "335 | \n", "0 | \n", "326 | \n", "331 | \n", "0 | \n", "
| 50% | \n", "342 | \n", "382 | \n", "10 | \n", "348 | \n", "389 | \n", "0 | \n", "348 | \n", "387 | \n", "0 | \n", "349 | \n", "384 | \n", "0 | \n", "349 | \n", "381 | \n", "0 | \n", "348 | \n", "377 | \n", "0 | \n", "348 | \n", "374 | \n", "0 | \n", "348 | \n", "370 | \n", "0 | \n", "349 | \n", "368 | \n", "0 | \n", "
| 75% | \n", "342 | \n", "382 | \n", "45 | \n", "348 | \n", "390 | \n", "32 | \n", "355 | \n", "398 | \n", "24 | \n", "362 | \n", "405 | \n", "16 | \n", "368 | \n", "412 | \n", "4 | \n", "371 | \n", "414 | \n", "0 | \n", "371 | \n", "410 | \n", "0 | \n", "371 | \n", "406 | \n", "0 | \n", "372 | \n", "405 | \n", "0 | \n", "
| max | \n", "342 | \n", "382 | \n", "202 | \n", "348 | \n", "390 | \n", "176 | \n", "355 | \n", "398 | \n", "155 | \n", "362 | \n", "405 | \n", "179 | \n", "368 | \n", "412 | \n", "154 | \n", "375 | \n", "420 | \n", "137 | \n", "382 | \n", "428 | \n", "138 | \n", "389 | \n", "435 | \n", "119 | \n", "395 | \n", "442 | \n", "142 | \n", "