Shanraq.org Shanraq.org
Таңдау және сүзгілер: тек керегін қалдыру
IT

Python: деректен өз есебіңізге дейін 28-сабақ (барлығы 56)

Таңдау және сүзгілер: тек керегін қалдыру

Python курсының жиырма жетінші сабағы. Маска — «иә» мен «жоқтан» тұратын баған, әрі кесте сонымен тұтас сүзіледі, циклсіз. `df[маска]`, `.loc[маска, бағандар]`, `&`, `|`, `~` және міндетті жақшалар, `isin`, `between`, `str`, әрі сүзгіден кейін қайта саналмайтын белгілер.

Не үшін керек

Кесте сирек тұтас керек болады. Бір қаланың түбіртектері, айдың екінші жартысындағы шығыс, сомасы күдікті үлкен жолдар керек. Тізімде бұл — if бар цикл және жаңа тізім; кестеде — бір өрнек, әрі ол санап шығу емес, шарт болып оқылады.

Осы жерде жиырма бесінші сабақтың уәдесі де жабылады: loc пен iloc дәл жолдар сүзілген жерде ажырасады.

Бірден тұтас

vyborka.py файлы. Қаңтардағы он түбіртек және олардан керегін алудың сегіз тәсілі.

"""27-сабақ: керекті жолдар мен бағандарды алу.

Қаңтардағы он түбіртек. Солардан таңдаймыз — алдымен бағандарды, сосын
жолдарды, сосын екеуін бірден.
"""

import pandas as pd

rows = [
    ("2026-01-03", "Қостанай", "тамақ", 4200),
    ("2026-01-05", "Қостанай", "жанармай", 18500),
    ("2026-01-07", "Рудный", "тамақ", 2600),
    ("2026-01-09", "Қостанай", "байланыс", 4990),
    ("2026-01-12", "Астана", "тамақ", 7300),
    ("2026-01-15", "Қостанай", "жалдау", 95000),
    ("2026-01-18", "Рудный", "жанармай", 16200),
    ("2026-01-21", "Астана", "байланыс", 4990),
    ("2026-01-24", "Қостанай", "тамақ", 3100),
    ("2026-01-27", "Рудный", "жалдау", 62000),
]
df = pd.DataFrame(rows, columns=["day", "city", "kind", "amount"])
df["day"] = pd.to_datetime(df["day"])
print(df)

print()
print("== бағандар: біреуі және бірнешеуі")
print("df['amount'] →", type(df["amount"]).__name__)
print("df[['city', 'amount']] →", type(df[["city", "amount"]]).__name__)

print()
print("== маска — «иә» мен «жоқтан» тұратын баған")
big = df["amount"] > 10000
print(big.tolist())
print("келген жол:", int(big.sum()), "барлығынан", len(df))

print()
print("== жолдарды сүзу")
print(df[big])

print()
print("== екі шарт: & | ~ және міндетті жақшалар")
kostanay_food = (df["city"] == "Қостанай") & (df["kind"] == "тамақ")
print("Қостанай әрі тамақ:", int(kostanay_food.sum()))
print("тамақ емес:", int((~(df["kind"] == "тамақ")).sum()))
print("тамақ не байланыс:", int(df["kind"].isin(["тамақ", "байланыс"]).sum()))

print()
print("== жолдар мен бағандар бір өтінімде")
print(df.loc[kostanay_food, ["day", "amount"]])

print()
print("== тағы үш дайын шарт")
print("4000-нан 20000-ға дейін:", int(df["amount"].between(4000, 20000).sum()))
print("қаласы «Қ»-дан басталады:", int(df["city"].str.startswith("Қ").sum()))
print("айдың екінші жартысы:", int((df["day"] >= "2026-01-15").sum()))

print()
print("== сүзгіден кейін белгілер қайта саналмайды")
rudny = df[df["city"] == "Рудный"]
print("белгілер:", rudny.index.tolist())
print("loc[2]:", rudny.loc[2, "kind"], "| iloc[2]:", rudny.iloc[2]["kind"])

print()
print("== loc арқылы жазу")
df.loc[df["kind"] == "байланыс", "kind"] = "мобильді байланыс"
print(df["kind"].value_counts().to_dict())

Шығысы:

         day      city      kind  amount
0 2026-01-03  Қостанай     тамақ    4200
1 2026-01-05  Қостанай  жанармай   18500
2 2026-01-07    Рудный     тамақ    2600
3 2026-01-09  Қостанай  байланыс    4990
4 2026-01-12    Астана     тамақ    7300
5 2026-01-15  Қостанай    жалдау   95000
6 2026-01-18    Рудный  жанармай   16200
7 2026-01-21    Астана  байланыс    4990
8 2026-01-24  Қостанай     тамақ    3100
9 2026-01-27    Рудный    жалдау   62000

