Практика 1. Базовая работа с форматами данных в Python¶
В этом ноутбуке познакомимся с двумя главными библиотеками для работы с данными:
- numpy: массивы чисел
- pandas: таблицы
и научимся читать и сохранять данные в разных форматах (CSV, JSON, Parquet).
Запускайте ячейки по порядку: Shift + Enter.
import numpy as np
import pandas as pd
1. NumPy: массивы¶
a = np.array([1, 2, 3, 4, 5])
print(a)
print("тип:", type(a))
print("размер:", a.shape)
[1 2 3 4 5] тип: <class 'numpy.ndarray'> размер: (5,)
Операции применяются сразу ко всему массиву, без циклов:
print(a + 10)
print(a * 2)
print(a ** 2)
[11 12 13 14 15] [ 2 4 6 8 10] [ 1 4 9 16 25]
print("сумма: ", a.sum())
print("среднее: ", a.mean())
print("минимум: ", a.min())
print("максимум:", a.max())
сумма: 15 среднее: 3.0 минимум: 1 максимум: 5
Двумерный массив (матрица): строки — объекты, столбцы — признаки.
m = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
])
print(m)
print("форма:", m.shape)
print("первая строка:", m[0])
print("первый столбец:", m[:, 0])
print("элемент [1, 2]:", m[1, 2])
[[1 2 3] [4 5 6] [7 8 9]] форма: (3, 3) первая строка: [1 2 3] первый столбец: [1 4 7] элемент [1, 2]: 6
Фильтрация по условию:
print(a[a > 2])
[3 4 5]
Полезные способы создать массив:
print(np.zeros(3))
print(np.ones(3))
print(np.arange(0, 10, 2))
print(np.linspace(0, 1, 5))
[0. 0. 0.] [1. 1. 1.] [0 2 4 6 8] [0. 0.25 0.5 0.75 1. ]
Задание 1¶
Создайте массив чисел от 1 до 10, возведите все числа в квадрат и найдите их сумму.
# ваш код
2. Pandas: таблицы¶
Series— один столбецDataFrame— вся таблица
s = pd.Series([10, 20, 30], name="числа")
s
0 10 1 20 2 30 Name: числа, dtype: int64
df = pd.DataFrame({
"имя": ["Аня", "Борис", "Вера", "Глеб", "Дина"],
"возраст": [23, 31, 27, 45, 38],
"город": ["Москва", "Казань", "Москва", "Сочи", "Казань"],
"зарплата": [90000, 120000, 105000, None, 98000],
})
df
| имя | возраст | город | зарплата | |
|---|---|---|---|---|
| 0 | Аня | 23 | Москва | 90000.0 |
| 1 | Борис | 31 | Казань | 120000.0 |
| 2 | Вера | 27 | Москва | 105000.0 |
| 3 | Глеб | 45 | Сочи | NaN |
| 4 | Дина | 38 | Казань | 98000.0 |
Осмотр таблицы¶
print("форма:", df.shape)
df.head(3)
форма: (5, 4)
| имя | возраст | город | зарплата | |
|---|---|---|---|---|
| 0 | Аня | 23 | Москва | 90000.0 |
| 1 | Борис | 31 | Казань | 120000.0 |
| 2 | Вера | 27 | Москва | 105000.0 |
df.info()
<class 'pandas.DataFrame'> RangeIndex: 5 entries, 0 to 4 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 имя 5 non-null str 1 возраст 5 non-null int64 2 город 5 non-null str 3 зарплата 4 non-null float64 dtypes: float64(1), int64(1), str(2) memory usage: 388.0 bytes
df.describe()
| возраст | зарплата | |
|---|---|---|
| count | 5.000000 | 4.000000 |
| mean | 32.800000 | 103250.000000 |
| std | 8.786353 | 12737.739203 |
| min | 23.000000 | 90000.000000 |
| 25% | 27.000000 | 96000.000000 |
| 50% | 31.000000 | 101500.000000 |
| 75% | 38.000000 | 108750.000000 |
| max | 45.000000 | 120000.000000 |
Столбцы и строки¶
print(df["имя"])
0 Аня 1 Борис 2 Вера 3 Глеб 4 Дина Name: имя, dtype: str
df[["имя", "возраст"]]
| имя | возраст | |
|---|---|---|
| 0 | Аня | 23 |
| 1 | Борис | 31 |
| 2 | Вера | 27 |
| 3 | Глеб | 45 |
| 4 | Дина | 38 |
df.loc[0] # строка по номеру индекса
имя Аня возраст 23 город Москва зарплата 90000.0 Name: 0, dtype: object
df[df["возраст"] > 30] # фильтр
| имя | возраст | город | зарплата | |
|---|---|---|---|---|
| 1 | Борис | 31 | Казань | 120000.0 |
| 3 | Глеб | 45 | Сочи | NaN |
| 4 | Дина | 38 | Казань | 98000.0 |
df[(df["город"] == "Москва") & (df["возраст"] > 25)] # несколько условий
| имя | возраст | город | зарплата | |
|---|---|---|---|---|
| 2 | Вера | 27 | Москва | 105000.0 |
Новые столбцы и сортировка¶
df["возраст_через_5_лет"] = df["возраст"] + 5
df.sort_values("возраст", ascending=False)
| имя | возраст | город | зарплата | возраст_через_5_лет | |
|---|---|---|---|---|---|
| 3 | Глеб | 45 | Сочи | NaN | 50 |
| 4 | Дина | 38 | Казань | 98000.0 | 43 |
| 1 | Борис | 31 | Казань | 120000.0 | 36 |
| 2 | Вера | 27 | Москва | 105000.0 | 32 |
| 0 | Аня | 23 | Москва | 90000.0 | 28 |
Группировка¶
df.groupby("город")["возраст"].mean()
город Казань 34.5 Москва 25.0 Сочи 45.0 Name: возраст, dtype: float64
df["город"].value_counts()
город Москва 2 Казань 2 Сочи 1 Name: count, dtype: int64
Пропуски¶
print(df.isna().sum())
имя 0 возраст 0 город 0 зарплата 1 возраст_через_5_лет 0 dtype: int64
# заполнить средним
df["зарплата"] = df["зарплата"].fillna(df["зарплата"].mean())
df
| имя | возраст | город | зарплата | возраст_через_5_лет | |
|---|---|---|---|---|---|
| 0 | Аня | 23 | Москва | 90000.0 | 28 |
| 1 | Борис | 31 | Казань | 120000.0 | 36 |
| 2 | Вера | 27 | Москва | 105000.0 | 32 |
| 3 | Глеб | 45 | Сочи | 103250.0 | 50 |
| 4 | Дина | 38 | Казань | 98000.0 | 43 |
Задание 2¶
- Выберите людей старше 25 лет.
- Найдите среднюю зарплату по городам.
- Добавьте столбец
зарплата_в_год(зарплата × 12).
# ваш код
3. Форматы данных¶
Одни и те же данные можно сохранить в разных форматах:
| Формат | Что это |
|---|---|
| CSV | обычный текст, значения через запятую |
| JSON | текст со структурой «ключ: значение» |
| Parquet | компактный бинарный формат для больших таблиц; хранит типы столбцов и быстро читается |
CSV¶
df.to_csv("people.csv", index=False)
print(open("people.csv", encoding="utf-8").read())
имя,возраст,город,зарплата,возраст_через_5_лет Аня,23,Москва,90000.0,28 Борис,31,Казань,120000.0,36 Вера,27,Москва,105000.0,32 Глеб,45,Сочи,103250.0,50 Дина,38,Казань,98000.0,43
df_csv = pd.read_csv("people.csv")
df_csv
| имя | возраст | город | зарплата | возраст_через_5_лет | |
|---|---|---|---|---|---|
| 0 | Аня | 23 | Москва | 90000.0 | 28 |
| 1 | Борис | 31 | Казань | 120000.0 | 36 |
| 2 | Вера | 27 | Москва | 105000.0 | 32 |
| 3 | Глеб | 45 | Сочи | 103250.0 | 50 |
| 4 | Дина | 38 | Казань | 98000.0 | 43 |
JSON¶
df.to_json("people.json", orient="records", force_ascii=False, indent=2)
print(open("people.json", encoding="utf-8").read())
[
{
"имя":"Аня",
"возраст":23,
"город":"Москва",
"зарплата":90000.0,
"возраст_через_5_лет":28
},
{
"имя":"Борис",
"возраст":31,
"город":"Казань",
"зарплата":120000.0,
"возраст_через_5_лет":36
},
{
"имя":"Вера",
"возраст":27,
"город":"Москва",
"зарплата":105000.0,
"возраст_через_5_лет":32
},
{
"имя":"Глеб",
"возраст":45,
"город":"Сочи",
"зарплата":103250.0,
"возраст_через_5_лет":50
},
{
"имя":"Дина",
"возраст":38,
"город":"Казань",
"зарплата":98000.0,
"возраст_через_5_лет":43
}
]
df_json = pd.read_json("people.json")
df_json
| имя | возраст | город | зарплата | возраст_через_5_лет | |
|---|---|---|---|---|---|
| 0 | Аня | 23 | Москва | 90000 | 28 |
| 1 | Борис | 31 | Казань | 120000 | 36 |
| 2 | Вера | 27 | Москва | 105000 | 32 |
| 3 | Глеб | 45 | Сочи | 103250 | 50 |
| 4 | Дина | 38 | Казань | 98000 | 43 |
Обычный JSON (не таблица) можно читать стандартным модулем json, он превращает файл в словарь:
import json
data = {"название": "Мой проект", "версия": 1, "теги": ["данные", "python"]}
with open("config.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
with open("config.json", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded)
print(loaded["теги"][0])
{'название': 'Мой проект', 'версия': 1, 'теги': ['данные', 'python']}
данные
Parquet¶
Parquet — современный формат для хранения таблиц в ML и анализе данных. В отличие от CSV он запоминает типы столбцов и занимает меньше места. Для работы нужна библиотека pyarrow (в Google Colab она уже установлена, локально: pip install pyarrow).
df.to_parquet("people.parquet", index=False)
df_parquet = pd.read_parquet("people.parquet")
df_parquet
| имя | возраст | город | зарплата | возраст_через_5_лет | |
|---|---|---|---|---|---|
| 0 | Аня | 23 | Москва | 90000.0 | 28 |
| 1 | Борис | 31 | Казань | 120000.0 | 36 |
| 2 | Вера | 27 | Москва | 105000.0 | 32 |
| 3 | Глеб | 45 | Сочи | 103250.0 | 50 |
| 4 | Дина | 38 | Казань | 98000.0 | 43 |
Из таблицы в numpy и обратно¶
arr = df[["возраст", "зарплата"]].to_numpy()
print(arr)
print(arr.shape)
[[2.3000e+01 9.0000e+04] [3.1000e+01 1.2000e+05] [2.7000e+01 1.0500e+05] [4.5000e+01 1.0325e+05] [3.8000e+01 9.8000e+04]] (5, 2)
pd.DataFrame(arr, columns=["возраст", "зарплата"])
| возраст | зарплата | |
|---|---|---|
| 0 | 23.0 | 90000.0 |
| 1 | 31.0 | 120000.0 |
| 2 | 27.0 | 105000.0 |
| 3 | 45.0 | 103250.0 |
| 4 | 38.0 | 98000.0 |
Массивы numpy тоже можно сохранять:
np.save("arr.npy", arr)
print(np.load("arr.npy"))
[[2.3000e+01 9.0000e+04] [3.1000e+01 1.2000e+05] [2.7000e+01 1.0500e+05] [4.5000e+01 1.0325e+05] [3.8000e+01 9.8000e+04]]
Задание 3¶
- Сохраните таблицу
dfв файлresult.csv. - Прочитайте его обратно в новую переменную и проверьте, что
shapeсовпадает. - Сохраните её же в
result.parquet, прочитайте обратно и сравните размеры файловresult.csvиresult.parquet(подсказка:os.path.getsize).
# ваш код
4. Мини-итог¶
numpy— быстрые операции над массивами чиселpandas— таблицы:head,info,describe, фильтры,groupby, пропуски- Читаем и пишем:
read_csv/to_csv,read_json/to_json,read_parquet/to_parquet - Прежде чем что-то делать с данными, их нужно осмотреть:
shape,head,info,describe