Разбор задач с собеседований по статистике для Дата Саентистов

В современных собеседованиях на позицию Data Scientist кандидатов проверяют не только практические навыки программирования, но и глубокое понимание статистических методов. В данной статье рассмотрены часто встречающиеся задач, которые могут встретиться на интервью. Разберём каждую задачу с теоретической точки зрения, а также продемонстрируем пример кода на Python.
Задача 1. Корректировка на множественные сравнения при тестировании гипотез
Суть задачи:
При одновременном проведении нескольких тестов (например, сравнение средних между группами) вероятность ошибки первого рода (ложноположительного результата) растёт. Необходимо правильно провести множественную корректировку (например, с помощью метода Бонферрони или FDR).
Что нужно знать:
- p-value – вероятность получить наблюдаемый результат (или более экстремальный) при условии, что нулевая гипотеза верна.
- Ошибка первого рода (α-ошибка) – вероятность отвергнуть верную нулевую гипотезу.
- Метод Бонферрони корректирует уровень значимости, деля его на число тестов.
Пример кода на Python:
В этом примере сгенерируем синтетические данные для нескольких групп и проведём t-тесты с корректировкой p-value методом Бонферрони.
import numpy as np
from scipy.stats import ttest_ind
from statsmodels.stats.multitest import multipletests
# Генерируем данные для 4 групп
np.random.seed(42)
group1 = np.random.normal(loc=0, scale=1, size=100)
group2 = np.random.normal(loc=0.2, scale=1, size=100)
group3 = np.random.normal(loc=0, scale=1, size=100)
group4 = np.random.normal(loc=-0.1, scale=1, size=100)
groups = [group1, group2, group3, group4]n_groups = len(groups)
p_values = []
# Сравниваем все пары групп
for i in range(n_groups):
for j in range(i+1, n_groups):
stat, p = ttest_ind(groups[i], groups[j])
p_values.append(p)
print(f"Сравнение группы {i+1} vs {j+1}: p-value = {p:.4f}")
# Корректировка методом Бонферрони
adjusted = multipletests(p_values, method='bonferroni')
print("\nКорректированные p-value:", adjusted[1])
Комментарий:
После корректировки вы получите скорректированные значения p-value, которые помогут избежать ложных открытий при одновременной проверке нескольких гипотез.
Задача 2. Байесовская оценка параметров
Суть задачи:
Рассмотрим задачу оценивания параметра θ\thetaθ некоторого распределения с использованием Байесовского подхода. Например, пусть у нас есть наблюдения из биномиального процесса, и требуется оценить вероятность успеха.
Что нужно знать:
- Апостериорное распределение: обновление априорного распределения с учётом наблюдаемых данных с помощью теоремы Байеса.
- Для биномиального процесса удобно использовать сопряжённое априорное распределение – бета-распределение.
Пример кода на Python (оценка доли успехов):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import beta
# Пусть априорное распределение theta ~ Beta(1, 1) (равномерное)
a_prior, b_prior = 1, 1
# Наблюдения: 20 испытаний, 14 успехов
n = 20
successes = 14
# Апостериорное распределение: Beta(a + successes, b + n - successes)
a_post = a_prior + successes
b_post = b_prior + n - successes
# Вычисляем значения для построения графика
theta = np.linspace(0, 1, 100)
posterior_pdf = beta.pdf(theta, a_post, b_post)
plt.plot(theta, posterior_pdf, label='Апостериорное распределение')
plt.xlabel('θ')
plt.ylabel('Плотность')
plt.title('Байесовский вывод для оценки параметра θ')
plt.legend()
plt.show()
print(f"Оценка параметра θ (мода апостериорного распределения): {(a_post - 1) / (a_post + b_post - 2):.3f}")
Комментарий:
Данный подход позволяет не только получить точечную оценку, но и охарактеризовать неопределённость параметра через апостериорное распределение.
Задача 3. Оценка мультиколлинеарности в регрессионном анализе
Суть задачи:
При построении множественной линейной регрессии важно проверять наличие мультиколлинеарности – сильной корреляции между предикторами. Одним из способов диагностики является вычисление коэффициента инфляции дисперсии (Variance Inflation Factor, VIF).
Что нужно знать:
- VIF: если значение VIF больше 5-10, это сигнал о потенциальной мультиколлинеарности.
- Проблема мультиколлинеарности может привести к нестабильным оценкам коэффициентов модели.
Пример кода на Python:
Сгенерируем синтетические данные с коррелированными признаками и вычислим VIF для каждого.
import numpy as np
import pandas as pd
from statsmodels.stats.outliers_influence import variance_inflation_factor
# Генерация синтетических данных
np.random.seed(42)
n_samples = 100
X1 = np.random.normal(0, 1, n_samples)
X2 = 0.8 * X1 + np.random.normal(0, 0.5, n_samples) # X2 сильно коррелирован с X1
X3 = np.random.normal(0, 1, n_samples)
data = pd.DataFrame({'X1': X1, 'X2': X2, 'X3': X3})
# Вычисляем VIF для каждого признака
vif_data = pd.DataFrame()
vif_data["feature"] = data.columns
vif_data["VIF"] = [variance_inflation_factor(data.values, i) for i in range(data.shape[1])]
print(vif_data)
Комментарий:
Анализ VIF помогает выявить признаки, вызывающие проблемы в регрессионной модели, и принять решение о их исключении или использовании методов регуляризации.
Задача 4. Применение бутстраппинга для оценки доверительных интервалов
Суть задачи:
Бутстраппинг – это метод повторной выборки с возвращением, позволяющий оценивать статистическую неопределённость без предположений о распределении исходных данных.
Что нужно знать:
- Бутстрап позволяет получить распределение оценок (например, среднего) и построить доверительные интервалы.
- Применим этот метод для оценки среднего значения выборки.
Пример кода на Python:
В примере продемонстрируем, как с помощью бутстраппинга оценить 95% доверительный интервал для среднего значения.
import numpy as np
# Генерируем синтетические данные
np.random.seed(42)
data = np.random.normal(loc=10, scale=2, size=200)
# Функция для вычисления среднего
def bootstrap_mean(data, n_bootstrap=1000):
means = [] n = len(data)
for _ in range(n_bootstrap):
sample = np.random.choice(data, size=n, replace=True)
means.append(np.mean(sample))
return np.array(means)
bootstrap_means = bootstrap_mean(data, n_bootstrap=10000)
# Вычисляем 95% доверительный интервал
lower_bound = np.percentile(bootstrap_means, 2.5)
upper_bound = np.percentile(bootstrap_means, 97.5)
print(f"95% доверительный интервал для среднего: [{lower_bound:.3f}, {upper_bound:.3f}]")
Комментарий:
Бутстраппинг удобен, когда классические предположения о распределении данных не выполняются. Этот метод широко применяется для оценки нестандартных статистик и доверительных интервалов.
Задача 5. Проверка стационарности временных рядов с помощью теста Дики-Фуллера (ADF)
Суть задачи:
В анализе временных рядов важно определить, является ли ряд стационарным. Тест Дики-Фуллера помогает проверить гипотезу о наличии единичного корня в ряду.
Что нужно знать:
- Стационарность: временной ряд считается стационарным, если его статистические характеристики (среднее, дисперсия) не изменяются во времени.
- Тест ADF: нулевая гипотеза – наличие единичного корня (ряд нестационарен); маленький p-value позволяет отвергнуть нулевую гипотезу.
Пример кода на Python:
Используем синтетический временной ряд и проведём тест ADF с помощью функции adfuller
из statsmodels.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
# Генерируем синтетический временной ряд с трендом (нестабилен)
np.random.seed(42)
n = 200
trend = np.linspace(0, 10, n)
noise = np.random.normal(0, 1, n)
time_series = trend + noise
# Проведем тест ADF
result = adfuller(time_series)
print("ADF статистика:", result[0])
print("p-value:", result[1])
# Визуализация временного ряда
plt.plot(time_series)
plt.title("Синтетический временной ряд")
plt.xlabel("Время")
plt.ylabel("Значение")
plt.show()
Комментарий:
Если p-value теста ADF окажется выше стандартного уровня значимости (например, 0.05), нельзя отвергнуть гипотезу о нестационарности ряда. В таком случае требуется преобразование данных (например, дифференцирование) для дальнейшего анализа.
Задача 6. Проверка нормальности распределения
Суть задачи:
Многие статистические тесты предполагают нормальность данных. Нужно проверить, являются ли данные нормально распределёнными.
Что нужно знать:
- Тест Шапиро-Уилка (Shapiro-Wilk test): проверяет гипотезу о нормальности.
- Тест Колмогорова-Смирнова: сравнивает распределение выборки с заданным (например, нормальным).
- Q-Q plot (Квантиль-квантиль график): позволяет визуально оценить соответствие нормальному распределению.
Пример кода на Python:
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
# Генерируем данные
np.random.seed(42)
data = np.random.normal(0, 1, 100) # Данные из нормального распределения
# Тест Шапиро-Уилка
stat, p = stats.shapiro(data)
print(f"Shapiro-Wilk test: W={stat:.4f}, p-value={p:.4f}")
# Q-Q plot
stats.probplot(data, dist="norm", plot=plt)
plt.title("Q-Q Plot")
plt.show()
Интерпретация:
- Если p-value > 0.05, то нет оснований отвергнуть гипотезу нормальности.
- Q-Q plot должен быть близким к диагональной линии.
Задача 7. Доверительный интервал для дисперсии
Суть задачи:
Нужно построить доверительный интервал для дисперсии нормального распределения.
Что нужно знать:
- Статистика хи-квадрат (χ2\chi^2χ2): (n−1)S2χα/2,n−12<σ2<(n−1)S2χ1−α/2,n−12\frac{(n-1)S^2}{\chi^2_{\alpha/2, n-1}} < \sigma^2 < \frac{(n-1)S^2}{\chi^2_{1-\alpha/2, n-1}}χα/2,n−12(n−1)S2<σ2<χ1−α/2,n−12(n−1)S2
- Используется для оценки разброса данных.
Пример кода на Python:
import numpy as np
import scipy.stats as stats
# Генерируем данные
np.random.seed(42)
data = np.random.normal(10, 3, 50) # Среднее 10, стандартное отклонение 3
# Оценки параметров
n = len(data)
sample_variance = np.var(data, ddof=1) # Оценка дисперсии
alpha = 0.05 # Уровень значимости
# Доверительный интервал
chi2_lower = stats.chi2.ppf(alpha/2, df=n-1)
chi2_upper = stats.chi2.ppf(1-alpha/2, df=n-1)
lower_bound = (n-1) * sample_variance / chi2_upper
upper_bound = (n-1) * sample_variance / chi2_lower
print(f"95% доверительный интервал для дисперсии: ({lower_bound:.2f}, {upper_bound:.2f})")
Вывод:
Если доверительный интервал слишком широк, значит, выборка небольшая или дисперсия сильно варьируется.
Задача 8. Выбор количества кластеров в K-means (метод локтя)
Суть задачи:
Нужно выбрать оптимальное количество кластеров для алгоритма K-means.
Что нужно знать:
- Метод локтя (Elbow Method): выбираем число кластеров, при котором инерция (сумма квадратов расстояний до центроидов) перестаёт значительно уменьшаться.
Пример кода на Python:
Редактироватьimport numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# Генерация данных
np.random.seed(42)
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60)
# Метод локтя
inertia = []K = range(1, 10)
for k in K:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(X)
inertia.append(kmeans.inertia_)
# График метода локтя
plt.plot(K, inertia, 'bo-')
plt.xlabel('Количество кластеров')
plt.ylabel('Инерция')
plt.title('Метод локтя')
plt.show()
Вывод:
Оптимальное число кластеров находится в точке «излома» графика.
Задача 9. Определение выбросов с помощью межквартильного размаха (IQR)
Суть задачи:
Нужно выявить аномальные наблюдения в данных.
Что нужно знать:
- IQR (Interquartile Range) – размах между первым (Q1) и третьим (Q3) квартилями.
- Точка выброса: нижняя граница=Q1−1.5×IQR\text{нижняя граница} = Q1 – 1.5 \times IQRнижняя граница=Q1−1.5×IQR верхняя граница=Q3+1.5×IQR\text{верхняя граница} = Q3 + 1.5 \times IQRверхняя граница=Q3+1.5×IQR
Пример кода на Python:
import numpy as np
import matplotlib.pyplot as plt
# Генерируем данные
np.random.seed(42)
data = np.append(np.random.normal(10, 2, 100), [30, 35]) # Добавили выбросы
# Вычисляем IQR
Q1 = np.percentile(data, 25)
Q3 = np.percentile(data, 75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# Выводим выбросы
outliers = data[(data < lower_bound) | (data > upper_bound)]print(f"Выбросы: {outliers}")
# Визуализация (Boxplot)
plt.boxplot(data, vert=False)
plt.title("Boxplot с выбросами")
plt.show()
Вывод:
Выбросы можно обработать, удалив их или заменив медианой.
Задача 10. Байесовский A/B-тест
Суть задачи:
Нужно провести A/B-тест с использованием Байесовского подхода.
Что нужно знать:
- В Байесовском A/B-тесте вероятность успеха модели A и B представляют бета-распределениями.
- Мы вычисляем вероятность, что вариант B лучше A.
Пример кода на Python:
import numpy as np
import scipy.stats as stats
# Данные эксперимента: клики / показы
A_clicks, A_impressions = 200, 1000
B_clicks, B_impressions = 250, 1000
# Байесовские априорные параметры (Beta(1,1) - неинформативный)
alpha_A, beta_A = 1 + A_clicks, 1 + A_impressions - A_clicks
alpha_B, beta_B = 1 + B_clicks, 1 + B_impressions - B_clicks
# Генерация выборок из апостериорных распределений
samples_A = np.random.beta(alpha_A, beta_A, 10000)
samples_B = np.random.beta(alpha_B, beta_B, 10000)
# Вероятность того, что B лучше A
prob_B_better = np.mean(samples_B > samples_A)
print(f"Вероятность, что B лучше A: {prob_B_better:.4f}")
Вывод:
Если вероятность, что B лучше A, больше 95%, можно сделать вывод в пользу варианта B.
Задача 11. Анализ влияния выбросов на регрессионную модель с помощью диагностики Кука
Суть задачи:
Выбросы могут существенно влиять на оценку коэффициентов линейной регрессии. Один из способов выявления таких наблюдений – вычисление расстояния Кука (Cook’s distance).
Основные моменты:
- Cook’s distance оценивает влияние каждого наблюдения на параметры модели.
- Значения, превышающие ориентировочную границу (например, 4n\frac{4}{n}n4, где nnn – число наблюдений), сигнализируют о потенциально влияющих точках.
Пример кода на Python:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm
# Генерируем синтетические данные
np.random.seed(42)
n = 100
X = np.random.normal(0, 1, n)
y = 2 * X + np.random.normal(0, 1, n)
# Вносим выбросы в первые 5 наблюдений
X[0:5] += 10
y[0:5] += 10
df = pd.DataFrame({'X': X, 'y': y})
X_with_const = sm.add_constant(df['X'])
model = sm.OLS(df['y'], X_with_const).fit()
# Вычисляем влияние наблюдений
influence = model.get_influence()
cooks = influence.cooks_distance[0]
# Визуализируем расстояния Кука
plt.stem(np.arange(len(cooks)), cooks, markerfmt=",")
plt.axhline(4/n, color='red', linestyle='--', label='Порог (4/n)')
plt.xlabel('Наблюдение')
plt.ylabel("Расстояние Кука")
plt.legend()
plt.title("Диагностика влияния наблюдений (Cook's Distance)")
plt.show()
Комментарий:
Анализ Cook’s distance позволяет выявить наблюдения, которые непропорционально влияют на модель, что может потребовать их дальнейшего изучения или корректировки модели.
Задача 12. Непараметрический тест Манна–Уитни для сравнения двух независимых выборок
Суть задачи:
Когда предположение о нормальности данных нарушается, для сравнения двух выборок можно использовать непараметрический тест Манна–Уитни.
Основные моменты:
- Тест проверяет нулевую гипотезу о равенстве распределений двух групп.
- Подходит для выборок с различными распределениями и маленькими размерами.
Пример кода на Python:
import numpy as np
from scipy.stats import mannwhitneyu
np.random.seed(42)
# Генерируем две независимые выборки
group1 = np.random.normal(0, 1, 50)
group2 = np.random.normal(0.5, 1, 50)
stat, p = mannwhitneyu(group1, group2, alternative='two-sided')
print(f"Mann–Whitney U-тест: статистика = {stat:.2f}, p-value = {p:.4f}")
Комментарий:
Если p-valuep\text{-value}p-value оказывается меньше выбранного уровня значимости (например, 0.05), можно заключить, что распределения выборок статистически различаются.
Задача 13. Jackknife-ресемплинг для оценки смещения и дисперсии оценок
Суть задачи:
Jackknife – метод ресемплинга, позволяющий оценить смещение и дисперсию статистической оценки, исключая по одному наблюдению из выборки.
Основные моменты:
- Метод последовательно исключает каждое наблюдение, вычисляя оценку на “почти полной” выборке.
- Используется для оценки стандартной ошибки и устойчивости модели.
Пример кода на Python:
import numpy as np
np.random.seed(42)
data = np.random.normal(10, 2, 100)
n = len(data)
jackknife_means = np.empty(n)
for i in range(n):
jackknife_sample = np.delete(data, i)
jackknife_means[i] = np.mean(jackknife_sample)
jackknife_mean = np.mean(jackknife_means)
jackknife_var = (n - 1) / n * np.sum((jackknife_means - jackknife_mean)**2)
jackknife_std = np.sqrt(jackknife_var)
print(f"Jackknife оценка среднего: {jackknife_mean:.3f}")
print(f"Jackknife стандартная ошибка: {jackknife_std:.3f}")
Комментарий:
Метод Jackknife позволяет получить представление о стабильности оценок, что особенно важно при небольших выборках или при наличии выбросов.
Задача 14. Тест Мардии для проверки многомерной нормальности
Суть задачи:
Для задач, связанных с многомерными данными (например, множественная регрессия или кластеризация), важно проверить гипотезу о многомерной нормальности. Тест Мардии анализирует отклонения по асимметрии и эксцессу.
Основные моменты:
- Мardia’s skewness и kurtosis используются для оценки многомерной нормальности.
- Если p-valuep\text{-value}p-value теста меньше уровня значимости, можно отвергнуть гипотезу о нормальности.
Пример кода на Python:
Примечание: Для выполнения теста используется библиотека pingouin. Если она не установлена, выполните
pip install pingouin
.
import numpy as np
import pandas as pd
import pingouin as pg
# Генерируем многомерные данные (3 признака)
np.random.seed(42)
data = np.random.multivariate_normal([0, 0, 0], np.eye(3), size=200)
df = pd.DataFrame(data, columns=['X1', 'X2', 'X3'])
# Тест Мардии для многомерной нормальности
stat, p_value, skew, kurtosis = pg.multivariate_normality(df, alpha=0.05)
print(f"Mardia's test: статистика = {stat:.3f}, p-value = {p_value:.3f}")
Комментарий:
Этот тест помогает оценить, насколько данные соответствуют многомерному нормальному распределению, что является важным предположением для многих методов анализа.
Задача 15. Перестановочный тест для проверки разницы медиан двух выборок
Суть задачи:
Перестановочный (или permutation) тест – непараметрический метод, позволяющий проверить гипотезу о равенстве медиан двух групп без предположения о нормальности данных.
Основные моменты:
- Вычисляется наблюдаемая разница медиан между группами.
- Затем происходит случайное перемешивание (перестановка) меток групп для оценки распределения разницы под нулевой гипотезой.
Пример кода на Python:
import numpy as np
np.random.seed(42)
# Генерируем две выборки с разными медианами
group1 = np.random.normal(10, 2, 50)
group2 = np.random.normal(12, 2, 50)
# Наблюдаемая разница медиан
obs_diff = np.median(group2) - np.median(group1)
print(f"Наблюдаемая разница медиан: {obs_diff:.3f}")
# Перестановочный тест
n_permutations = 10000
combined = np.concatenate([group1, group2])
diffs = np.empty(n_permutations)
n1 = len(group1)
for i in range(n_permutations):
np.random.shuffle(combined)
perm_group1 = combined[:n1] perm_group2 = combined[n1:] diffs[i] = np.median(perm_group2) - np.median(perm_group1)
p_value = np.mean(np.abs(diffs) >= np.abs(obs_diff))
print(f"p-value перестановочного теста: {p_value:.4f}")
Комментарий:
Если p-valuep\text{-value}p-value оказывается маленьким (например, < 0.05), можно сделать вывод о статистически значимой разнице медиан между группами.
Задача 16. Оценка причинно-следственного эффекта с помощью инструментальных переменных
Суть задачи:
При наличии эндогенности (например, когда объясняющая переменная коррелирует с ошибкой модели) стандартные регрессионные оценки могут быть смещёнными. Для корректной оценки причинно-следственных эффектов применяется метод инструментальных переменных (IV), который использует внешнюю переменную (инструмент), удовлетворяющую двум условиям:
- Инструмент коррелирован с эндогенной переменной.
- Инструмент не коррелирован с ошибкой модели.
Пример кода на Python:
В данном примере используется метод двухшаговой регрессии. Для демонстрации применяется библиотека linearmodels (при необходимости установите её через pip).
import numpy as np
import pandas as pd
from linearmodels.iv import IV2SLS
# Генерация синтетических данных
np.random.seed(42)
n = 500
# Инструмент Z
Z = np.random.normal(0, 1, n)
# Эндогенная переменная X генерируется с влиянием Z и случайным шумом
X = 0.8 * Z + np.random.normal(0, 1, n)
# Ошибка, коррелирующая с X (эндогенность)
epsilon = np.random.normal(0, 1, n)
# Зависимая переменная Y
Y = 2 * X + epsilon
data = pd.DataFrame({'Y': Y, 'X': X, 'Z': Z})
# Модель IV (двухшаговая регрессия)
# Формула: Y ~ 1 + [X ~ Z]iv_model = IV2SLS.from_formula('Y ~ 1 + [X ~ Z]', data=data).fit()
print(iv_model.summary)
Комментарий:
Использование инструментария IV позволяет корректно оценить коэффициент влияния XXX на YYY, устраняя смещение, вызванное эндогенностью.
Задача 17. Байесовская иерархическая модель для анализа групповых данных
Суть задачи:
При наличии данных, сгруппированных по категориям (например, ученики по классам, пациенты по клиникам), часто наблюдается вариативность как на уровне группы, так и на уровне наблюдений. Байесовские иерархические модели позволяют учитывать эту структуру, моделируя как индивидуальные, так и групповые эффекты.
Пример кода на Python с использованием библиотеки PyMC3:
Ниже приведён упрощённый пример, где данные генерируются для нескольких групп, а модель оценивает общую среднюю и групповые отклонения.
import numpy as np
import pymc3 as pm
import matplotlib.pyplot as plt
# Генерация синтетических данных
np.random.seed(42)
n_groups = 5
n_per_group = 50
true_mu = 10
true_sigma = 2
group_effects = np.random.normal(0, 1, n_groups)
data = []group_idx = []for i in range(n_groups):
group_data = np.random.normal(true_mu + group_effects[i], true_sigma, n_per_group)
data.append(group_data)
group_idx.extend([i]*n_per_group)
data = np.concatenate(data)
# Байесовская иерархическая модель
with pm.Model() as hierarchical_model:
# Глобальные гиперпараметры
mu = pm.Normal('mu', mu=0, sigma=10)
sigma = pm.HalfNormal('sigma', sigma=5)
# Групповые отклонения
tau = pm.HalfNormal('tau', sigma=5)
group_offsets = pm.Normal('group_offsets', mu=0, sigma=tau, shape=n_groups)
# Модель для наблюдений
y_est = mu + group_offsets[np.array(group_idx)] y_like = pm.Normal('y_like', mu=y_est, sigma=sigma, observed=data)
trace = pm.sample(2000, tune=1000, target_accept=0.9, cores=1, progressbar=True)
pm.traceplot(trace, var_names=['mu', 'sigma', 'tau'])
plt.show()
Комментарий:
Иерархическая модель позволяет оценивать как общее влияние, так и специфичные для группы эффекты, что особенно полезно при наличии вложенной структуры данных.
Задача 18. Выживаемость и модель пропорциональных рисков Кокса
Суть задачи:
В задачах анализа выживаемости (например, времени до наступления события) используется модель Кокса для оценки влияния факторов на риск наступления события. Модель Кокса является полу-параметрической и не требует предположения о базовом распределении времени выживания.
Пример кода на Python с использованием библиотеки lifelines:
import numpy as np
import pandas as pd
from lifelines import CoxPHFitter
import matplotlib.pyplot as plt
# Генерация синтетических данных
np.random.seed(42)
n = 200
# Время выживания (синтетические данные)
time = np.random.exponential(10, n)
# Событие: 1 - событие произошло, 0 - цензурирование
event = np.random.binomial(1, 0.7, n)
# Дополнительные ковариаты
age = np.random.normal(50, 10, n)
treatment = np.random.binomial(1, 0.5, n)
df = pd.DataFrame({'time': time, 'event': event, 'age': age, 'treatment': treatment})
# Модель Кокса
cph = CoxPHFitter()
cph.fit(df, duration_col='time', event_col='event')
cph.print_summary()
# Пример прогноза функции выживания
cph.plot()
plt.title("Оценка функции риска по модели Кокса")
plt.show()
Комментарий:
Модель Кокса позволяет оценить влияние нескольких факторов на риск наступления события, не требуя явного задания базовой линии риска.
Задача 19. Анализ коинтеграции и построение VAR модели для многомерных временных рядов
Суть задачи:
При работе с несколькими временными рядами (например, экономическими показателями) важно учитывать, что ряды могут иметь общие долгосрочные тренды (коинтеграция). Для анализа взаимозависимостей используется модель VAR (Vector Autoregression).
Пример кода на Python с использованием statsmodels:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.vector_ar.vecm import coint_johansen
from statsmodels.tsa.api import VAR
# Генерация синтетических данных: два взаимосвязанных ряда с долгосрочной коинтеграцией
np.random.seed(42)
n = 300
time_index = pd.date_range(start='2000-01-01', periods=n, freq='M')
trend = np.linspace(0, 10, n)
y1 = trend + np.random.normal(0, 1, n)
y2 = 0.5 * trend + np.random.normal(0, 1, n) + 2 # связь с y1 через общий тренд
df = pd.DataFrame({'y1': y1, 'y2': y2}, index=time_index)
# Тест Йохансена на коинтеграцию
johansen_test = coint_johansen(df, det_order=0, k_ar_diff=1)
print("Собственные значения (eigenvalues):")
print(johansen_test.eig)
# Построение VAR модели
model = VAR(df)
results = model.fit(maxlags=5, ic='aic')
print(results.summary())
# Прогнозирование
lag_order = results.k_ar
forecast = results.forecast(df.values[-lag_order:], steps=10)
forecast_df = pd.DataFrame(forecast, index=pd.date_range(df.index[-1], periods=10, freq='M'), columns=['y1_forecast', 'y2_forecast'])
print(forecast_df)
Комментарий:
Анализ коинтеграции с тестом Йохансена позволяет проверить наличие долгосрочных связей между рядами, а VAR модель – оценить динамику и взаимодействие временных рядов.
Задача 20. Регрессия с помощью гауссовских процессов
Суть задачи:
Гауссовские процессы (GP) представляют собой мощный непараметрический байесовский метод для регрессии, позволяющий учитывать сложные зависимости в данных и оценивать неопределённость предсказаний.
Пример кода на Python с использованием scikit-learn:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel as C
# Генерация синтетических данных
np.random.seed(42)
X = np.atleast_2d(np.linspace(0, 10, 100)).T
y = np.sin(X).ravel() + np.random.normal(0, 0.2, X.shape[0])
# Определение ядра: константа + RBF
kernel = C(1.0, (1e-3, 1e3)) * RBF(1, (1e-2, 1e2))
gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10)
# Обучение модели
gp.fit(X, y)
X_pred = np.atleast_2d(np.linspace(0, 10, 200)).T
y_pred, sigma = gp.predict(X_pred, return_std=True)
# Визуализация результатов
plt.figure(figsize=(8, 5))
plt.plot(X, y, 'r.', markersize=10, label='Наблюдения')
plt.plot(X_pred, y_pred, 'b-', label='Предсказание GP')
plt.fill_between(X_pred.ravel(), y_pred - 1.96*sigma, y_pred + 1.96*sigma,
alpha=0.2, color='blue', label='95% доверительный интервал')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Гауссовские процессы для регрессии')
plt.legend()
plt.show()
Комментарий:
Гауссовские процессы позволяют не только предсказывать значения, но и оценивать степень неопределённости, что особенно важно при работе с ограниченными данными или в условиях высокой изменчивости.
Итоги
Эти задачи демонстрируют широкий спектр статистических знаний, востребованных у Data Scientist. Освоив подобные задачи, вы сможете успешно отвечать на вопросы на собеседованиях, показывая глубокое понимание как теории, так и практической реализации алгоритмов.
Надеюсь, статья окажется полезной для подготовки к собеседованиям и углубления ваших знаний в статистике!