Создание искусственных наборов данных в Pandas для тестирования и анализа

Раздел: Python -> Pandas

Основные подходы к генерации данных в Pandas

Как быстро создать произвольный DataFrame с числовыми столбцами для отладки алгоритмов?

Наиболее эффективный способ для числовых данных - использование numpy.random в сочетании с конструктором DataFrame. Это позволяет контролировать распределение, размер и тип данных. Пример с нормальным распределением, целыми числами и датами:


import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'id': np.arange(1, 101),
    'значение': np.random.normal(loc=50, scale=10, size=100),
    'категория': np.random.choice(['A', 'B', 'C'], size=100),
    'дата': pd.date_range('2023-01-01', periods=100, freq='D')
})
print(df.head())
    

обработка больших данных python (обработка больших данных в python)

Пояснение: seed фиксирует случайность для воспроизводимости. np.random.normal генерирует 100 чисел со средним 50 и стандартным отклонением 10. pd.date_range создаёт ежедневные даты.

Типичная ошибка: забыть указать size в numpy функциях - тогда возвращается одно значение, а не массив. Или несоответствие длины при создании столбцов - все массивы должны быть одинаковой длины.

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

Как сгенерировать столбец с повторяющимися категориями и заданными вероятностями?

Использование np.random.choice с параметром p для вероятностей и replace=True (по умолчанию).


categories = ['низкий', 'средний', 'высокий']
probabilities = [0.2, 0.5, 0.3]
df['уровень'] = np.random.choice(categories, size=1000, p=probabilities)
print(df['уровень'].value_counts(normalize=True))
    

очистка данных python (очистка данных в python)

Проблема: если вероятности не суммируются в 1, возникает ошибка ValueError. Также при малых размерах выборки эмпирическое распределение может отклоняться от заданного.

Как создать временной ряд с пропусками или нерегулярными интервалами?

Генерация случайных дат с помощью pd.to_datetime и случайного выбора из диапазона. Затем можно добавить пропуски через sample.


import random
start = pd.Timestamp('2023-01-01')
end = pd.Timestamp('2023-12-31')
dates = [start + pd.Timedelta(days=random.randint(0, 364)) for _ in range(500)]
df_dates = pd.DataFrame({'дата': sorted(dates), 'значение': np.random.randn(500)})
# Вносим пропуски (10%)
missing_idx = df_dates.sample(frac=0.1).index
df_dates.loc[missing_idx, 'значение'] = np.nan
print(df_dates.isnull().sum())
    

Python подготовка данных (подготовка данных в python)

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

Ошибка: при большом количестве дат генерация через списковое включение может быть медленной. Альтернатива - np.random.choice из всех дат диапазона (если они дискретны).

Как создать данные с известной корреляцией между признаками?

Использование многомерного нормального распределения из numpy.random.multivariate_normal. Задаётся вектор средних и ковариационная матрица.


mean = [0, 10]
cov = [[1, 0.8], [0.8, 2]]  # положительная корреляция 0.8
data = np.random.multivariate_normal(mean, cov, size=1000)
df_corr = pd.DataFrame(data, columns=['x', 'y'])
print(df_corr.corr())
    

работа с dataframe python (работа с dataframe в python)

Этот способ незаменим при тестировании регрессионных моделей или методов снижения размерности.

Ковариационная матрица должна быть положительно полуопределённой. Ошибка возникает, если корреляция выходит за пределы [-1,1] или матрица несимметрична.

Как создать правдоподобные персональные данные (имена, адреса, номера)?

Библиотека Faker предоставляет реалистичные данные для разных локалей. Установка: pip install faker.


from faker import Faker
fake = Faker('ru_RU')  # русская локаль

def generate_person():
    return {
        'имя': fake.name(),
        'город': fake.city(),
        'email': fake.email(),
        'телефон': fake.phone_number()
    }

df_fake = pd.DataFrame([generate_person() for _ in range(50)])
print(df_fake.head())
    

Faker позволяет генерировать текст, адреса, компании, даты рождения и многое другое. Это лучший выбор для демонстрации работы с нечисловыми данными.

Проблема: повторяющиеся данные при малых выборках (особенно имена). Решение - увеличить размер или использовать unique() на финальном наборе. Также Faker может быть медленным для миллионов записей - тогда стоит комбинировать с numpy.

- генерация данных python (генерация данных в python)
- Python код символа (код символа в python)
- код из файла python (код из файла python)

Расширенные примеры генерации данных

1. Большой DataFrame с различными типами и пропусками

Генерация 100 000 строк с числовыми, категориальными, логическими и временными столбцами, включая случайные пропуски.

Пример

import pandas as pd
import numpy as np
from faker import Faker

np.random.seed(0)
n = 100_000

# Числовые столбцы
age = np.random.randint(18, 80, size=n)
salary = np.random.exponential(scale=50000, size=n).astype(int)
score = np.random.uniform(0, 100, size=n).round(1)

