AI Agents · Урок

Агенты для статистических сводок

Анализ распределений, корреляций и выбросов в отчётах, созданных агентом.

Урок 4 из 413 шагов

«Агенты для статистических сводок» — бесплатный урок AI Agents на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Agents, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Agents содержит 4 уроков всего.

Зачем нужны статистические сводки

Необработанные данные редко бывают полезны сами по себе. Агент анализа данных становится действительно ценным, когда может автоматически вычислять статистические сводки и преобразовывать числа в понятные выводы.

В этом уроке рассматриваются основные статистические операции: describe, корреляция, обнаружение выбросов, определение распределения и автоматическое создание выводов.

df.describe(): отправная точка

df.describe() за один вызов вычисляет количество наблюдений, mean, std, min, квартили и max для всех числовых столбцов. Это стандартный первый шаг любого исследовательского анализа данных.

import pandas as pd

df = pd.read_csv('sales_data.csv')

# Basic numeric summary
print(df.describe())

# Also describe categorical columns
print(df.describe(include='object'))

# Custom percentiles
print(df.describe(percentiles=[0.05, 0.25, 0.5, 0.75, 0.95]))

# Convert to clean dict for agent use
def get_numeric_summary(df):
    desc = df.describe().round(2)
    return {
        col: desc[col].to_dict()
        for col in desc.columns
    }

Матрица корреляций

Матрица корреляций показывает попарные линейные взаимосвязи между всеми числовыми столбцами. Значения находятся в диапазоне от -1 (сильная отрицательная связь) до +1 (сильная положительная связь). Значения, близкие к 0, указывают на отсутствие линейной связи.

import pandas as pd
import numpy as np

def compute_correlation_matrix(df):
    numeric = df.select_dtypes(include='number')
    corr = numeric.corr().round(3)
    return corr.to_dict()

def find_strong_correlations(df, threshold=0.7):
    numeric = df.select_dtypes(include='number')
    corr = numeric.corr()
    strong = []
    cols = corr.columns
    for i in range(len(cols)):
        for j in range(i + 1, len(cols)):  # upper triangle only
            val = corr.iloc[i, j]
            if abs(val) >= threshold:
                strong.append({
                    'col_a': cols[i],
                    'col_b': cols[j],
                    'correlation': round(val, 3),
                    'direction': 'positive' if val > 0 else 'negative'
                })
    return sorted(strong, key=lambda x: abs(x['correlation']), reverse=True)

Обнаружение выбросов: метод IQR

Метод межквартильного размаха (IQR) определяет выбросы как значения, расположенные более чем на 1,5 × IQR выше Q3 или ниже Q1. Он устойчив к экстремальным значениям: в отличие от z-оценки, метод хорошо работает даже при наличии выбросов в данных.

import pandas as pd

def detect_outliers_iqr(df, columns=None, multiplier=1.5):
    numeric = df.select_dtypes(include='number')
    if columns:
        numeric = numeric[columns]

    outlier_report = {}
    for col in numeric.columns:
        q1 = numeric[col].quantile(0.25)
        q3 = numeric[col].quantile(0.75)
        iqr = q3 - q1
        lower = q1 - multiplier * iqr
        upper = q3 + multiplier * iqr

        outliers = numeric[(numeric[col] < lower) | (numeric[col] > upper)][col]
        outlier_report[col] = {
            'q1': round(q1, 3),
            'q3': round(q3, 3),
            'iqr': round(iqr, 3),
            'lower_bound': round(lower, 3),
            'upper_bound': round(upper, 3),
            'outlier_count': len(outliers),
            'outlier_pct': round(len(outliers) / len(df) * 100, 1),
            'outlier_values': outliers.tolist()[:10]  # first 10
        }
    return outlier_report

Определение типа распределения

Определение типа распределения (нормальное, асимметричное, бимодальное или равномерное) помогает агенту выбирать подходящие статистические критерии и точно описывать данные.

Используйте асимметрию и kurtosis как быстрые эвристики перед проведением формальных проверок.

import pandas as pd
from scipy import stats

def identify_distribution(series):
    '''Classify distribution type using skewness, kurtosis, and normality test.'''
    clean = series.dropna()
    if len(clean) < 8:
        return {'type': 'insufficient_data'}

    skewness = clean.skew()
    kurtosis = clean.kurtosis()

    # Shapiro-Wilk normality test (reliable up to ~5000 samples)
    sample = clean.sample(min(500, len(clean)), random_state=42)
    _, p_value = stats.shapiro(sample)

    distribution = 'normal' if p_value > 0.05 else 'non-normal'

    if abs(skewness) < 0.5 and p_value > 0.05:
        dist_type = 'normal'
    elif skewness > 1.0:
        dist_type = 'right-skewed (long right tail)'
    elif skewness < -1.0:
        dist_type = 'left-skewed (long left tail)'
    elif abs(skewness) < 0.5 and kurtosis < -1:
        dist_type = 'uniform-like'
    else:
        dist_type = 'approximately normal'

    return {
        'type': dist_type,
        'skewness': round(skewness, 3),
        'kurtosis': round(kurtosis, 3),
        'normality_pvalue': round(p_value, 4),
        'is_normal': p_value > 0.05
    }

