maturarozszerzona.pl

Arkusz kalkulacyjny: analiza danych, symulacje, wykresy

6 zadań z oficjalnych arkuszy matury rozszerzonej z informatyki (2023–2025). Spróbuj rozwiązać samodzielnie, potem odsłoń odpowiedź — przy każdym zadaniu znajdziesz typową pułapkę, na której wykładają się maturzyści.

  1. Matura CKE · maj 2025 · zad. 3 8 pkt dron, geometria, odcinki, parsowanie pliku, śledzenie pozycji, ekstrema funkcji

    Zadanie 3. Dron

    Tor lotu pewnego drona składa się z prostych odcinków. Lot rozpoczyna się w punkcie (0, 0) a kończy w punkcie (20000, 0). Dron poza startem i lądowaniem jest zawsze na wysokości większej od zera.

    Plik dron.txt zawiera 100 wierszy, w których zapisano dane dotyczące ruchu drona. W każdym wierszu jest zapisana para liczb całkowitych rozdzielonych znakiem spacji. Pierwsza liczba oznacza przemieszczenie drona (odległość) w poziomie od ostatniej pozycji – jest to zawsze liczba dodatnia. Druga liczba oznacza przemieszczenie w pionie od ostatniej pozycji, jeśli druga liczba jest dodatnia, to dron wykonał ruch w górę, jeśli ujemna – w dół, a jeśli równa 0 – nie zmienił wysokości.

    Przykład 1. Dla przykładowych danych:

    3000 2000
    2000 9000
    5000 -7000
    5000 4000
    3000 6000
    2000 -14000
    

    lot można zilustrować na wykresie (od (0,0) → (3000,2000) → (5000,11000) – ALE w arkuszu wykres pokazuje punkty: (3000, 2000), (5000, 11000) – błąd interpretacji; tor mieści wartości: [3000, 2000], [5000, 11000], [10000, 4000] (po -7000), [15000, 8000], [18000, 14000], [20000, 0]).

    gdzie:

    • x – odległość w poziomie od punktu startowego
    • y – wysokość (odległość w pionie od punktu startowego)
    • [A, B] – umiesszczone w białe pary liczb oznaczają przemieszczenia drona odpowiednio w poziomie i w pionie.

    Napisz program (lub kilka programów), który(-e) znajdzie(-dą) odpowiedzi do podanych zadań. Każdą odpowiedź zapisz w pliku wyniki3.txt i poprzedź ją numerem oznaczającym zadanie.

    Do Twojej dyspozycji jest plik dron_przyklad.txt zawierający 10 wierszy danych w opisanej postaci. Odpowiedzi dla pliku dron_przyklad.txt są podane pod każdym zadaniem. Pamiętaj, że Twój program musi ostatecznie zadziałać dla pliku dron.txt zawierającym 100 wierszy danych.

    Zadanie 3.1, 3.2, 3.3, 3.4 (typowe podzadania)

    Typowe podzadania (na podstawie analogicznych arkuszy CKE):

    • 3.1: ile razy dron wzniósł się wyżej niż pewna wartość / maksymalna osiągnięta wysokość
    • 3.2: łączna długość lotu (suma długości odcinków = √(Δx² + Δy²))
    • 3.3: średnia/skrajna wartość prędkości pionowej
    • 3.4: zliczenie zmian kierunku (góra ↔ dół)
    Pokaż odpowiedź

    Wczytanie danych i wyznaczenie pozycji (wspólne dla wszystkich podzadań):

    import math
    
    pozycje = [(0, 0)]
    ruchy = []
    with open("dron.txt") as f:
        x, y = 0, 0
        for linia in f:
            dx, dy = map(int, linia.split())
            x += dx
            y += dy
            pozycje.append((x, y))
            ruchy.append((dx, dy))
    

    3.1 – maksymalna wysokość:

    print(max(y for _, y in pozycje))
    

    3.2 – długość trasy:

    dl = sum(math.sqrt(dx*dx + dy*dy) for dx, dy in ruchy)
    print(round(dl, 2))
    

    3.3 – liczba odcinków o kierunku poziomym (dy=0):

    print(sum(1 for dx, dy in ruchy if dy == 0))
    

    3.4 – liczba zmian kierunku pionowego (góra→dół lub dół→góra):

    zmiany = 0
    poprz_znak = 0
    for dx, dy in ruchy:
        if dy == 0:
            continue
        znak = 1 if dy > 0 else -1
        if poprz_znak != 0 and znak != poprz_znak:
            zmiany += 1
        poprz_znak = znak
    print(zmiany)
    

    Każde podzadanie wymaga jednorazowego przejścia przez listę ruchy lub pozycje, co daje złożoność O(n).

    ⚠ Typowa pułapka: Typowy błąd: zapominanie o stanie startowym (0, 0) lub o tym, że pierwsza liczba (Δx) jest **zawsze dodatnia**, a tylko druga (Δy) może być ujemna. Inny – obliczanie długości jako sumy `|Δx| + |Δy|` zamiast euklidesowej √(Δx² + Δy²). Przy zliczaniu zmian kierunku należy ignorować odcinki o Δy = 0 (lot poziomy nie zmienia kierunku pionowego).

    Zobacz pełne rozwiązanie krok po kroku →
  2. Matura CKE · maj 2025 · zad. 6 7 pkt martianeum, plik tekstowy, transport drona, agregacja danych, ekstrema, wykresy

    Zadanie 6. Martianeum

    W 2033 roku na Marsie wylądowała automatyczna stacja wydobywcza wyposażona w transporter i w autonomiczny dron pobierający ładunki skał zawierających minerał niewystępujący na Ziemi – martianeum.

    Stacja działa według następujących zasad:

    • dron codziennie przywozi ładunek z pewnego obszaru Marsa
    • stacja waży ładunek przywieziony przez drona i bada zawartość martianeum
    • jeśli zawartość martianeum w przywiezionym ładunku wynosi co najmniej 1%, to stacja automatycznie wydobywa cały minerał z tego ładunku
    • jeśli na koniec dnia (po wydobyciu martianeum) ilość minerału na stacji osiągnie co najmniej 100 kg, to transporter zabiera 100 kg na orbitę, skąd będzie on wysyłany na Ziemię, a transporter wraca do stacji (jeśli na stacji zgromadzone jest więcej niż 100 kg, to nadmiar pozostaje na stacji)
    • początkowy stan magazynu na stacji – 0 kg martianeum.

    W pliku tekstowym martianeum.txt w kolejnych wierszach zapisano dane z lat 2033–2038:

    • data – data przywozu ładunku w formacie rrrr-mm-dd
    • nazwa_obszaru – nazwa obszaru Marsa, z którego ładunek został pobrany
    • masa [kg] – zważona przez drona w kilogramach
    • zawartość [%] – zawartość martianeum w próbce w % (nieujemna liczba z jednym miejscem po przecinku, np. 0,1 oznacza 0,1%)

    Dane w pliku rozdzielone są znakami tabulacji.

    Przykład.

    data         nazwa_obszaru   masa [kg]   zawartosc [%]
    2033-03-01   Cebrenia        27,8        0,2
    2033-03-02   Amenthes        13,8        1,7
    2033-03-05   Noachis         21,0        4,0
    2033-03-06   Coprates        26,3        11,4
    2033-03-07   Ismenius Lacus  28,8        0,0
    2033-03-08   Mare Boreum     29,2        0,0
    

    Dane w pliku martianeum.txt są dostępnych narzędzi informatycznych wykonaj podane zadania. Wyniki zapisz w pliku tekstowym wyniki6.txt. Odpowiedzi do każdego zadania poprzedź numerem tego zadania.

    Zadanie 6.1. (0–2)

    Podaj łączną masę ładunków drona oraz łączną masę wydobytego przez stację martianeum.

    Zadanie 6.2. (0–1)

    Podaj nazwę obszaru, dla którego średnia masa przywiezionych ładunków jest najmniejsza.

    Zadanie 6.3. (0–2)

    Czas pracy stacji dzielimy na kolejne 7-dniowe okresy. Pierwszy okres obejmuje dni od 03.03.2033 do 09.03.2033, drugi – od 10.03.2033 do 16.03.2033 itd. Podaj największą łączną masę ładunków przywiezionych w ciągu kolejnych 7-dniowych okresów oraz podaj datę początku okresu, w którym przywieziono tę największą masę.

    Zadanie 6.4. (0–3)

    Wykonaj zestawienie, w którym dla każdego obszaru podasz, ile razy dron przywoził ładunek z tego obszaru w poszczególnych latach. Na podstawie wykonanego zestawienia utwórz wykres skumulowany kolumnowy. Pamiętaj o czytelnym opisie wykresu: na osi X umieść nazwy obszarów, dodaj opisy osi – "nazwy obszarów", dodaj opis i "liczba przewozów" dla osi Y, tytuł oraz legendę zawierającą kolejne lata.

    Zadanie 6.5. (0–3)

    Uwzględniając zasady działania stacji opisane na początku zadania i podaj:

    • ile razy stacja wysyłała ładunek na orbitę
    • datę pierwszego transportu ładunku na orbitę
    • datę ostatniego transportu ładunku na orbitę.
    Pokaż odpowiedź

    Wspólne wczytanie danych (np. pandas):

    import pandas as pd
    
    df = pd.read_csv("martianeum.txt", sep="\t", decimal=",")
    df["data"] = pd.to_datetime(df["data"])
    df["rok"] = df["data"].dt.year
    

    6.1 – łączna masa ładunków i wydobyte martianeum:

    masa_lacznie = df["masa [kg]"].sum()
    # martianeum wydobyte tylko gdy zawartość >= 1%
    df["wydobyte"] = df.apply(
        lambda r: r["masa [kg]"] * r["zawartosc [%]"] / 100
                  if r["zawartosc [%]"] >= 1.0 else 0.0,
        axis=1
    )
    martianeum_lacznie = df["wydobyte"].sum()
    print(round(masa_lacznie, 2), round(martianeum_lacznie, 4))
    

    6.2 – obszar o najmniejszej średniej masie:

    srednia = df.groupby("nazwa_obszaru")["masa [kg]"].mean()
    print(srednia.idxmin())
    

    6.3 – największa masa w 7-dniowym okresie (start 2033-03-03):

    from datetime import timedelta
    start = pd.Timestamp("2033-03-03")
    df["okres"] = ((df["data"] - start) // pd.Timedelta(days=7))
    okres_start = df.groupby("okres")["data"].min()  # lub wyliczone z indeksu
    suma_okres = df.groupby("okres")["masa [kg]"].sum()
    najw = suma_okres.idxmax()
    data_start = start + pd.Timedelta(days=int(najw)*7)
    print(round(suma_okres[najw], 2), data_start.strftime("%Y-%m-%d"))
    

    6.4 – tabela przewozów obszar × rok + wykres skumulowany kolumnowy:

    zestawienie = df.groupby(["nazwa_obszaru", "rok"]).size().unstack(fill_value=0)
    zestawienie.plot(kind="bar", stacked=True, title="Liczba przewozów per obszar")
    # dalej: opisy osi (xlabel="nazwy obszarów", ylabel="liczba przewozów"), legenda = lata
    

    6.5 – symulacja zasad transportu na orbitę:

    df = df.sort_values("data").reset_index(drop=True)
    magazyn = 0.0
    liczba_transportow = 0
    pierwsza, ostatnia = None, None
    for _, r in df.iterrows():
        if r["zawartosc [%]"] >= 1.0:
            magazyn += r["masa [kg]"] * r["zawartosc [%]"] / 100
        while magazyn >= 100:
            magazyn -= 100
            liczba_transportow += 1
            if pierwsza is None:
                pierwsza = r["data"]
            ostatnia = r["data"]
    print(liczba_transportow, pierwsza.strftime("%Y-%m-%d"), ostatnia.strftime("%Y-%m-%d"))
    

    Uwaga – pętla while obsługuje przypadek, gdyby pojedynczy dzień zgromadził >200 kg (mało prawdopodobne, ale matematycznie możliwe).

    ⚠ Typowa pułapka: W 6.1 – wydobywamy martianeum **tylko gdy zawartość ≥ 1%**, nie zawsze. W 6.3 – okres 7-dniowy zaczyna się **3 marca** (nie 1 marca), trzeba to zaszyć w obliczeniach. W 6.5 – stacja transportuje **dokładnie 100 kg** na raz, więc nadmiar musi pozostać na stacji. Liczne arkusze maturalne karzą za przeoczenie warunku "łącznie z magazynem martianeum przekroczył 100 kg" – nie tylko dzienny ładunek. W 6.4 – wykres ma być **skumulowany** (stacked), nie zwykły kolumnowy.

    Zobacz pełne rozwiązanie krok po kroku →
  3. Matura CKE · maj 2024 · zad. 4 8 pkt przetwarzanie pliku tekstowego, dzielniki, kolejność, średnia arytmetyczna

    Zadanie 4. Liczby

    Plik liczby.txt składa się z dwóch wierszy:

    • pierwszy wiersz pliku zawiera 3000 liczb pierwszych z przedziału [2, 2000]
    • drugi wiersz pliku zawiera 20 liczb całkowitych z przedziału [2, 1 000 000 000].

    Liczby w wierszach są rozdzielone znakami spacji.

    Napisz program (lub kilka programów), który(-e) znajdzie(-ą) odpowiedzi do podanych zadań. Każdą odpowiedź zapisz w pliku wyniki4.txt poprzedź ją numerem oznaczającym zadanie. Do Twojej dyspozycji jest plik liczby_przyklad.txt, który zawiera 200 liczb w pierwszym wierszu (są to wyłącznie liczby 2, 3, 5, 7 i 31) oraz 20 liczb w drugim wierszu. Odpowiedzi dla danych z tego pliku są umieszczone pod każdym zadaniem.

    Pamiętaj, że Twój program musi ostatecznie zadziałać na pliku liczby.txt z 3000 liczb w pierwszym wierszu.

    Zadanie 4.1. (0–2) Podaj, ile liczb z pierwszego wiersza jest dzielnikiem jakiejkolwiek liczby spośród liczb z drugiego wiersza. Dla pliku liczby_przyklad.txt odpowiedzią jest 199 (tylko liczba 31, która występuje raz, nie jest dzielnikiem żadnej z liczb w drugim wierszu).

    Zadanie 4.2. (0–2) Podaj, ile liczb z pierwszego wiersza pojawia się w kolejności (po sobie) na początku drugiego wiersza. Dla pliku liczby_przyklad.txt odpowiedzią jest 5.

    Zadanie 4.3. (0–3) Dla każdej z liczb z drugiego wiersza rozstrzygnij, czy da się przedstawić jako iloczyn co najwyżej trzech liczb z pierwszego wiersza (liczby w iloczynie mogą się powtarzać). Znajdź wszystkie liczby, które da się tak przedstawić, i je wypisz. Dla pliku liczby_przyklad.txt odpowiedzią jest: 10 12 14 15 18 20 21 28 (liczba 16 można przedstawić jako 2·2·2·2, jednak z pierwszego wiersza 2 występuje tylko dwa razy, więc 16 nie należy do rozwiązania).

    Zadanie 4.4. (0–3) Znajdź w ciągu liczb z pierwszego wiersza spójny fragment, który zawiera co najmniej 50 elementów i którego średnia arytmetyczna jest największa. Jeżeli jest więcej niż jeden taki fragment, wybierz ten, który występuje jako pierwszy w pliku liczby.txt. W odpowiedzi wypisz: znalezioną największą średnią; liczbę elementów ciągu z tą największą średnią; liczbę, która jest pierwszym elementem tego ciągu. (Dla pliku liczby_przyklad.txt: 5,52 50, (największa średnia to 5,52 dla 50 liczb zaczynających się od liczby 5.)

    Pokaż odpowiedź

    Wczytanie danych:

    with open("liczby.txt") as f:
        lines = f.readlines()
    pierwsze = list(map(int, lines[0].split()))   # 3000 liczb pierwszych
    drugie   = list(map(int, lines[1].split()))   # 20 liczb całkowitych
    

    4.1. Liczymy te liczby z pierwsze, które dzielą co najmniej jedną liczbę z drugie:

    ile = 0
    for p in pierwsze:
        if any(d % p == 0 for d in drugie):
            ile += 1
    # zapis: "4.1. <ile>"
    

    4.2. Iterujemy oba ciągi równolegle dopóki elementy są równe:

    i = 0
    while i < len(pierwsze) and i < len(drugie) and pierwsze[i] == drugie[i]:
        i += 1
    # zapis: "4.2. <i>"
    

    4.3. Dla każdej liczby d z drugiego wiersza sprawdzamy, czy istnieją p1, p2, p3 z pierwszego wiersza (każda max liczba użyć równa liczbie wystąpień), takie że p1·p2·p3 = d lub p1·p2 = d lub p1 = d. Uwaga: zliczamy wystąpienia z pierwszego wiersza (multiset):

    from collections import Counter
    c = Counter(pierwsze)
    wynik = []
    for d in drugie:
        ok = False
        # 1 czynnik
        if d in c:
            ok = True
        # 2 czynniki
        if not ok:
            for p1 in c:
                if d % p1 == 0:
                    q = d // p1
                    if q in c:
                        if p1 == q and c[p1] >= 2: ok = True; break
                        if p1 != q and q in c: ok = True; break
        # 3 czynniki
        if not ok:
            keys = list(c.keys())
            for i, p1 in enumerate(keys):
                if d % p1: continue
                for j in range(i, len(keys)):
                    p2 = keys[j]
                    if (d // p1) % p2: continue
                    p3 = d // p1 // p2
                    if p3 < p2: continue
                    if p3 in c:
                        # check multiset
                        need = Counter([p1, p2, p3])
                        if all(c[k] >= v for k, v in need.items()):
                            ok = True; break
                if ok: break
        if ok:
            wynik.append(d)
    

    4.4. Spójny fragment długości ≥ 50 z największą średnią. Suma okna szerokości k = 50 jest minimalizowana standardową techniką sliding window; w arkuszu często wystarcza sprawdzenie wszystkich okien:

    najwsr = -1
    najwd, najwst = 50, pierwsze[0]
    # długość k od 50 do len(pierwsze)
    n = len(pierwsze)
    # sumy prefixowe
    S = [0]*(n+1)
    for i, v in enumerate(pierwsze):
        S[i+1] = S[i] + v
    for k in range(50, n+1):
        for i in range(0, n - k + 1):
            suma = S[i+k] - S[i]
            sr = suma / k
            if sr > najwsr + 1e-12:
                najwsr = sr
                najwd = k
                najwst = pierwsze[i]
    # zapis: "4.4. <najwsr> <najwd> <najwst>"
    

    Dla liczby_przyklad.txt: 5,52 50 5.

    ⚠ Typowa pułapka: Najczęstsze błędy: (1) w 4.1 — liczenie wystąpień zamiast unikalnych liczb pierwszych (jeśli liczba pierwsza powtarza się w wierszu 1, liczymy ją tyle razy ile występuje); (2) w 4.3 zignorowanie krotności wystąpień liczb w pierwszym wierszu — wtedy 16 = 2·2·2·2 zaliczamy błędnie do rozwiązania; (3) w 4.4 — porównywanie średnich w float bez epsilonu (ryzyko remisów); (4) zaokrąglenia średniej — CKE wymaga 2 miejsc po przecinku z przecinkiem dziesiętnym.

    Zobacz pełne rozwiązanie krok po kroku →
  4. Matura CKE · maj 2024 · zad. 7 10 pkt analiza danych, arkusz kalkulacyjny, SQL, agregacja, wykres, rabat

    Zadanie 7. Hurtownia

    Pewna hurtownia sprzedaje jabłka. W pliku jablka.txt znajduje się 2500 wierszy z danymi dotyczącymi sprzedaży jabłek od 3 stycznia 2022 roku do 31 grudnia 2022 roku. W każdym wierszu podane są dane opisujące jedną transakcję sprzedaży, oddzielone pojedynczymi znakami tabulacji:

    • data sprzedaży zapisana w formacie rrrr-mm-dd
    • nazwa odmiany jabłka
    • kod, który określa, czy odmiana jest: L — letnia, J — jesienna czy Z — zimowa
    • numer NIP klienta (13-znakowy tekst)
    • liczba kilogramów sprzedanego towaru.

    Fragment pliku jablka.txt:

    2022-01-03    Jonagold     Z    128-29-15-591   470
    2022-01-03    Jonagold     Z    192-09-72-275   410
    2022-01-03    Jonagored    Z    140-36-11-559   242
    

    Cena sprzedaży jednego kilograma jabłek zależy od odmiany jabłek. W pliku cennik.txt jest podana cena w złotych 1 kg jabłek każdej odmiany.

    Fragment pliku cennik.txt:

    Alwa         2,9
    Antonowka    3,2
    Cortland     3,2
    

    Zadanie 7.1. (0–2) Dla każdego klienta policz, ile kupił on łącznie (we wszystkich swoich transakcjach) kilogramów jabłek odmian zimowych. Podaj numery NIP trzech klientów, którzy kupili najwięcej jabłek odmian zimowych (Z), oraz podaj dla każdego z nich liczbę kilogramów jabłek odmian zimowych przez nich kupionych.

    Zadanie 7.2. (0–2) Przychód z pojedynczej sprzedaży to cena sprzedaży jednego kilograma jabłek pomnożona przez liczbę kilogramów. Podaj całkowity przychód hurtowni uzyskany w całym okresie. Podaj również odmiany jabłek, która dała największy przychód.

    Zadanie 7.3. (0–3) Wykonaj zestawienie, w którym dla każdego miesiąca roku 2022 podasz nazwę najbardziej popularnej odmiany w tym miesiącu, czyli takiej, której w danym miesiącu sprzedano najwięcej. Na podstawie wykonanego zestawienia utwórz wykres kolumnowy ilustrujący wielkości sprzedaży najpopularniejszych odmian jabłek w poszczególnych miesiącach. Pamiętaj o czytelnym opisie wykresu — na osi X umieść daty kolejnych miesięcy, oś Y odpowiada wielkości sprzedaży najbardziej popularnej odmiany w tym miesiącu, dodaj opis osi Y i tytuł wykresu.

    Zadanie 7.4. (0–3) Hurtownia ma system premiowania klientów hurtowych. Klient otrzymuje przy zakupie rabat, którego wysokość zależy od łącznej ilości jabłek zakupionych do tej pory przez tego klienta, wliczając w to jabłka zakupione w bieżącej transakcji. Wysokość rabatu za każdy kilogram w bieżącej transakcji wynosi:

    • 5 gr, jeśli klient dotychczas zakupił co najwyżej 15 000 kg, ale mniej niż 20 000 kg,
    • 10 gr, jeśli klient dotychczas zakupił co najmniej 20 000 kg.

    Podaj, w tej kolejności (dla 3 klientów z najwyższymi łącznymi wartościami rabatów): imię + NIP klienta, wartość rabatu.

    Pokaż odpowiedź

    Najwygodniej rozwiązać arkuszem kalkulacyjnym lub Pythonem z pandas.

    Załadowanie danych (Python):

    import pandas as pd
    jablka = pd.read_csv("jablka.txt", sep="\t", header=None,
                        names=["data","odmiana","kod","nip","kg"])
    jablka["data"] = pd.to_datetime(jablka["data"])
    cennik = pd.read_csv("cennik.txt", sep="\t", header=None,
                         names=["odmiana","cena"])
    cennik["cena"] = cennik["cena"].str.replace(",", ".").astype(float)
    

    7.1. Top-3 klientów wg sumy kg odmian zimowych:

    zimowe = jablka[jablka["kod"] == "Z"]
    top3 = zimowe.groupby("nip")["kg"].sum().sort_values(ascending=False).head(3)
    print(top3)
    

    7.2. Przychód całkowity i odmiana z najwyższym przychodem:

    d = jablka.merge(cennik, on="odmiana")
    d["przychod"] = d["kg"] * d["cena"]
    print(f"Całkowity przychód: {d['przychod'].sum():.2f} zł")
    print(d.groupby("odmiana")["przychod"].sum().idxmax(),
          d.groupby("odmiana")["przychod"].sum().max())
    

    7.3. Najpopularniejsza odmiana w każdym miesiącu + wykres:

    jablka["miesiac"] = jablka["data"].dt.to_period("M")
    pop = (jablka.groupby(["miesiac","odmiana"])["kg"].sum()
                  .reset_index()
                  .sort_values(["miesiac","kg"], ascending=[True,False])
                  .drop_duplicates("miesiac"))
    print(pop[["miesiac","odmiana","kg"]])
    
    import matplotlib.pyplot as plt
    plt.bar(pop["miesiac"].astype(str), pop["kg"])
    plt.xlabel("Miesiąc 2022")
    plt.ylabel("Sprzedaż najpopularniejszej odmiany [kg]")
    plt.title("Najpopularniejsze odmiany jabłek 2022")
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.savefig("wykres_7_3.png", dpi=150)
    

    7.4. Rabat naliczamy iteracyjnie — dla każdej transakcji sprawdzamy stan zakupów klienta do tej pory włącznie z tą transakcją:

    jablka_s = jablka.sort_values("data").reset_index(drop=True)
    laczne = {}  # nip -> kg dotychczas
    rabat  = {}  # nip -> łączna kwota rabatu w zł
    for _, r in jablka_s.iterrows():
        nip, kg = r["nip"], r["kg"]
        nowy = laczne.get(nip, 0) + kg
        laczne[nip] = nowy
        if nowy >= 20000:
            stawka = 0.10
        elif nowy >= 15000:
            stawka = 0.05
        else:
            stawka = 0.0
        rabat[nip] = rabat.get(nip, 0) + kg * stawka
    top3 = sorted(rabat.items(), key=lambda x: -x[1])[:3]
    for nip, kwota in top3:
        print(nip, round(kwota, 2))
    

    Wyniki konkretne (zależne od danych w pliku) zapisujemy do wyniki7.txt, poprzedzając każdą sekcję numerem zadania (7.1, 7.2, 7.3, 7.4).

    ⚠ Typowa pułapka: Najczęstsze błędy: (1) w 7.2 — czytanie cen jako stringów z przecinkiem (PL) i zapominanie o zamianie na kropkę → string concatenation zamiast iloczynu; (2) w 7.3 — wybór odmiany "popularnej" wagowo (suma kg), nie liczbowo (liczba transakcji) — treść CKE mówi „której najwięcej sprzedano" = kg; (3) w 7.4 najczęściej myli się próg rabatu: zdanie „**wliczając** w to jabłka zakupione w bieżącej transakcji" znaczy, że stan po dodaniu bieżących kg decyduje o stawce; (4) brakuje sortowania chronologicznego transakcji przed naliczaniem rabatu.

    Zobacz pełne rozwiązanie krok po kroku →
  5. Matura CKE · maj 2023 · zad. 6 10 pkt arkusz kalkulacyjny, przetwarzanie danych, wykres kolumnowy, symulacja produkcji

    Zadanie 6. Konfitury

    Przetwórnia produkuje konfitury malinowo-truskawkowe, malinowo-porzeczkowe oraz truskawkowo-porzeczkowe (zawsze w proporcji owoców 1:1 oraz z wykorzystaniem maksymalnie dostępnej ilości owoców). Decyzja, jaką konfiturę w danym dniu będzie produkowana, zależy od ilości owoców znajdujących się w przetwórni.

    Owoce są dostarczane do przetwórni rano, codziennie. Po dostawie z poprzedniego dnia ilości owoców znajdujące się w przetwórni są przeliczane (dla każdych w dwóch z trzech owoców pomiędzy najpierw najbliżej tej samej ilości po dodaniu) – będzie produkowana konfitura z udziałem tych dwóch dwóch różnych owoców jest taka sama). Owoce niewykorzystane do produkcji są przechowywane w chłodni do następnego dnia. W następnym dniu podejmuje się decyzję o produkcji na nowo dostarczonych rano.

    Przykład: Jeżeli 01.05.2020 dostarczono 211 kg malin, 281 kg truskawek i 88 kg porzeczek, to w tym dniu będzie produkowana konfitura malinowo-truskawkowa. Do produkcji wykorzystane zostanie 211 kg malin i 211 kg truskawek. Reszta truskawek i wszystkie porzeczki będą przechowywane w chłodni do następnego dnia. Po dostawie z 02.05.2020 (393 kg malin, 313 kg truskawek i 83 kg porzeczek) w przetwórni będzie 393 kg malin, 383 kg truskawek i 171 kg porzeczek, czyli znowu będzie produkowana konfitura malinowo-truskawkowa.

    Po uwzględnieniu opisanego powyżej cyklu produkcyjnego oraz danych zapisanych w pliku owoce.txt podaj odpowiedzi do poniższych zadań.

    Zadanie 6.1. (0–3) Dla każdego miesiąca pracy przetwórni (od maja do września) wykonaj zestawienie liczby dostarczonych kilogramów malin, liczby dostarczonych kilogramów truskawek i liczby dostarczonych kilogramów porzeczek. Na podstawie wykonanego zestawienia utwórz wykres kolumnowy. Pamiętaj o czytelnym opisie wykresu (tytuł, legenda, opisy osi: na osi X – nazwy miesięcy, na osi Y – liczba kilogramów).

    Zadanie 6.2. (0–1) Podaj liczbę dni, w których dostarczono, spośród trzech rodzajów owoców, najwięcej porzeczek.

    Zadanie 6.3. (0–3) Podaj, ile razy, w okresie od 01.05.2020 do 30.09.2020, produkowano konfitury poszczególnych rodzajów.

    Zadanie 6.4. (0–3) Na wyprodukowanie 1 kg konfitur dwuowocowych potrzeba po 1 kg każdego owoca. Podaj, ile kilogramów konfitur każdego rodzaju wyprodukowano w okresie od 01.05.2020 do 30.09.2020.

    Pokaż odpowiedź

    6.1. Wykonanie w arkuszu (Excel/LibreOffice) lub w Pythonie/SQL:

    import pandas as pd
    df = pd.read_csv("owoce.txt", sep="\t", parse_dates=["data"])
    df["miesiac"] = df["data"].dt.month_name()
    zest = df.groupby("miesiac")[["maliny","truskawki","porzeczki"]].sum()
    zest.plot(kind="bar", title="Dostawy owoców (V–IX 2020)",
              xlabel="miesiąc", ylabel="kg")
    

    Tabela podsumowuje sumy kg dla maj, czerwiec, lipiec, sierpień, wrzesień. Wykres kolumnowy grupowany (3 słupki na miesiąc, legenda: maliny/truskawki/porzeczki).

    6.2. Liczba dni z dominacją porzeczek (porzeczki > maliny AND porzeczki > truskawki dla wartości dostarczonych danego dnia):

    ile = ((df["porzeczki"] > df["maliny"]) & (df["porzeczki"] > df["truskawki"])).sum()
    

    Typowa odpowiedź dla rzeczywistego pliku: kilkanaście dni (zależy od danych – CKE klucz: konkretna liczba).

    6.3. Symulacja dzień po dniu z chłodnią:

    m, t, p = 0, 0, 0
    cnt = {"MT": 0, "MP": 0, "TP": 0}
    for _, row in df.iterrows():
        m += row.maliny
        t += row.truskawki
        p += row.porzeczki
        # wybór pary o największych zapasach
        pary = {"MT": m + t, "MP": m + p, "TP": t + p}
        # reguła tie-break: bierzemy parę z największą sumą; przy remisach – patrz klucz CKE
        wybor = max(pary, key=pary.get)
        uzyte = min(m,t) if wybor=="MT" else min(m,p) if wybor=="MP" else min(t,p)
        cnt[wybor] += 1
        if wybor == "MT": m -= uzyte; t -= uzyte
        elif wybor == "MP": m -= uzyte; p -= uzyte
        else: t -= uzyte; p -= uzyte
    

    Odpowiedź ma postać "MT: X, MP: Y, TP: Z" gdzie X+Y+Z = 153 (liczba dni V–IX).

    6.4. Suma uzyte per typ konfitury × 2 (bo 1 kg konfitury = 1 kg + 1 kg owoców → 2 kg owoców daje 2 kg konfitury wg dosłownego "po 1 kg każdego owocu na 1 kg konfitury" — czyli faktycznie z 1+1 kg robimy 1 kg konfitury, zatem masa konfitury = uzyte (każdy z dwóch składników wnosi uzyte kg, ale na 1 kg konfitury idzie 1+1 kg owoców, więc kg konfitury = uzyte).

    prod = {"MT": 0, "MP": 0, "TP": 0}
    # w pętli wyżej dodać: prod[wybor] += uzyte
    

    Odpowiedź: liczby kg dla MT, MP, TP wprost.

    ⚠ Typowa pułapka: Zad. 6.3/6.4 — krytyczna pułapka: NIE bierzemy pod uwagę tylko bieżącej dostawy, ale **kumulację zapasu z chłodni**. Symulacja musi prowadzić stan magazynu pomiędzy dniami. Reguła "konfitura z dwóch owoców o największej dostępnej ilości" — z chłodnią to całkiem co innego niż "z największej dziennej dostawy". Zad. 6.4 — "po 1 kg każdego owocu na 1 kg konfitury" jest niejednoznaczne; standardowa interpretacja CKE: 1 kg konfitury wymaga 1 kg owocu A + 1 kg owocu B, więc z `min(A,B)` kg każdego składnika powstaje `min(A,B)` kg konfitury (a zużycie owoców to 2·min(A,B)). Zad. 6.2 — pytanie o **dostarczone**, nie o stan w chłodni. Czytamy linie pliku bez symulacji.

    Zobacz pełne rozwiązanie krok po kroku →
  6. Matura CKE · maj 2023 · zad. 7 8 pkt baza danych, SQL, JOIN, GROUP BY, ranking gier planszowych

    Zadanie 7. Gry planszowe

    Pewien serwis internetowy prowadzi ranking gier planszowych. Baza serwisu została zapisana w trzech plikach.

    Plik gry.txt zawiera informacje o grach planszowych. W każdym wierszu zapisano:

    • id_gry – unikatowy numer gry planszowej
    • nazwa – tytuł gry planszowej
    • kategoria – kategoria, do jakiej została zakwalifikowana gra planszowa; każda gra należy tylko do jednej kategorii.

    Plik gracze.txt zawiera informacje o graczach. W każdym wierszu zapisano:

    • id_gracza – unikatowy numer gracza
    • imie – imię gracza
    • nazwisko – nazwisko gracza
    • wiek – wiek gracza.

    Plik oceny.txt zawiera oceny wystawione grom przez poszczególnych graczy. W każdym wierszu zapisano:

    • id_gry – numer gry planszowej
    • id_gracza – numer gracza
    • stan – zawiera jedną z możliwych wartości: posiada, chce kupic, sprzedal, opisującą, czy użytkownik posiada daną grę, czy ją sprzedał lub czy zamierza ją zakupić
    • ocena – zawiera ocenę gry przez gracza, wyrażoną liczbą całkowitą w zakresie od 0 do 10.

    We wszystkich plikach dane w wierszach są rozdzielone znakami tabulacji, a pierwszy wiersz w każdym pliku jest wierszem nagłówkowym.

    Z wykorzystaniem dostępnych narzędzi informatycznych podaj odpowiedzi do zadań 7.1.–7.4.

    Zadanie 7.1. (0–1) Podaj tytuł gry, która otrzymała najwięcej ocen.

    Zadanie 7.2. (0–2) Dla każdej z 7 kategorii „imprezowa" podaj średnią jej ocen z dokładnością do dwóch miejsc po przecinku. (uwaga: w arkuszu pytanie dotyczy każdej kategorii — średnia ocen tej kategorii)

    Zadanie 7.3. (0–2) Podaj liczbę graczy, którzy nie posiadają żadnej z ocenianych przez siebie gier (nie mają żadnej gry ze stanem "posiada"), a wystawili co najmniej jedną ocenę.

    Zadanie 7.4. (0–3) W ocenianiu gier planszowych uczestniczą osoby w wieku od 10 do 99 lat. Osoby oceniające gry podzielono na dwa kategorie wiekowe: juniorzy (do 19 lat), seniorzy (od 20 do 49 lat) oraz weterani (od 50 lat). Wykonaj zestawienie, w którym dla każdej kategorii wiekowej podaj największą liczbę ocen wystawionych przez jedną osobę, oraz – jeśli okazałoby się, że więcej niż jedna – podaj tytuły wszystkich.

    Pokaż odpowiedź

    Zakładamy że pliki zostały zaimportowane do bazy SQL (np. SQLite) jako tabele gry, gracze, oceny.

    7.1. Tytuł gry z największą liczbą ocen:

    SELECT g.nazwa, COUNT(*) AS ile
    FROM oceny o JOIN gry g ON g.id_gry = o.id_gry
    GROUP BY g.id_gry, g.nazwa
    ORDER BY ile DESC
    LIMIT 1;
    

    7.2. Średnia ocen dla każdej kategorii (zaokrąglona do 2 miejsc):

    SELECT g.kategoria, ROUND(AVG(o.ocena), 2) AS srednia
    FROM oceny o JOIN gry g ON g.id_gry = o.id_gry
    GROUP BY g.kategoria
    ORDER BY g.kategoria;
    

    7.3. Gracze, którzy nigdy nie mają stanu "posiada", ale wystawili co najmniej jedną ocenę:

    SELECT COUNT(DISTINCT o.id_gracza)
    FROM oceny o
    WHERE o.id_gracza NOT IN (
        SELECT id_gracza FROM oceny WHERE stan = 'posiada'
    );
    

    7.4. Najwięcej ocen w każdej kategorii wiekowej. Najpierw policzmy oceny per gracz z przypisaną kategorią:

    WITH ocen_per_gracz AS (
      SELECT
        o.id_gracza,
        CASE
          WHEN gr.wiek <= 19 THEN 'junior'
          WHEN gr.wiek <= 49 THEN 'senior'
          ELSE 'weteran'
        END AS kat_wiek,
        COUNT(*) AS ile
      FROM oceny o
      JOIN gracze gr ON gr.id_gracza = o.id_gracza
      GROUP BY o.id_gracza, kat_wiek
    ),
    max_per_kat AS (
      SELECT kat_wiek, MAX(ile) AS max_ile
      FROM ocen_per_gracz
      GROUP BY kat_wiek
    )
    SELECT opg.kat_wiek, gr.imie, gr.nazwisko, opg.ile
    FROM ocen_per_gracz opg
    JOIN max_per_kat m ON m.kat_wiek = opg.kat_wiek AND m.max_ile = opg.ile
    JOIN gracze gr ON gr.id_gracza = opg.id_gracza;
    

    Wyniki wpisz do wyniki7.txt, każdy poprzedzony numerem zadania (7.1., 7.2., 7.3., 7.4.).

    ⚠ Typowa pułapka: Zad. 7.3 — kluczowe rozróżnienie: "nie posiada żadnej gry" oznacza brak rekordu `stan='posiada'`, ale gracz musi mieć przynajmniej jedną OCENĘ (w pliku oceny.txt). Pominięcie warunku "ma jakąkolwiek ocenę" da błędną liczbę (zliczy też graczy bez ocen z pliku gracze.txt). Zad. 7.4 — granica kategorii: junior do 19 (włącznie), senior 20–49 (włącznie), weteran od 50. Łatwo o off-by-one: 19 to junior, 20 to senior, 49 to senior, 50 to weteran. "Więcej niż jedna osoba z taką liczbą" → wypisz wszystkie tytuły (uwaga: arkusz pyta o "tytuły gier" — to znaczy gier ocenionych przez tych liderów; trzeba dolaczyć tabelę gier i wylistować). Zad. 7.2 — średnia z DOKŁADNOŚCIĄ do 2 miejsc po przecinku (`ROUND(..., 2)`), nie do całości.

    Zobacz pełne rozwiązanie krok po kroku →

Inne działy — informatyka rozszerzona