Инструменты научных вычислений: массивы и таблицы в Python
Эффективное использование NumPy и Pandas
Как оптимально обрабатывать табличные данные с числовыми массивами?
Наиболее продуктивный подход заключается в совместном применении NumPy для операций над многомерными массивами и Pandas для структурированных таблиц с метками. Таким образом можно выполнять векторизованные вычисления, не прибегая к циклам Python. Например, сначала загружаются данные в DataFrame, затем извлекаются столбцы как массивы NumPy для математических расчетов, после чего результат снова интегрируется в таблицу.
import numpy as np
import pandas as pd
df = pd.read_csv('data.csv')
array = df['price'].to_numpy() # преобразование в массив NumPy
mean_price = np.mean(array)
df['price_normalized'] = (array - mean_price) / np.std(array)Python numpy pandas (numpy и pandas в python)
Пояснение: загрузка данных выполняется одной строкой Pandas, затем столбец конвертируется в массив для векторизованной нормализации. Результат сохраняется как новый столбец DataFrame.
Типичные ошибки:
- Попытка напрямую умножить DataFrame на число – Pandas делает это поэлементно, но при смешивании типов может возникнуть неявное приведение. Рекомендуется использовать .to_numpy() для явного контроля.
- Забывание про пропущенные значения. NumPy не поддерживает NaN по умолчанию в целочисленных массивах. Перед конвертацией следует удалить или заполнить пропуски.
- Использование циклов для обработки строк – это в десятки раз медленнее векторизованных операций.
Как выполнить фильтрацию данных с использованием только Pandas?
Если задача не требует интенсивных численных расчетов, достаточно возможностей Pandas. Логическая индексация и методы .query() позволяют выбирать строки по условиям.
import pandas as pd
df = pd.DataFrame({'A': [1,2,3], 'B': [10,20,30]})
filtered = df[df['A'] > 1] # строки, где A > 1
# или с query:
filtered2 = df.query('A > 1 and B < 25')
Фильтрация не создает копию данных, а возвращает представление. Однако изменение отфильтрованного набора может повлиять на исходный DataFrame – это стоит учитывать.
Проблема:
Цепочка операций с копиями может приводить к неожиданным результатам. Используйте .copy() перед модификацией.
Как создать массив NumPy с заданной структурой?
NumPy предоставляет функции np.zeros, np.ones, np.arange, np.linspace для быстрой генерации массивов.
import numpy as np
a = np.zeros((3,4)) # матрица 3x4 из нулей
b = np.ones((2,3,2)) # трёхмерный массив из единиц
c = np.arange(0, 10, 2) # [0,2,4,6,8]
d = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.]
Пояснение: arange генерирует последовательность с заданным шагом, linspace – равномерное распределение на отрезке. Все функции поддерживают тип данных через параметр dtype.
Ошибка:
При использовании np.arange с нецелым шагом возможны погрешности из-за арифметики с плавающей запятой. Для равномерной сетки лучше применять linspace.
Как объединить несколько таблиц с разной структурой?
Pandas поддерживает SQL-подобные операции слияния через pd.merge(). Это мощнее, чем конкатенация, так как учитывает ключи.
import pandas as pd
orders = pd.DataFrame({'order_id': [1,2], 'customer_id': [101,102]})
customers = pd.DataFrame({'id': [101,102], 'name': ['Alice','Bob']})
merged = pd.merge(orders, customers, left_on='customer_id', right_on='id', how='inner')
print(merged)
Результат: объединенная таблица с именем клиента. Параметр how определяет тип соединения (inner, outer, left, right).
Типичная ошибка:
Несовпадение типов ключей (строка против числа) приводит к пустому результату. Перед слиянием следует привести ключи к одному типу.
Расширенные примеры применения NumPy и Pandas
import numpy as np
import pandas as pd
# Векторизованная замена значений в DataFrame на основе условия
np.random.seed(42)
df = pd.DataFrame(np.random.randn(5,3), columns=['A','B','C'])
df['D'] = np.where(df['A'] > 0, 'positive', 'negative')
print('Исходный DataFrame:')
print(df.head())
# Вывод результата:
# A B C D
# 0 0.496714 0.861736 0.028766 positive
# 1 -0.234153 -0.398063 -0.510058 negative
# 2 -0.239048 0.406690 0.142977 negative
# 3 0.294284 0.779050 0.284340 positive
# 4 -0.871038 -0.202532 -0.007785 negative
A B C D 0 0.496714 0.861736 0.028766 positive 1 -0.234153 -0.398063 -0.510058 negative 2 -0.239048 0.406690 0.142977 negative 3 0.294284 0.779050 0.284340 positive 4 -0.871038 -0.202532 -0.007785 negative
# Группировка с множественными агрегациями
df_group = pd.DataFrame({
'category': ['A','A','B','B','A'],
'value1': [10,20,30,40,50],
'value2': [1,2,3,4,5]
})
agg_funcs = {'value1': ['sum','mean'], 'value2': 'max'}
result = df_group.groupby('category').agg(agg_funcs)
print(result)
value1 value2
sum mean max
category
A 80 26.67 5
B 70 35.00 4
# Работа с временными рядами: создание и скользящее среднее
dates = pd.date_range('2024-01-01', periods=10, freq='D')
ts = pd.Series(np.random.randn(10), index=dates)
rolling_mean = ts.rolling(window=3).mean()
print('Скользящее среднее с окном 3:')
print(pd.concat([ts.rename('original'), rolling_mean.rename('rolling')], axis=1).head(7))
Скользящее среднее с окном 3:
original rolling
2024-01-01 0.496714 NaN
2024-01-02 0.861736 NaN
2024-01-03 0.028766 0.462405
2024-01-04 -0.398063 0.164146
2024-01-05 0.406690 0.012464
2024-01-06 -0.871038 -0.287470
2024-01-07 -0.398063 -0.287470
# Сводная таблица с многомерной группировкой
np.random.seed(0)
df_pivot = pd.DataFrame({
'Year': [2020,2020,2021,2021,2020],
'Quarter': ['Q1','Q2','Q1','Q2','Q1'],
'Product': ['A','A','B','B','B'],
'Sales': np.random.randint(100,500,5)
})
pivot = pd.pivot_table(df_pivot, values='Sales', index='Year', columns='Quarter', aggfunc='sum', fill_value=0, margins=True)
print(pivot)
Quarter Q1 Q2 All Year 2020 326 473 799 2021 218 243 461 All 544 716 1260
# Использование apply с пользовательской функцией на оси
df_apply = pd.DataFrame({'x': [1,2,3], 'y': [4,5,6]})
df_apply['z'] = df_apply.apply(lambda row: row['x']**2 + row['y']**2, axis=1)
print(df_apply)
x y z 0 1 4 17 1 2 5 29 2 3 6 45
# Векторизованное умножение матриц через NumPy
A = np.array([[1,2],[3,4]])
B = np.array([[5,6],[7,8]])
C = np.dot(A, B) # или A @ B
print('Произведение матриц:')
print(C)
Произведение матриц: [[19 22] [43 50]]
# Обработка пропущенных значений с использованием интерполяции
df_nan = pd.DataFrame({'A': [1, np.nan, 3, np.nan, 5]})
df_nan['A_interp'] = df_nan['A'].interpolate(method='linear')
print(df_nan)
A A_interp 0 1.0 1.0 1 NaN 2.0 2 3.0 3.0 3 NaN 4.0 4 5.0 5.0