Проверки на нормальность

Существует несколько формальных критериев нормальности. Критерий Шапиро — Уилка лучше всего подходит для небольших выборок, а критерий Д’Агостино — Пирсона — для больших наборов данных. Порог p-значения обычно равен 0,05: отвергайте гипотезу о нормальности, если p < 0,05.

from scipy import stats
import numpy as np

def test_normality(series, alpha=0.05):
    clean = series.dropna().values
    n = len(clean)
    results = {}

    # Shapiro-Wilk (best for n < 5000)
    if n <= 5000:
        stat, p = stats.shapiro(clean)
        results['shapiro_wilk'] = {
            'statistic': round(stat, 4),
            'p_value': round(p, 4),
            'is_normal': p > alpha
        }

    # D'Agostino-Pearson (n >= 20)
    if n >= 20:
        stat, p = stats.normaltest(clean)
        results['dagostino_pearson'] = {
            'statistic': round(stat, 4),
            'p_value': round(p, 4),
            'is_normal': p > alpha
        }

    # Kolmogorov-Smirnov
    mean, std = np.mean(clean), np.std(clean)
    stat, p = stats.kstest(clean, 'norm', args=(mean, std))
    results['kolmogorov_smirnov'] = {
        'statistic': round(stat, 4),
        'p_value': round(p, 4),
        'is_normal': p > alpha
    }

    return results

Полный статистический профиль

Объедините весь статистический анализ в одну функцию full_profile(), которая возвращает подробную статистическую сводку для каждого числового столбца таблицы данных.

def full_statistical_profile(df):
    numeric = df.select_dtypes(include='number')
    profiles = {}

    for col in numeric.columns:
        series = numeric[col].dropna()
        profile = {
            'count': len(series),
            'null_count': df[col].isnull().sum(),
            'mean': round(series.mean(), 4),
            'median': round(series.median(), 4),
            'std': round(series.std(), 4),
            'min': round(series.min(), 4),
            'max': round(series.max(), 4),
            'range': round(series.max() - series.min(), 4),
            'q1': round(series.quantile(0.25), 4),
            'q3': round(series.quantile(0.75), 4)
        }
        profile['distribution'] = identify_distribution(series)
        outliers = detect_outliers_iqr(df, columns=[col])
        profile['outliers'] = outliers.get(col, {})
        profiles[col] = profile

    return {
        'profiles': profiles,
        'correlations': find_strong_correlations(df),
        'shape': {'rows': len(df), 'columns': len(df.columns)}
    }

Автоматическое создание выводов

Передайте статистический профиль в LLM и попросите создать понятные выводы. Модель выявляет закономерности, отмечает аномалии и выделяет результаты, важные для бизнес-пользователя.

import json

INSIGHT_PROMPT = '''You are a data analyst. Generate 3-5 key insights from this statistical summary.

Dataset: {dataset_name}
Statistical profile:
{profile_json}

For each insight:
- Be specific (use actual numbers)
- Focus on business relevance
- Flag any data quality concerns (high null counts, extreme outliers)
- Note unexpected patterns

Format as bullet points.'''

def generate_insights(df, dataset_name='dataset'):
    profile = full_statistical_profile(df)
    profile_text = json.dumps(profile, indent=2, default=str)[:3000]
    return llm_call(INSIGHT_PROMPT.format(
        dataset_name=dataset_name,
        profile_json=profile_text
    ))

# Example output:
# - Revenue column has 3.2% outliers; max value ($48,500) is 12x the median ($3,900)
# - Customer age follows a right-skewed distribution (skewness: 1.4) with most users under 35
# - Strong positive correlation (r=0.87) between session_count and lifetime_value

Определение тенденции во временном ряду

Для данных временного ряда определяйте общую тенденцию (рост, снижение или отсутствие изменений) с помощью линейной регрессии. Это позволяет агентам сообщать: «Выручка увеличивается на 2 400 долларов в месяц.»

import numpy as np
from scipy import stats