# Категориальные
cities = ['Москва', 'Санкт-Петербург', 'Новосибирск', 'Екатеринбург']
city = np.random.choice(cities, size=n, p=[0.4, 0.3, 0.2, 0.1])

# Логический
is_active = np.random.choice([True, False], size=n, p=[0.8, 0.2])

# Даты (случайные в пределах года)
start_date = pd.Timestamp('2023-01-01')
end_date = pd.Timestamp('2023-12-31')
dates = pd.to_datetime(np.random.randint(start_date.value, end_date.value, size=n))

df_big = pd.DataFrame({
    'age': age,
    'salary': salary,
    'score': score,
    'city': city,
    'is_active': is_active,
    'date': dates
})

# Вставка пропусков (случайным образом, 5% в каждом столбце)
for col in df_big.columns:
    mask = np.random.random(n) < 0.05
    df_big.loc[mask, col] = np.nan

print(df_big.head())
print(df_big.info())
   age   salary  score          city  is_active       date
0   46  20497.0   55.8  Санкт-Петербург       True 2023-11-17
1   39  20030.0   49.3       Новосибирск       True 2023-06-02
2   22  65012.0   68.2          Москва      False 2023-03-25
3   70  27912.0    NaN       Екатеринбург       True 2023-09-01
4   50  40399.0   22.1          Москва       True 2023-07-11

dtypes: age float64, salary float64, score float64, city object, is_active object, date datetime64[ns]

2. Генерация данных с внешним ключом (клиенты и заказы)

Создание двух связанных таблиц: клиенты (id, имя, город) и заказы (id заказа, id клиента, сумма, дата).

Пример

from faker import Faker
import pandas as pd
import numpy as np

fake = Faker('ru_RU')
n_customers = 2000
n_orders = 10000

# Клиенты
df_customers = pd.DataFrame({
    'customer_id': np.arange(1, n_customers+1),
    'name': [fake.name() for _ in range(n_customers)],
    'city': [fake.city() for _ in range(n_customers)]
})

# Заказы (некоторые клиенты могут не иметь заказов, некоторые - много)
customer_ids = np.random.choice(df_customers['customer_id'], size=n_orders, replace=True)
dates = pd.date_range('2023-01-01', '2024-01-01', periods=n_orders) + pd.to_timedelta(np.random.randint(0, 24*60*60, size=n_orders), unit='s')

df_orders = pd.DataFrame({
    'order_id': np.arange(1, n_orders+1),
    'customer_id': customer_ids,
    'amount': np.random.uniform(100, 5000, size=n_orders).round(2),
    'order_date': dates
})

print(df_customers.head(3))
print(df_orders.head(3))
print(f"Клиентов: {df_customers['customer_id'].nunique()}, Заказов: {len(df_orders)}")
   customer_id                name             city
0            1        Алексей Петров          Москва
1            2        Мария Иванова  Санкт-Петербург
2            3   Дмитрий Смирнов        Новосибирск

   order_id  customer_id  amount          order_date
0         1          279  4291.23 2023-01-01 00:00:00
1         2          897  1210.67 2023-01-01 01:15:24
2         3         1723  3879.45 2023-01-01 02:30:48

Клиентов: 2000, Заказов: 10000

3. Данные с дисбалансом классов (для классификации)

Создание двух признаков, где один класс составляет 90% выборки, другой - 10%.

Пример

n = 5000
# Большинство (0)
X_major = np.random.multivariate_normal([0, 0], [[1,0],[0,1]], size=int(n*0.9))
# Меньшинство (1)
X_minor = np.random.multivariate_normal([3, 3], [[1,0.5],[0.5,1]], size=int(n*0.1))

X = np.vstack([X_major, X_minor])
y = np.array([0]*len(X_major) + [1]*len(X_minor))

# Перемешивание
indices = np.random.permutation(n)
X, y = X[indices], y[indices]

df_imb = pd.DataFrame(X, columns=['f1', 'f2'])
df_imb['target'] = y
print(df_imb['target'].value_counts(normalize=True))
0    0.9
1    0.1
Name: target, dtype: float64

4. Использование lambda и assign для генерации вычисляемых полей

На основе сгенерированных столбцов добавить новые с помощью assign и лямбда-функций.

Пример

df = pd.DataFrame({
    'hours': np.random.randint(20, 60, size=100),
    'rate': np.random.uniform(10, 50, size=100).round(2)
})
df = df.assign(
    gross=lambda x: x['hours'] * x['rate'],
    tax=lambda x: np.where(x['gross'] < 2000, x['gross']*0.1, x['gross']*0.2),
    net=lambda x: x['gross'] - x['tax']
)
print(df.head())
   hours   rate   gross    tax     net
0     51  20.15  1027.65  102.77   924.88
1     31  36.28  1124.68  112.47  1012.21
2     47  16.74   786.78   78.68   708.10
3     28  45.99  1287.72  128.77  1158.95
4     55  21.31  1172.05  117.21  1054.84

Генерация данных в Python - comments

En
генерация данных python (python)