== бағандар: біреуі және бірнешеуі
df['amount'] → Series
df[['city', 'amount']] → DataFrame

== маска — «иә» мен «жоқтан» тұратын баған
[False, True, False, False, False, True, True, False, False, True]
келген жол: 4 барлығынан 10

== жолдарды сүзу
         day      city      kind  amount
1 2026-01-05  Қостанай  жанармай   18500
5 2026-01-15  Қостанай    жалдау   95000
6 2026-01-18    Рудный  жанармай   16200
9 2026-01-27    Рудный    жалдау   62000

== екі шарт: & | ~ және міндетті жақшалар
Қостанай әрі тамақ: 2
тамақ емес: 6
тамақ не байланыс: 6

== жолдар мен бағандар бір өтінімде
         day  amount
0 2026-01-03    4200
8 2026-01-24    3100

== тағы үш дайын шарт
4000-нан 20000-ға дейін: 6
қаласы «Қ»-дан басталады: 5
айдың екінші жартысы: 5

== сүзгіден кейін белгілер қайта саналмайды
белгілер: [2, 6, 9]
loc[2]: тамақ | iloc[2]: жалдау

== loc арқылы жазу
{'тамақ': 4, 'жанармай': 2, 'мобильді байланыс': 2, 'жалдау': 2}

Талдау

Баған және бағандар тізімі

df["amount"] — бұл Series, бір баған. df[["city", "amount"]] — екеуінен тұратын DataFrame: тік жақшаның ішінде тізім тұр, сондықтан жауап та кесте, тізімде бір ат болса да. Айырмашылық маңызды: Series пен DataFrame-нің әдістері әртүрлі, ал «неге істемейді» деген сұрақтың жартысы — кесте күткен жерде Series тұрғаны.

Маска — «иә» мен «жоқтан» тұратын баған

df["amount"] > 10000 «иә» не «жоқ» деп жауап бермейді. Ол бағанмен жауап береді: әр жолға бір жауап, сол белгілермен. Қалғанының бәрі содан:

  • big.sum() келген жолдарды санайды, өйткені True — бұл бірлік (төртінші сабақ);
  • df[big] True тұрған жолдарды қалдырады;
  • маска кестемен рет бойынша емес, белгі бойынша салыстырылады — pandas-тағының бәрі сияқты.

&, |, ~ және әшекей емес жақшалар

Екі шарт сөзбен емес, таңбамен қосылады: and орнына &, or орнына |, not орнына ~. Сөздер мұнда істемейді, әрі бұл қырсықтық емес: and бір ғана «иә» не «жоқ» жауабын сұрайды, ал бағанда ондай жауап он. Python мұны ашық айтады:

ValueError: The truth value of a Series is ambiguous.

Әр шарттың айналасындағы жақша міндетті, өйткені & салыстырудан бұрын орындалады: онсыз df["city"] == "Қостанай" & df["kind"] == "тамақ" деген өрнек df["city"] == ("Қостанай" & df["kind"]) == "тамақ" болып саналады да, жақша кінәлі екенін түсіндірмей құлайды.

Ұзын тізбектің орнына дайын шарттар

Күн сайын жазылатын үш нәрсе:

  • df["kind"].isin(["тамақ", "байланыс"])(... == "тамақ") | (... == "байланыс") орнына, әрі тізім қандай ұзын болса да жарайды;
  • df["amount"].between(4000, 20000) — екі салыстырудың орнына, шектері кіреді;
  • df["city"].str.startswith("Қ") — қасында str.contains, str.lower, str.len: жолдар істей алатынның бәрі бағанда .str арқылы бар.

Жетіспейтін мәндер бөлек тексеріледі: df["amount"].isna() және .notna(). NaN-мен салыстыру әрқашан «жоқ» береді, тіпті NaN == NaN те, сондықтан оларды салыстырумен іздеудің пайдасы жоқ.

Жолдар мен бағандар бір өтінімде

df.loc[маска, ["day", "amount"]] — сол жағы жолдарды, оң жағы бағандарды таңдайды. Бұл df[маска][["day", "amount"]] нұсқасынан қысқа да, арзан да: екіншісі артығын лақтыру үшін ғана барлық бағаннан аралық кесте құрады.

Сөзбен жазатын түрі де бар: df.query("amount > 5000 and city == 'Қостанай'") — жол ішінде and мен or дәл осылай істейді. Ол өзіңіз жазған ұзын шарттарға ыңғайлы.

Онымен істеуге болмайтын нәрсе: сұраныс жолын пайдаланушы енгізген нәрседен құрастыру. query өрнекті код ретінде талдайды, әрі қойылған мәтін орындалады — бұл жиырма бірінші сабақтағы SQL-инъекциямен бір тесік. Мәндер @айнымалы арқылы беріледі (df.query("amount > @limit")), ал сырттан келген шартты маскамен құрған қауіпсіз: маска ештеңе орындамайды.

