AI-рекомендации средств по уходу за кожей
Подбор средств по уходу — задача с высокой персонализацией: один и тот же продукт даёт разные результаты для разных типов кожи, климата, возраста и состава существующего ухода. Рекомендательная система должна учитывать не только предпочтения, но и совместимость активных компонентов.
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class SkincareRecommender:
"""Рекомендации средств на основе профиля кожи и состава"""
def build_skin_profile(self, user_data: dict) -> dict:
"""Профиль пользователя для таргетинга рекомендаций"""
return {
'skin_type': user_data.get('skin_type', 'normal'),
'concerns': user_data.get('concerns', []),
'sensitivities': user_data.get('sensitivities', []),
'current_routine': user_data.get('current_products', []),
'climate': user_data.get('climate', 'temperate'),
'age_group': user_data.get('age_group', '25-34'),
}
def check_ingredient_compatibility(self, product_a: dict,
product_b: dict) -> dict:
"""
Проверка совместимости активных компонентов.
Некоторые пары несовместимы: retinol + vitamin C, AHA + retinol.
"""
incompatible_pairs = [
({'retinol', 'retinoids'}, {'vitamin_c', 'ascorbic_acid'}),
({'aha', 'glycolic_acid', 'lactic_acid'}, {'retinol', 'retinoids'}),
({'benzoyl_peroxide'}, {'retinol', 'vitamin_c'}),
({'niacinamide'}, {'vitamin_c'}), # Спорный момент — лучше разделить
]
ingredients_a = set(product_a.get('key_ingredients', []))
ingredients_b = set(product_b.get('key_ingredients', []))
conflicts = []
for group_a, group_b in incompatible_pairs:
if ingredients_a & group_a and ingredients_b & group_b:
conflicts.append({
'ingredient_a': list(ingredients_a & group_a)[0],
'ingredient_b': list(ingredients_b & group_b)[0],
'recommendation': 'Use at different times of day (AM/PM)'
})
elif ingredients_b & group_a and ingredients_a & group_b:
conflicts.append({
'ingredient_a': list(ingredients_b & group_a)[0],
'ingredient_b': list(ingredients_a & group_b)[0],
'recommendation': 'Use at different times of day'
})
return {
'compatible': len(conflicts) == 0,
'conflicts': conflicts
}
def recommend_for_concern(self, concern: str,
products_catalog: pd.DataFrame,
skin_type: str,
top_k: int = 5) -> list[dict]:
"""
Рекомендации под конкретную проблему кожи.
concern: 'acne' | 'aging' | 'hyperpigmentation' | 'dryness' | 'sensitivity'
"""
# Фильтрация по типу кожи
suitable = products_catalog[
products_catalog['suitable_skin_types'].apply(
lambda types: skin_type in types or 'all' in types
)
].copy()
# Релевантность для проблемы
concern_ingredients = {
'acne': ['salicylic_acid', 'benzoyl_peroxide', 'niacinamide', 'zinc'],
'aging': ['retinol', 'peptides', 'hyaluronic_acid', 'vitamin_c'],
'hyperpigmentation': ['vitamin_c', 'niacinamide', 'kojic_acid', 'alpha_arbutin'],
'dryness': ['hyaluronic_acid', 'ceramides', 'glycerin', 'squalane'],
'sensitivity': ['centella_asiatica', 'aloe_vera', 'panthenol', 'allantoin'],
}.get(concern, [])
def concern_score(product_ingredients):
if not isinstance(product_ingredients, list):
return 0
matches = sum(1 for ing in concern_ingredients if ing in product_ingredients)
return matches / max(len(concern_ingredients), 1)
suitable['concern_relevance'] = suitable['key_ingredients'].apply(concern_score)
# Комбинированный скор: релевантность + рейтинг
suitable['final_score'] = (
suitable['concern_relevance'] * 0.6 +
suitable['avg_rating'].fillna(3.5) / 5.0 * 0.3 +
suitable['review_count'].fillna(0).clip(0, 500) / 500 * 0.1
)
top = suitable.nlargest(top_k, 'final_score')
return [
{
'product_id': row['product_id'],
'name': row['name'],
'concern_relevance': round(row['concern_relevance'], 2),
'rating': row.get('avg_rating', 0),
'key_actives': row.get('key_ingredients', [])[:3],
}
for _, row in top.iterrows()
]
Рекомендательная система для ухода за кожей с проверкой совместимости компонентов снижает количество возвратов на 25-35% и повышает конверсию категорийных страниц на 18-30%. Ключевое отличие от generic recommendation: учёт биохимии активных ингредиентов, а не только collaborative filtering по покупкам.







