Данные и типы
Прежде чем считать, нужно понять, какие у нас данные.
Строки и столбцы
Заголовок раздела «Строки и столбцы»В таблице orders одна строка — один заказ. Это наблюдение. Один столбец — один признак (переменная): сумма, канал, устройство.
Генеральная совокупность и выборка
Заголовок раздела «Генеральная совокупность и выборка»- Генеральная совокупность — все объекты, о которых мы хотим знать. Например, все заказы магазина за всё время.
- Выборка — часть совокупности, которую мы реально видим. Например, 1000 заказов за три месяца.
Почти всегда мы работаем с выборкой, а выводы хотим сделать про всю совокупность. Для этого нужна статистика. Подробнее — в уроке Выборка и доверительный интервал.
Если выборка собрана плохо, выводы будут неверными. Например, опрос только среди клиентов с мобильным приложением не покажет мнение всех клиентов.
Типы данных
Заголовок раздела «Типы данных»| Тип | Что это | Пример в orders | Что можно считать |
|---|---|---|---|
| Числовой непрерывный | Любое число на шкале | amount, delivery_hours | Среднее, медиана, разброс |
| Числовой дискретный | Целые числа, счёт | items | Среднее, медиана, мода |
| Категориальный | Группы без порядка | channel, device | Количество и доля, мода |
| Порядковый | Группы с порядком | Оценка 1–5, размер S/M/L | Медиана, мода |
| Время | Дата или момент | order_date | Группировка по дням и месяцам |
| Идентификатор | Имя записи | order_id, customer_id | Только считать. Среднее бессмысленно |
Тип определяет, что можно считать. Среднее customer_id посчитать можно, но смысла в нём нет.
Загрузка данных
Заголовок раздела «Загрузка данных»Подготовка: вы в папке stats-practice.
import csv
with open("data/orders.csv") as f: orders = list(csv.DictReader(f))
print(len(orders))
# все суммы как числаamount = [float(row["amount"]) for row in orders]print(amount[:3])
# уникальные каналыchannels = set(row["channel"] for row in orders)print(channels)Ответ (порядок каналов в set может отличаться):
1000[77.62, 34.75, 16.18]{'organic', 'ads', 'email'}[float(row["amount"]) for row in orders] — это генератор списка. Он берёт каждую строку и делает из текста число.
SELECT count(*) AS orders, count(DISTINCT customer_id) AS customersFROM orders;
DESCRIBE orders;
SELECT DISTINCT channel FROM orders;Первый запрос:
orders customers1000 288DESCRIBE показывает, какие типы DuckDB определил сам: amount и delivery_hours — DOUBLE, items — BIGINT, order_date — DATE, channel — VARCHAR.
Практика
Заголовок раздела «Практика»Задание 1
Заголовок раздела «Задание 1»Сколько строк в orders? Сколько разных клиентов (customer_id) сделали заказы? Посчитайте на Python и на SQL.
Проверка: 1000 заказов, 288 клиентов.
Решение
Python:
import csv
with open("data/orders.csv") as f: orders = list(csv.DictReader(f))
print(len(orders))print(len(set(row["customer_id"] for row in orders)))SQL:
SELECT count(*), count(DISTINCT customer_id) FROM orders;Задание 2
Заголовок раздела «Задание 2»Определите тип каждого столбца orders: непрерывный, дискретный, категориальный, время или идентификатор.
Проверка:
| Столбец | Тип |
|---|---|
order_id, customer_id | идентификатор |
order_date | время |
channel, device | категориальный |
items | дискретный |
amount, delivery_hours | непрерывный |
Задание 3
Заголовок раздела «Задание 3»Сколько заказов сделано в феврале 2024? Назовём это задание «на фильтр».
Проверка: 312.
Решение
Python. Дата в файле — текст вида 2024-02-11. Значит, подходит проверка начала строки:
feb = [row for row in orders if row["order_date"].startswith("2024-02")]print(len(feb))SQL:
SELECT count(*)FROM ordersWHERE order_date >= '2024-02-01' AND order_date < '2024-03-01';Задание 4
Заголовок раздела «Задание 4»Сколько заказов пришло через каждый канал? Какой канал самый частый?
Проверка: organic — 386, ads — 360, email — 254. Самый частый — organic.
Решение
Python:
from collections import Counter
print(Counter(row["channel"] for row in orders))Counter считает, сколько раз встретился каждый элемент.
SQL:
SELECT channel, count(*) AS nFROM ordersGROUP BY channelORDER BY n DESC;Дальше: Среднее, медиана, мода.