Создание искусственных наборов данных в 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.
Расширенные примеры генерации данных
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