Сүзгіден кейін белгілер қайта саналмайды

Үш жолды сүздік — белгілер [2, 6, 9] күйінде қалды, өйткені бұл сол жолдардың өзі. Сондықтан мысалдағы loc[2] мен iloc[2] әртүрлі нәтиже береді: біреуі белгісі 2 болатын жолды, екіншісі реті бойынша үшіншісін сұрайды.

Бұл — жиырма бесінші сабақ «айырмашылық жолдар сүзілген бойда шығады» деген дәл сол орын. Қолтаңбалар кедергі келтірсе, reset_index(drop=True) жолдарды қайта нөмірлейді; мұндағы drop=True — әйтпесе ескі белгілер жаңа бағанға айналады.

loc арқылы жазу, ал сүзгі арқылы неге болмайды

Шартқа келген жолдарды белгілеу loc арқылы жүреді:

df.loc[df["kind"] == "байланыс", "kind"] = "мобильді байланыс"

df[df["kind"] == "байланыс"]["kind"] = "мобильді байланыс" нұсқасы қисынды көрінеді әрі ештеңе істемейді. df[маска] жаңа кесте қайтарады, ал меншіктеу бастапқысын емес, соны өзгертеді. pandas мұны байқап, ChainedAssignmentError деп ескертеді — ұзын шығыста оңай өтіп кететін ескерту, өйткені ол сіз бағдарламаның шығысын күтетін жерге түспейді.

Ереже қарапайым: = белгісінің сол жағында бір тік жақшадан көп нәрсе тұрса — бұл loc.

Сабақ картасы

Сабақ картасы: маска, жолдар және бағандар

Өз сөзіңізбен айтыңыз

Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптар — сабақтың соңында.

  1. Маска деген не және df["amount"] > 10000 неге «иә» де, «жоқ» та емес?
  2. Екі шартты неге and сөзімен емес, & таңбасымен қосады?
  3. Сүзгіден кейін loc[2] мен iloc[2] неге әртүрлі жол бере алады?

Жаттығу

Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, түзету. Жауаптар — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.

1. Болжаңыз. Бұл бағдарлама не басып шығарады?

import pandas as pd

amounts = pd.Series([4200, 18500, 2600, 95000], index=["тамақ", "жанармай", "тамақ", "жалдау"])
mask = amounts > 5000
print(mask.tolist(), "| келгені:", int(mask.sum()))
print(amounts[mask].to_dict())

2. Бос орынды толтырыңыз. ... орнына шартты қойыңыз: қаласы Қостанай әрі сомасы 5000-нан көп.

# екі шарт, әрқайсысы өз жақшасында
import pandas as pd

df = pd.DataFrame({"city": ["Қостанай", "Рудный", "Қостанай"], "amount": [4200, 16200, 95000]})
print(df[...].to_string(index=False))

3. Түзетіңіз. Бағдарлама байланысты «мобильді байланысқа» ауыстыруға тиіс, бірақ кесте өзгермейді, ал шетте ChainedAssignmentError пайда болады.

# меншіктеу кестеге емес, көшірмеге кетеді
import pandas as pd

df = pd.DataFrame({"kind": ["тамақ", "байланыс"], "amount": [4200, 4990]})
df[df["amount"] > 4500]["kind"] = "мобильді байланыс"
print(df.to_string(index=False))

Тапсырма

Міндетті. Сабақтағы сол он түбіртекті алыңыз да, үш сұраққа циклмен емес, таңдаумен жауап беріңіз:

  1. Қостанайдағы 5000-нан қымбат түбіртектер — тек күні мен сомасы.
  2. Түбіртектерді белгілеңіз: сомасы 20000-нан болса — ірі, әйтпесе кәдімгі. Бағанды меншіктеумен қосыңыз, белгіні loc арқылы қойыңыз. Қайсысы қанша екенін басып шығарыңыз.
  3. Ірі түбіртектердің қалалар бойынша сомасы.

Күтілетін шығыс:

Қостанайда 5000-нан қымбат:
       day  amount
2026-01-05   18500
2026-01-15   95000

түбіртектің мөлшері:
мөлшері
кәдімгі    8
ірі        2

қалалар бойынша ірілері:
city
Рудный      62000
Қостанай    95000

Дайын болғаны: шығыс жол-жолымен сәйкес келеді; белгі = белгісінің сол жағындағы сүзгімен емес, df.loc[маска, "мөлшері"] арқылы қойылған; бірінші жауапта екі баған бір өтінімде таңдалған; сомалар циклмен емес, сүзілген кестені топтаумен алынған.

