- Объяснять устройство Series и DataFrame (значения, индекс, столбцы, типы)
- Читать CSV и делать первый обзор данных с помощью
head,info,describeиvalue_counts - Выбирать и сортировать строки и столбцы через
loc,iloc, маски иquery - Создавать новые столбцы векторизованно и без цепочечного присваивания
Айсель ведёт небольшой интернет-магазин канцтоваров. Продажи у неё в таблице Excel: товар, категория, цена, остаток на складе, продано штук. Чтобы на сотнях строк отвечать на вопросы «какая категория приносит больше выручки?» или «что пора заказать снова?», существует библиотека pandas. Она добавляет к массивам NumPy названия столбцов, метки строк и сотни готовых операций над таблицами.
Series и DataFrame
Одномерный массив с метками: значения (массив NumPy) и соответствующий им индекс (метки). У него есть имя (name) и тип (dtype).
Двумерная таблица: набор Series (столбцов) с общим индексом. У каждого столбца может быть свой тип — текст, целое, дробное число, дата.
К элементу Series можно обратиться и по метке (s['Pen']), и по позиции (s.iloc[0]). Арифметика векторизована, как в NumPy. Ниже прибавляем к ценам 18% НДС:
import pandas as pd
prices = pd.Series([1.5, 0.6, 35.0, 49.9],
index=['Notebook', 'Pen', 'Backpack', 'Headphones'],
name='price')
print(prices)
print(prices['Pen'], prices.iloc[-1])
print(prices[prices > 10].index.tolist())
print((prices * 1.18).round(2).tolist())▸ Ожидаемый результат
Notebook 1.5 Pen 0.6 Backpack 35.0 Headphones 49.9 Name: price, dtype: float64 0.6 49.9 ['Backpack', 'Headphones'] [1.77, 0.71, 41.3, 58.88]
Проще всего построить DataFrame из словаря: ключи — названия столбцов, значения — их содержимое. shape — кортеж (строки, столбцы), а dtypes показывает тип каждого столбца. В pandas 3 текстовые столбцы имеют тип str (в старых версиях увидишь object).
import pandas as pd
df = pd.DataFrame({
'name': ['Aysel', 'Murad', 'Leyla'],
'age': [19, 21, 20],
'city': ['Baku', 'Ganja', 'Baku'],
})
print(df)
print(df.shape, df.columns.tolist())
print(df.dtypes)▸ Ожидаемый результат
name age city 0 Aysel 19 Baku 1 Murad 21 Ganja 2 Leyla 20 Baku (3, 3) ['name', 'age', 'city'] name str age int64 city str dtype: object
Чтение CSV и первый взгляд на данные
В реальной работе таблицу читают из файла: pd.read_csv('sales.csv'). В браузере файлов нет, поэтому превращаем текст в «файл» с помощью io.StringIO — для read_csv разницы нет. Каждый блок кода выполняется отдельно, поэтому таблицу создаём в каждом блоке заново. Первый шаг всегда одинаков: head() показывает первые строки, а info() — столбцы, их типы и число непустых значений. Ниже выводим те же сведения по частям: shape, dtypes и count().
import io
import pandas as pd
data = '''product,category,price,stock,sold
Notebook,Stationery,1.5,120,340
Pen,Stationery,0.6,300,820
Backpack,Accessories,35.0,25,48
Headphones,Electronics,49.9,15,37
USB cable,Electronics,6.5,80,150
Mug,Home,8.0,40,95
Desk lamp,Home,27.5,12,20'''
df = pd.read_csv(io.StringIO(data))
print(df.head(3))
print(df.shape)
print(df.dtypes)
print(df.count().tolist())▸ Ожидаемый результат
product category price stock sold 0 Notebook Stationery 1.5 120 340 1 Pen Stationery 0.6 300 820 2 Backpack Accessories 35.0 25 48 (7, 5) product str category str price float64 stock int64 sold int64 dtype: object [7, 7, 7, 7, 7]
read_csv сам определил типы: числа — int64 и float64, текст — str. count() считает непустые значения в каждом столбце — пропусков здесь нет.describe() выдаёт для каждого числового столбца количество, среднее, стандартное отклонение (с делением на n − 1), минимум, квартили и максимум в одной таблице. Для категориального столбца value_counts() считает, сколько раз встречается каждое значение.
import io
import pandas as pd
data = '''product,category,price,stock,sold
Notebook,Stationery,1.5,120,340
Pen,Stationery,0.6,300,820
Backpack,Accessories,35.0,25,48
Headphones,Electronics,49.9,15,37
USB cable,Electronics,6.5,80,150
Mug,Home,8.0,40,95
Desk lamp,Home,27.5,12,20'''
df = pd.read_csv(io.StringIO(data))
print(df.describe().round(2))
print(df['category'].value_counts())▸ Ожидаемый результат
price stock sold count 7.00 7.00 7.00 mean 18.43 84.57 215.71 std 19.16 102.74 288.06 min 0.60 12.00 20.00 25% 4.00 20.00 42.50 50% 8.00 40.00 95.00 75% 31.25 100.00 245.00 max 49.90 300.00 820.00 category Stationery 2 Electronics 2 Home 2 Accessories 1 Name: count, dtype: int64
- qуровень: 0,25 (первый квартиль), 0,5 (медиана), 0,75 (третий квартиль)
- x₍ₖ₎k-е значение после сортировки по возрастанию (счёт с 0)
- h«дробная позиция» в отсортированных данных
По умолчанию pandas и NumPy вычисляют квантили линейной интерполяцией между двумя соседними значениями.
Вычисли вручную квартили 25% и 75% столбца price и сравни с результатом describe().
Показать решениеСкрыть решение
q = 0,25: h = 6 · 0,25 = 1,5 → середина между x₍₁₎ = 1,5 и x₍₂₎ = 6,5: 1,5 + 0,5 · 5 = 4,0.
q = 0,75: h = 6 · 0,75 = 4,5 → 27,5 + 0,5 · 7,5 = 31,25.
Медиана: h = 3 → x₍₃₎ = 8,0. Все три совпадают с
describe(). Среднее (18,43) намного больше медианы — несколько дорогих товаров тянут среднее вверх.Выбор: столбцы, loc и iloc
| Запись | Что возвращает |
|---|---|
df['price'] | один столбец — Series |
df[['product', 'price']] | несколько столбцов — DataFrame |
df.loc[row_labels, col_labels] | выбор по меткам; последняя метка среза включается |
df.iloc[row_pos, col_pos] | выбор по позициям; конец среза не включается |
import io
import pandas as pd
data = '''product,category,price,stock,sold
Notebook,Stationery,1.5,120,340
Pen,Stationery,0.6,300,820
Backpack,Accessories,35.0,25,48
Headphones,Electronics,49.9,15,37
USB cable,Electronics,6.5,80,150
Mug,Home,8.0,40,95
Desk lamp,Home,27.5,12,20'''
df = pd.read_csv(io.StringIO(data))
print(df['price'].head(3).tolist())
print(df.loc[2, 'product'], '|', df.iloc[0, 2])
print(df.loc[1:3, 'product':'price'])
print(df.iloc[1:3, 0:2])
df = df.set_index('product')
print(df.loc['Mug', 'price'])▸ Ожидаемый результат
[1.5, 0.6, 35.0]
Backpack | 1.5
product category price
1 Pen Stationery 0.6
2 Backpack Accessories 35.0
3 Headphones Electronics 49.9
product category
1 Pen Stationery
2 Backpack Accessories
8.0loc[1:3] вернул три строки (1, 2, 3), а iloc[1:3] — две (1, 2). После set_index('product') к строкам можно обращаться по названию товара.Фильтрация и сортировка
Строки фильтруем булевыми масками, как в NumPy: условия объединяем через &, |, ~ и берём в скобки. isin проверяет, входит ли значение в список, а query позволяет записать условие строкой. sort_values сортирует по столбцу, а nlargest сразу возвращает n наибольших значений.
import io
import pandas as pd
data = '''product,category,price,stock,sold
Notebook,Stationery,1.5,120,340
Pen,Stationery,0.6,300,820
Backpack,Accessories,35.0,25,48
Headphones,Electronics,49.9,15,37
USB cable,Electronics,6.5,80,150
Mug,Home,8.0,40,95
Desk lamp,Home,27.5,12,20'''
df = pd.read_csv(io.StringIO(data))
cheap = df[df['price'] < 10]
print(cheap[['product', 'price']])
print(df[(df['category'] == 'Electronics') & (df['stock'] < 50)]['product'].tolist())
print(df[df['category'].isin(['Home', 'Accessories'])]['product'].tolist())
print(df.query('price > 20 and sold > 30')[['product', 'sold']])
print(df.sort_values('sold', ascending=False).head(3)[['product', 'sold']])
print(df.nlargest(2, 'price')[['product', 'price']])▸ Ожидаемый результат
product price
0 Notebook 1.5
1 Pen 0.6
4 USB cable 6.5
5 Mug 8.0
['Headphones']
['Backpack', 'Mug', 'Desk lamp']
product sold
2 Backpack 48
3 Headphones 37
product sold
1 Pen 820
0 Notebook 340
4 USB cable 150
product price
3 Headphones 49.9
2 Backpack 35.0Новые столбцы
Новый столбец создаётся присваиванием: df['revenue'] = df['price'] * df['sold'] — без цикла, вычисление идёт по всему столбцу. Для значения по условию используют np.where, а чтобы изменить только часть строк — df.loc[маска, 'столбец'] = значение. rename и drop возвращают новый DataFrame, поэтому результат снова присваиваем переменной.
import io
import numpy as np
import pandas as pd
data = '''product,category,price,stock,sold
Notebook,Stationery,1.5,120,340
Pen,Stationery,0.6,300,820
Backpack,Accessories,35.0,25,48
Headphones,Electronics,49.9,15,37
USB cable,Electronics,6.5,80,150
Mug,Home,8.0,40,95
Desk lamp,Home,27.5,12,20'''
df = pd.read_csv(io.StringIO(data))
df['revenue'] = (df['price'] * df['sold']).round(2)
df['band'] = np.where(df['price'] >= 20, 'high', 'low')
df['status'] = 'ok'
df.loc[df['stock'] < 20, 'status'] = 'reorder'
df = df.rename(columns={'sold': 'units'}).drop(columns=['category'])
print(df)
print(f"Total revenue: {df['revenue'].sum():.2f} AZN")▸ Ожидаемый результат
product price stock units revenue band status 0 Notebook 1.5 120 340 510.0 low ok 1 Pen 0.6 300 820 492.0 low ok 2 Backpack 35.0 25 48 1680.0 high ok 3 Headphones 49.9 15 37 1846.3 high reorder 4 USB cable 6.5 80 150 975.0 low ok 5 Mug 8.0 40 95 760.0 low ok 6 Desk lamp 27.5 12 20 550.0 high reorder Total revenue: 6813.30 AZN
Какой процент общей выручки по таблице выше приходится на категорию Electronics? Посчитай вручную и запиши выражение на pandas.
Показать решениеСкрыть решение
Общая выручка — 6813,3 маната.
Доля = 2821,3 / 6813,3 ≈ 0,414, то есть около 41,4%.
pandas:
df.loc[df['category'] == 'Electronics', 'revenue'].sum() / df['revenue'].sum() (считать нужно до drop, пока столбец category ещё есть).pandas — ежедневный инструмент аналитиков, экономистов, банков, телеком-компаний и научных лабораторий: отчёты, анализ продаж, результаты опросов, журналы датчиков. В следующем уроке займёмся пропусками, группировкой, объединением таблиц и датами.
Прочитай CSV в DataFrame. 1) Выведи списком имена студентов с баллом 80 и выше, отсортированные по баллу по убыванию; 2) выведи средний балл всех студентов, округлённый до 1 знака после запятой.
import io
import pandas as pd
data = '''name,group,score
Aysel,A,91
Murad,B,76
Leyla,A,85
Elvin,B,64
Nigar,A,78
Tural,B,88'''
df = pd.read_csv(io.StringIO(data))
# 1) names with score >= 80, highest first
# 2) mean score, 1 decimal▸ Ожидаемый результат
['Aysel', 'Tural', 'Leyla'] 80.3
Добавь в таблицу заказов кафе столбец total = price * qty. Затем выведи на отдельных строках: 1) название позиции с наибольшим total; 2) список позиций, у которых total больше 25; 3) сумму всех total.
import pandas as pd
orders = pd.DataFrame({
'item': ['tea', 'coffee', 'cake', 'juice'],
'price': [2.5, 4.0, 5.5, 3.0],
'qty': [12, 7, 4, 9],
})
# add the total column, then print the three results▸ Ожидаемый результат
tea ['tea', 'coffee', 'juice'] 107.0
Главное
- Series — одномерный массив с метками, DataFrame — таблица из Series с общим индексом.
- Первый взгляд на новые данные:
head(),info(),describe(),value_counts(). locработает с метками и включает конец среза;ilocработает с позициями и не включает его.- Фильтруй масками (
&,|,~),isinиquery; сортируй черезsort_valuesиnlargest. - Чтобы изменить часть строк, пиши
df.loc[маска, 'столбец'] = значениеи избегай цепочечного присваивания.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.
df.loc[2:4] для DataFrame с индексом 0, 1, 2, …?