Python: деректен өз есебіңізге дейін 27-сабақ (барлығы 56)
Оқу және жазу: CSV, JSON және SQL бір жолмен
Python курсының жиырма алтыншы сабағы. Басқа жүйеден келген файл — бұл бөлгіш, бөлшектегі үтір, BOM және өз белгісі бар жетіспейтін мән; циклде әрқайсысын есте ұстау керек, ал `read_csv`-те бұлар — параметрлер. `read_csv`, `to_csv`, `read_sql` және `to_sql`, әрі файлдың кесте туралы нені ұмытатыны.
Не үшін керек
Он екінші сабақ CSV-ды csv модулімен оқуды үйретті: жол-жолымен, әр санды мәтіннен қолмен. Файл біреу әрі шағын болса, бұл — дұрыс құрал.
Бірақ басқа жүйелерден келген файлдар әртүрлі болады. Excel-ден — үтірдің орнына нүктелі үтірмен әрі бөлшек ішінде үтірмен. Бухгалтериядан — мыңдықта бос орынмен және бос ұяшықтың орнына «дерек жоқ» деген белгімен. Ескі жүйеден — басында BOM-мен. Осы ұсақ-түйектің әрқайсысы циклде жеке жолға айналады, оны есте ұстау керек, ал ұмытылғаны үнсіз қате жауапқа айналады.
pandas-та мұның бәрі — бір функцияның параметрлері. Сабақ солардың қайсысы екені туралы.
Бірден тұтас
formaty.py файлы. Бір кесте үш пішімге кетіп, қайта оралады.
"""26-сабақ: оқу және жазу — CSV, JSON, SQL.
Сол бір кесте үш пішімге кетіп, қайта оралады. Жолда не аман қалатынын, не
жоғалатынын қараймыз.
"""
import sqlite3
from pathlib import Path
import pandas as pd
HERE = Path(__file__).resolve().parent
# Инфляция, жылына %. Дүниежүзілік банктің дерегі; 2025 жыл әлі саналмаған.
df = pd.DataFrame(
{"KZ": [8.0, 15.0, 14.5, 8.7, None], "UZ": [10.8, 11.4, 10.0, 9.6, None]},
index=[2021, 2022, 2023, 2024, 2025],
)
df.index.name = "year"
print(df)
print()
print("== CSV: циклдің орнына бір жол")
csv_path = HERE / "inflation.csv"
df.to_csv(csv_path)
print(csv_path.read_text(encoding="utf-8"), end="")
print()
print("== және кері")
plain = pd.read_csv(csv_path)
print("бағандар:", list(plain.columns), "| белгілер:", plain.index.tolist())
back = pd.read_csv(csv_path, index_col="year")
print("бағандар:", list(back.columns), "| белгілер:", back.index.tolist())
print("бастапқысымен сәйкес:", back.equals(df))
print()
print("== жетіспейтін мән сол күйінде қалды")
print("бос ұяшық:", int(back.isna().sum().sum()), "| файлда ол былай:", repr(csv_path.read_text(encoding="utf-8").splitlines()[-1]))
print()
print("== файл нені ұмытады: түрді")
rates = pd.DataFrame({"day": pd.to_datetime(["2026-01-15", "2026-02-15"]), "rate": [512.3, 519.8]})
rates_path = HERE / "rates.csv"
rates.to_csv(rates_path, index=False)
print(rates_path.read_text(encoding="utf-8"), end="")
print("жай оқыдық: ", dict(pd.read_csv(rates_path).dtypes.astype(str)))
print("parse_dates-пен:", dict(pd.read_csv(rates_path, parse_dates=["day"]).dtypes.astype(str)))
print()
print("== JSON: сол қатар, басқа конверт")
json_path = HERE / "inflation.json"
df.to_json(json_path, orient="index")
text = json_path.read_text(encoding="utf-8")
print("ұзындығы:", len(text), "таңба, басы:")
print(text[:88], "…")
print()
print("== SQL: кесте дерекқорға кетіп, сұраныспен оралады")
db = sqlite3.connect(HERE / "digest.db")
df.reset_index().to_sql("inflation", db, if_exists="replace", index=False)
high = pd.read_sql("SELECT year, KZ FROM inflation WHERE KZ > 10 ORDER BY year", db)
print(high)
db.close()
Шығысы:
KZ UZ
year
2021 8.0 10.8
2022 15.0 11.4
2023 14.5 10.0
2024 8.7 9.6
2025 NaN NaN
== CSV: циклдің орнына бір жол
year,KZ,UZ
2021,8.0,10.8
2022,15.0,11.4
2023,14.5,10.0
2024,8.7,9.6
2025,,
== және кері
бағандар: ['year', 'KZ', 'UZ'] | белгілер: [0, 1, 2, 3, 4]
бағандар: ['KZ', 'UZ'] | белгілер: [2021, 2022, 2023, 2024, 2025]
бастапқысымен сәйкес: True
== жетіспейтін мән сол күйінде қалды
бос ұяшық: 2 | файлда ол былай: '2025,,'
== файл нені ұмытады: түрді
day,rate
2026-01-15,512.3
2026-02-15,519.8
жай оқыдық: {'day': 'str', 'rate': 'float64'}
parse_dates-пен: {'day': 'datetime64[us]', 'rate': 'float64'}
== JSON: сол қатар, басқа конверт
ұзындығы: 143 таңба, басы:
{"2021":{"KZ":8.0,"UZ":10.8},"2022":{"KZ":15.0,"UZ":11.4},"2023":{"KZ":14.5,"UZ":10.0}," …
== SQL: кесте дерекқорға кетіп, сұраныспен оралады
year KZ
0 2022 15.0
1 2023 14.5
Талдау
Бір жол — ары, бір жол — бері
df.to_csv(жол) кестені тұтас жазады: тақырып баған аттарынан, жол белгілері бірінші бағанмен, жетіспейтін мәндер — бос ұяшық. pd.read_csv(жол) кері оқиды. Циклдегі writer.writerow да, int(row["year"]) де жоқ — түрлерді pandas мазмұнына қарап өзі анықтайды.
Он екінші сабақпен салыстырыңыз: сол жұмысқа он бес жол кететін, әрі олардың әрқайсысы қателесуге болатын орын еді.
Файл нені ұмытады
Файл — бұл мәтін. Ол екі нәрсені ұмытады, әрі екеуі де қатеге апарады.
Индексті. read_csv ескертусіз бірінші бағанды кәдімгі баған деп санайды: жол белгілері year бағанына айналды, ал олардың орнына [0, 1, 2, 3, 4] нөмірлері шықты. index_col="year" деп айтыңыз — жыл қайтадан белгі болады. Мысалдағы back.equals(df) тексерісі True дегенді дәл содан кейін басып шығарады.
Түрді. Файлдағы 2026-01-15 — жол. pandas оны жол күйінде оқиды, ал day.dt.month істемейді: жолдың айы жоқ. parse_dates=["day"] оны күнге айналдырады, шығыста str-дің datetime64[us]-ке айналғаны көрініп тұр. Кодтармен де солай: dtype={"kod": str} санға айналумен бірге жоғалатын алдыңғы нөлді сақтап қалады.
Бұл мысалда жетіспейтін мән жолда аман қалды: бос ұяшық NaN болып оқылды, ал NaN бос ұяшық болып жазылды — бос ұяшық нақ екеу, сол екеуі. Бірақ бұл бағанның қасиеті емес, сәттілік: мәтіндік бағанда бос ұяшық пен бос жолды ажырату мүмкін емес, ал NA, N/A, nan және тағы ондаған сөзді read_csv әдепкі күйінде жетіспейтін мән деп санайды — Намибияның нағыз NA кодын қоса. Нені жетіспейтін мән деп санауды анық беру керек: na_values=[...] және keep_default_na=False.
Басқа жерден келген кез келген файлды дерлік жабатын параметрлер
| Параметр | Қашан керек |
|---|---|
sep=";" |
Excel біздің жақта нүктелі үтірмен жазады |
decimal="," |
512,3 — бұл сан, жол емес |
thousands=" " |
1 200,50 — бұл да сан |
encoding="utf-8-sig" |
Excel файлының басындағы BOM |
na_values=["дерек жоқ", "-"] |
жіберушінің өз белгісі |
usecols=[...] |
екеуі үшін жиырма бағанды сүйремеу |
index_col="year" |
артық бағанның орнына белгі |
parse_dates=["day"] |
мәтінді күнге айналдыру |
dtype={"kod": str} |
алдыңғы нөлді сақтау |
nrows=5 |
гигабайттық файлды тұтас оқымай көз жүгірту |
Соңғысы әдетке айналуға тұрарлық: мұндай файлды тұтас оқымас бұрын, бес жолын оқып, dtypes-ке қараңыз. Бұл — отыз секунд және болашақ түсінбестіктің жартысы.
Жазғанда үшеуі маңызды:
index=False— жол белгілері жай ғана нөмір болса, файлда олардың шаруасы жоқ;float_format="%.2f"— есепте8.041471000000001тұрмауы үшін;na_rep="дерек жоқ"— алушыға бос орын емес, белгі керек болса.
JSON: read_json қашан, ал json.load қашан
to_json мен read_json JSON жазық кесте болғанда істейді, ал ондағы басты сұрақ — orient: жолдар мен бағандарды қалай жаю керек. Мысалда orient="index" «жыл → жол» сөздігін берді.
Ал он сегізінші сабақтағы банктің жауабы — кесте емес: онда кірістірілген нысандар, қызметтік қаптама және метадерек бар. Ондайды json.load-пен талдаған оңай, біз солай істедік те, ал кестені дайын сөздіктер тізімінен құрған жөн. Кірістірілген құрылымдар үшін pd.json_normalize бар, ол оларды бағандарға жаяды.
Ереже иесі бойынша емес, мәні бойынша: өзі кесте болып тұрған жазық JSON-ды read_json-мен оқыңыз; кірістірілгенін json.load немесе json_normalize арқылы талдаңыз. Басқа біреудің API-і көбіне екіншісін береді, өз to_json-ыңыз біріншісін, бірақ мұны кім жібергені емес, құрылымы шешеді.
SQL: to_sql және read_sql
Байланыс жиырма бірінші сабақтағы жерден — sqlite3-тен алынады. to_sql кестені дерекқорға салады, read_sql сұраныстың нәтижесін дайын кесте күйінде қайтарады.
Бұл жиырма екінші сабақтың орнын баспайды, оның жалғасы. Топтауды, біріктіруді және сүзгіні бұрынғыдай дерекқорға берген дұрыс: ол мұны жадыға сыймайтын деректе де істей алады әрі үлкеннің орнына кішкентай нәтиже қайтарады. read_sql — екі дүниенің арасындағы есік, GROUP BY-дан суыну себебі емес.
Екі ескерту. Мәндер сұранысқа жолды пішімдеу арқылы емес, params= арқылы қойылады — неге екені сол SQLite сабағында көрсетілген. Әрі байланыс туралы: sqlite3-ті pandas сол күйінде қабылдайды, PostgreSQL және басқалар үшін SQLAlchemy не ADBC жарайды — шақыру бұл кезде бірдей көрінеді, тек con-ға не бергеніңіз өзгереді.
Сабақ картасы
Өз сөзіңізбен айтыңыз
Қарамай, дауыстап немесе қағазға жауап беріңіз. Жауаптар — сабақтың соңында.
- Кестені CSV-ға жазғанда не жоғалады және оны оқығанда қалай қайтарады?
- JSON-ды қашан
read_json-мен емес,json.load-пен оқыған жөн? - pandas та топтай алатын болса,
GROUP BY-ды дерекқорға не үшін қалдырамыз?
Жаттығу
Тапсырмаға дейінгі үш қысқа қадам: болжау, толықтыру, түзету. Жауаптар — сабақтың соңында, бірақ алдымен өзіңіз жауап беріңіз.
1. Болжаңыз. Файл Excel-ден келген, ал оны параметрсіз оқыды. Бағдарлама не басып шығарады?
import io
import pandas as pd
TEXT = "year;rate\n2025;512,3\n2026;519,8\n"
df = pd.read_csv(io.StringIO(TEXT))
print(df)
print("пішіні:", df.shape, "| бағандар:", list(df.columns))
2. Бос орынды толтырыңыз. ... орнына параметрлерді қойыңыз, сонда екі баған және нағыз сандар шықсын.
# нүктелі үтір — бөлгіш, үтір — бөлшек бөлігі
import io
import pandas as pd
TEXT = "year;rate\n2025;512,3\n2026;519,8\n"
df = pd.read_csv(io.StringIO(TEXT), ...)
print("пішіні:", df.shape, "| бағандар:", list(df.columns))
print(dict(df.dtypes.astype(str)))
print(df["rate"].sum())
3. Түзетіңіз. «Жаздық — оқыдық» шеңберінен кейін кестеде артық баған пайда болды. Оны бір параметрмен алып тастаңыз.
# Unnamed: 0 қайдан шықты
import io
import pandas as pd
df = pd.DataFrame({"kind": ["тамақ", "байланыс"], "amount": [1200, 4000]})
buffer = io.StringIO()
df.to_csv(buffer)
print("оқыдық:", pd.read_csv(io.StringIO(buffer.getvalue())).columns.tolist())
Тапсырма
Міндетті. Бағдарлама «бухгалтердің экспортын» өзі жазады — utf-8-sig кодтауындағы, нүктелі үтірі, мыңдықта бос орны, бөлшекте үтірі, дерек жоқ белгісі және артық ескертпе бағаны бар файл:
жыл;санат;сома;ескертпе
2024;тамақ;1 200,50;
2024;байланыс;4 000,00;тариф ауысты
2025;тамақ;1 380,75;
2025;байланыс;дерек жоқ;шот келмеді
Оны бір read_csv шақыруымен оқыңыз: сома сан болсын, дерек жоқ — жетіспейтін мән, ал ескертпе мүлде оқылмасын. Кестені, баған түрлерін және жетіспейтін мәндер санын басып шығарыңыз. Содан кейін индекссіз таза CSV жазыңыз, кестені SQLite-қа салыңыз және сұраныспен жылдар бойынша соманы алыңыз.
Күтілетін шығыс:
оқылды:
жыл санат сома
0 2024 тамақ 1200.50
1 2024 байланыс 4000.00
2 2025 тамақ 1380.75
3 2025 байланыс NaN
түрлері: {'жыл': 'int64', 'санат': 'str', 'сома': 'float64'}
жетіспейтін мән: 1
таза:
жыл,санат,сома
2024,тамақ,1200.5
2024,байланыс,4000.0
2025,тамақ,1380.75
2025,байланыс,
жылдар бойынша:
жыл сома
2024 5200.50
2025 1380.75
Дайын болғаны: шығыс жол-жолымен сәйкес келеді; бәрі жолдағы ауыстырумен емес, read_csv параметрлерімен талданған; сома бағанының түрі str емес, float64; таза файлда жол нөмірлерінің бағаны жоқ; жылдар бойынша сома groupby-мен емес, сұраныспен алынған.
Өз деректеріңізде. Сізге жіберілген кез келген файлды алыңыз — үзінді көшірме, экспорт, есеп. Бес жолын оқыңыз (nrows=5), dtypes-ке қараңыз және сандар сан, күндер күн болатындай параметрлерді таңдаңыз. Нәтижені таза CSV етіп жазыңыз.
Қалауыңыз бойынша.
- Сол кестені үш түрлі
orient-пен JSON-ға сақтап, файлдарды салыстырыңыз. - Өз файлыңызды
dtype={"kod": str}арқылы оқып, алдыңғы нөлдің орнында тұрғанына көз жеткізіңіз. - Кестені SQLite-қа салып, оған
WHEREменGROUP BYбар сұраныс қойыңыз — нәтиже кесте болып келеді.
Жобада бұл қайда тұрады
Сегізінші қадам: дискі кестемен сөйлей бастайды. saqtau.save — бұл float_format-пен және жетіспейтін мәннің орнына бос ұяшықпен жазатын to_csv, saqtau.load — index_col="year" бар read_csv, әрі дискіден сөздік емес, бірден кесте келеді. Есеп те to_csv(index=False) арқылы жазылады.
note бағаны жоғалды: ол n/a белгісін сөзбен түсіндіру үшін бар еді, ал бос ұяшық та соны айтады, әрі read_csv оны сұраусыз NaN-ға айналдырады.
Желіге әзірге қол тигізген жоқпыз: банк бір шағын JSON-мен жауап береді, ал ол үшін json.load бұрынғыдай дұрыс құрал.
Қарыздар. Жиынтықтың дерекқоры әзірге жоқ: жобада to_sql қолданылмайды, дерек сол үшін дайын болса да. Оған да серверге жеткен жерде жетеміз.
Жауаптар
Жауаптарды көрсету
Сұрақтарға
- Индекс пен түрлер жоғалады. Индекс
index_colпараметрімен қайтады, түрлер — күндер үшінparse_dates, ал мәтін мәтін күйінде қалуы маңызды бағандар үшінdtypeарқылы. Жетіспейтін мәндер, олардан өзгеше, жолда өздері аман қалады. - JSON кесте болмағанда: кірістірілген нысандар, қызметтік қаптама, дерек айналасындағы метадерек. Ондайды
json.loadталдайды, ал кесте дайын сөздіктер тізімінен немесеpd.json_normalizeарқылы құрылады. - Өйткені дерекқор жадыға сыюға міндетті емес деректе жұмыс істейді әрі үлкеннің орнына кішкентай нәтиже қайтарады. Бесеуін алу үшін миллион жолды pandas-қа сүйреу — үйде қалдыруға болатын нәрсенің жол ақысын төлеу.
Жаттығуға
- Әдепкі бөлгіш үтір деп саналады, сондықтан
2025;512,3жолы үтір бойынша2025;512және3болып қиылған. Бірінші бөлігі жол белгісіна, екіншісі мәнге айналған, ал кестедегі сандардың бәрі қате. Бағдарлама құлаған жоқ: ол басқа жүйеден келген файлды «сәтті» түрде дұрыс емес оқыды.
year;rate
2025;512 3
2026;519 8
пішіні: (2, 1) | бағандар: ['year;rate']
sep=";", decimal=",". Бірінші параметр жолды дұрыс белгі бойынша қияды, екіншісі сан ішіндегі үтір бөлшек бөлігі екенін түсіндіреді.
import io
import pandas as pd
TEXT = "year;rate\n2025;512,3\n2026;519,8\n"
df = pd.read_csv(io.StringIO(TEXT), sep=";", decimal=",")
print("пішіні:", df.shape, "| бағандар:", list(df.columns))
print(dict(df.dtypes.astype(str)))
print(df["rate"].sum())
пішіні: (2, 2) | бағандар: ['year', 'rate']
{'year': 'int64', 'rate': 'float64'}
1032.1
to_csv(buffer, index=False). Мұндағы жол белгілері жай ғана нөмір, файлда олардың шаруасы жоқ; түскен соң олар атсыз баған болып оқылады да, атын алады:Unnamed: 0.
import io
import pandas as pd
df = pd.DataFrame({"kind": ["тамақ", "байланыс"], "amount": [1200, 4000]})
buffer = io.StringIO()
df.to_csv(buffer)
print("индекспен:", pd.read_csv(io.StringIO(buffer.getvalue())).columns.tolist())
clean = io.StringIO()
df.to_csv(clean, index=False)
print("индекссіз:", pd.read_csv(io.StringIO(clean.getvalue())).columns.tolist())
индекспен: ['Unnamed: 0', 'kind', 'amount']
индекссіз: ['kind', 'amount']
Тапсырмаға
Файлдың төрт ерекшелігінің бәрі бір шақырудың параметрлерімен жабылады: sep=";", decimal=",", thousands=" ", encoding="utf-8-sig", na_values=["дерек жоқ"] және керекті үш баған үшін usecols. Файлды мәтіндегі ауыстырумен тазалау азғырығы — қате: , таңбасын . таңбасына ауыстыру ескертпе ішіндегі кез келген үтірді бүлдіреді, ал келесі жіберушінің жетіспейтін мән белгісі басқаша болады.
Жылдар бойынша сома SELECT жыл, SUM(сома) ... GROUP BY жыл сұранысымен саналады, өйткені дерек дерекқорда тұр, ал дерекқор мұны істей алады.
Дереккөздер
- pandas-тағы кіріс пен шығыс — барлық пішім бірден, мысалдарымен.
- read_csv параметрлерінің толық тізімі — онда елуден астам; білу керегі — оншақты.
- sqlite3 модулі —
read_sqlқабылдайтын байланыс.
Пікірлер (0)
Пікір қалдыру үшін кіріңіз →
Әзірге пікір жоқ. Бірінші болыңыз.