Өз деректеріңізде. Өз кестеңізді алып, оған үш шарт құрыңыз: біреуі қарапайым, біреуі екі бөліктен, біреуі isin не between арқылы. Әрқайсысына қанша жол келгенін басып шығарыңыз. Біреуіне нөл жол келсе — dtypes-ке қараңыз. Бағанда санның орнына жол тұрса, == барлық жолға үнсіз «жоқ» береді, ал > пен < TypeError-мен құлайды. Мұны шартты іріктеумен емес, сүзгіге дейінгі pd.to_numeric арқылы емдейді.

Қалауыңыз бойынша.

  • Сол шартты query арқылы жазып, қайсысы оңай оқылатынын салыстырыңыз.
  • df[маска].reset_index(drop=True) жасап, белгілерге не болғанын қараңыз.
  • ~маска қанша жол беретінін тексеріп, маскамен қосқанда кестенің ұзындығы шығатынына көз жеткізіңіз.

Жобада бұл қайда тұрады

Қазір қадам жоқ: жиынтыққа бес жол жетеді, әрі онда сүзетін ештеңе әзірге жоқ. Бірақ таңдау — келесі қадам содан жасалатын нәрсе: қатар бірнешеу болғанда, есеп «тек керекті жолдарды алудан» басталады, содан кейін ғана келесі сабақтағы топтау келеді.

Қарыздар. Шарттар бізде кодтың ішінде жазылады. Олар үшеуден асқанда, ат сұрайды — әрі қатар тұрған үш жақшадан гөрі жақсы оқылатын irileri(df) тәрізді функцияларға айналады.

Жауаптар

Жауаптарды көрсету

Сұрақтарға

  1. Маска — «иә» мен «жоқтан» тұратын баған, әр жолға бір жауап, сол белгілермен. Бағанды санмен салыстыру бағанды тұтас емес, әр мәнді салыстырады, сондықтан жауап та баған болып шығады.
  2. Өйткені and бір жауап сұрайды, ал бағанда олар жол саны қанша болса, сонша. & — әр элементпен жұмыс істеп, дәл сондай баған қайтаратын таңба. Жақшалар да сол себепті керек: & салыстырудан бұрын орындалады.
  3. Өйткені сүзгі белгілерді қайта санамайды: қалған жолдарда олар бұрынғыдай. loc[2] белгісі 2 болатын жолды, iloc[2] реті бойынша үшіншісін сұрайды, ал сүзгіден кейін бұл әртүрлі жол.

Жаттығуға

  1. Салыстыру «иә» мен «жоқтан» тұратын баған береді, sum() келгенін санайды, ал amounts[mask] тек соларды қалдырады — белгілерімен бірге.
[False, True, False, True] | келгені: 2
{'жанармай': 18500, 'жалдау': 95000}
  1. (df["city"] == "Қостанай") & (df["amount"] > 5000). Жақшалар міндетті, таңбасы — сөз емес, &.
import pandas as pd

df = pd.DataFrame({"city": ["Қостанай", "Рудный", "Қостанай"], "amount": [4200, 16200, 95000]})
print(df[(df["city"] == "Қостанай") & (df["amount"] > 5000)].to_string(index=False))
    city  amount
Қостанай   95000
  1. df.loc[df["amount"] > 4500, "kind"] = "мобильді байланыс". Меншіктеу кестенің өзіне түсуге тиіс, ал df[маска] — бұл басқа кесте.
import pandas as pd

df = pd.DataFrame({"kind": ["тамақ", "байланыс"], "amount": [4200, 4990]})
df.loc[df["amount"] > 4500, "kind"] = "мобильді байланыс"
print(df.to_string(index=False))
             kind  amount
            тамақ    4200
мобильді байланыс    4990

Тапсырмаға

Бірінші жауап — df.loc[маска, ["day", "amount"]]: жолдар мен бағандар бір өтінімде. Екіншісі — алдымен баған тұтасымен әдепкі мәнмен толтырылады, содан кейін шарт ақиқат жерде loc оны басып жазады; сонда белгісіз жол қалмайды. Үшіншісі — сүзгі және топтау: ірілерін іріктеп алып, содан кейін қалалар бойынша қосу.

Дереккөздер

Мәтінде қате не теру қатесі кездессе, бізге айтыңыз

Тапсырманы тексеру

Алдымен VS Code-та шешіп, іске қосыңыз — редактор қатені сол жерде көрсетеді. Дайын шешімді осында қойыңыз. Тексеретін — модель: ол қатені атап көрсетеді, бірақ дайын жауапты бермейді.

Тексеру үшін кіру керек. Кіру

Пікірлер (0)

Әзірге пікір жоқ. Бірінші болыңыз.