def detect_trend(values):
    if len(values) < 3:
        return {'trend': 'insufficient_data'}

    x = np.arange(len(values))
    y = np.array(values, dtype=float)
    slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)

    if p_value > 0.05:
        trend = 'flat (no significant trend)'
    elif slope > 0:
        trend = 'increasing'
    else:
        trend = 'decreasing'

    return {
        'trend': trend,
        'slope_per_period': round(slope, 4),
        'r_squared': round(r_value ** 2, 4),
        'p_value': round(p_value, 4),
        'significant': p_value < 0.05
    }

# Example: monthly revenue trend
monthly_revenue = [10000, 11200, 10800, 12500, 13100, 14200, 15000]
print(detect_trend(monthly_revenue))
# {'trend': 'increasing', 'slope_per_period': 834.2, 'r_squared': 0.95, ...}

Сравнительная статистика

Часто наиболее полезный вывод получается при сравнении групп: «Средняя стоимость заказа в сегменте A на 40% выше, чем в сегменте B.» Для сравнения групп используйте t-критерии или критерий Манна — Уитни.

from scipy import stats
import pandas as pd

def compare_groups(df, group_column, value_column):
    groups = df.groupby(group_column)[value_column].apply(list)
    group_names = list(groups.index)

    comparison = []
    for i, g1 in enumerate(group_names):
        for j, g2 in enumerate(group_names):
            if j <= i:
                continue
            a, b = groups[g1], groups[g2]
            mean_a = pd.Series(a).mean()
            mean_b = pd.Series(b).mean()

            # Mann-Whitney U (non-parametric, no normality assumption)
            stat, p = stats.mannwhitneyu(a, b, alternative='two-sided')
            pct_diff = (mean_a - mean_b) / mean_b * 100 if mean_b != 0 else 0

            comparison.append({
                'group_a': g1, 'group_b': g2,
                'mean_a': round(mean_a, 2),
                'mean_b': round(mean_b, 2),
                'pct_difference': round(pct_diff, 1),
                'p_value': round(p, 4),
                'significant': p < 0.05
            })
    return comparison

Анализ пропущенных значений

Перед вычислением любых статистических показателей проанализируйте пропущенные значения. Высокая доля пустых значений в столбце делает вычисленные по нему показатели недостоверными. Сообщайте количество пустых значений, их процент и закономерности (пропуски случайны или систематичны?).

import pandas as pd
import numpy as np

def analyze_missing_values(df):
    total_rows = len(df)
    missing_report = {}

    for col in df.columns:
        null_count = df[col].isnull().sum()
        if null_count == 0:
            continue
        null_pct = null_count / total_rows * 100

        # Check if nulls correlate with another column (systematic pattern)
        pattern = 'random'
        if null_pct > 5:
            for other_col in df.select_dtypes(include='object').columns:
                if other_col == col:
                    continue
                null_rates = df.groupby(other_col)[col].apply(
                    lambda x: x.isnull().mean()
                )
                if null_rates.max() - null_rates.min() > 0.3:  # 30% difference
                    pattern = f'correlated_with_{other_col}'
                    break

        missing_report[col] = {
            'null_count': int(null_count),
            'null_pct': round(null_pct, 1),
            'severity': 'high' if null_pct > 20 else 'medium' if null_pct > 5 else 'low',
            'pattern': pattern
        }

    return missing_report

Проверка знаний

Почему метод IQR предпочтительнее z-оценки для обнаружения выбросов в приложениях с агентами?

Повторение: агенты статистических сводок

Агенты статистических сводок объединяют: df.describe() для базовых статистических показателей, матрицы корреляций для выявления взаимосвязей, обнаружение выбросов методом IQR (устойчивое к экстремальным значениям), определение распределения с помощью асимметрии и проверок на нормальность и определение тенденций с помощью линейной регрессии.

Передавайте статистический профиль в LLM для автоматического создания выводов, преобразующих числа в понятные бизнес-результаты. Сравнительная статистика (сравнение групп с проверкой статистической значимости) помогает выявлять наиболее практически применимые выводы.

Можно начать бесплатно

Изучай AI Agents с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
60
Уроки
239

Часто задаваемые вопросы

Урок «Агенты для статистических сводок» бесплатный?

Да — полный текст урока «Агенты для статистических сводок» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Agents, подпишись на CoddyKit PRO. Курс AI Agents содержит 4 уроков всего.

Чему я научусь в уроке «Агенты для статистических сводок»?

Анализ распределений, корреляций и выбросов в отчётах, созданных агентом. Ты практикуешь AI Agents с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Agents?

Предыдущий опыт не требуется. AI Agents на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Агенты для статистических сводок»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Agents?

Да. Каждый урок AI Agents включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Шаблон интерпретатора кода для анализа данных
  2. Инструменты агентов на основе Pandas
  3. Автоматическая генерация диаграмм и визуализаций
  4. Агенты для статистических сводок
← Назад к AI Agents