AI-система фандрайзингу та роботи з донорами
Некомерційні організації втрачають 60-70% донорів після першої пожертвування через відсутність персоналізованої комунікації. AI-система передбачає схильність до повторного пожертвування, оптимізує момент та канал звернення, персоналізує суми запитів.
Модель схильності до пожертвування
import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier
from anthropic import Anthropic
import json
class DonorPropensityModel:
"""Предсказание вероятности следующего пожертвования"""
def __init__(self):
self.model = GradientBoostingClassifier(
n_estimators=200, learning_rate=0.05, max_depth=4, random_state=42
)
def build_rfm_features(self, donor_history: pd.DataFrame) -> pd.DataFrame:
"""RFM + дополнительные признаки для фандрайзинга"""
today = pd.Timestamp.now()
donor_stats = donor_history.groupby('donor_id').agg(
recency=('donation_date', lambda x: (today - x.max()).days),
frequency=('donation_id', 'count'),
monetary=('amount', 'sum'),
avg_donation=('amount', 'mean'),
last_amount=('amount', 'last'),
max_donation=('amount', 'max'),
first_donation_days=('donation_date', lambda x: (today - x.min()).days),
).reset_index()
# Тренд: растут ли суммы?
def donation_trend(group):
if len(group) < 3:
return 0
x = np.arange(len(group))
y = group['amount'].values
return np.polyfit(x, y, 1)[0] # Slope
trends = donor_history.groupby('donor_id').apply(donation_trend)
donor_stats['donation_trend'] = donor_stats['donor_id'].map(trends).fillna(0)
# Сезонность: давал ли в конце года (высокий сезон для НКО)?
year_end = donor_history[donor_history['donation_date'].dt.month.isin([11, 12])]
year_end_donors = set(year_end['donor_id'])
donor_stats['gives_year_end'] = donor_stats['donor_id'].isin(year_end_donors).astype(int)
return donor_stats
def predict_next_gift(self, donors: pd.DataFrame) -> pd.DataFrame:
"""Скоринг вероятности следующего пожертвования (90 дней)"""
features = self.build_rfm_features(donors)
feature_cols = ['recency', 'frequency', 'monetary', 'avg_donation',
'donation_trend', 'gives_year_end']
X = features[feature_cols].fillna(0)
probs = self.model.predict_proba(X)[:, 1]
features['propensity_score'] = probs
features['ask_amount'] = self._suggest_ask_amount(features)
features['donor_tier'] = pd.cut(
probs,
bins=[0, 0.2, 0.5, 0.75, 1.0],
labels=['lapsed', 'occasional', 'regular', 'loyal']
)
return features
def _suggest_ask_amount(self, donors: pd.DataFrame) -> pd.Series:
"""Предлагаемая сумма запроса: слегка выше средней"""
return (donors['avg_donation'] * 1.2).round(-1) # Округляем до десятков
class PersonalizedDonorOutreach:
"""Персонализированные обращения к донорам"""
def __init__(self):
self.llm = Anthropic()
def generate_appeal(self, donor: dict,
campaign: dict,
ask_amount: float) -> dict:
"""Персонализированное письмо для донора"""
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=350,
messages=[{
"role": "user",
"content": f"""Write a personalized fundraising appeal in Russian.
Donor profile:
- Name: {donor.get('first_name', 'Друг')}
- Giving history: {donor.get('frequency', 1)} gifts, average ${donor.get('avg_donation', 50):.0f}
- Last gift: {donor.get('last_amount', 50)} {donor.get('recency', 30)} days ago
- Main interests: {donor.get('cause_interests', ['general support'])}
Campaign: {campaign.get('name')}
Campaign story: {campaign.get('impact_story', '')[:200]}
Ask amount: ${ask_amount:.0f}
Write:
1. Personal opening (acknowledge their history)
2. Impact story (specific, emotional)
3. Clear ask with specific amount and its impact
4. Warm closing
Max 200 words. No generic phrases."""
}]
)
subject_response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=50,
messages=[{
"role": "user",
"content": f"Write a compelling email subject line in Russian for this fundraising appeal. Max 50 chars. Campaign: {campaign.get('name')}. Donor's interests: {donor.get('cause_interests', [])}."
}]
)
return {
'subject': subject_response.content[0].text.strip(),
'body': response.content[0].text,
'ask_amount': ask_amount,
'donor_id': donor.get('id')
}
def determine_best_channel(self, donor: dict) -> str:
"""Канал коммуникации на основе истории отклика"""
response_rates = donor.get('channel_response_rates', {})
if not response_rates:
return 'email'
return max(response_rates, key=response_rates.get)
Оптимізація кампаній
Ключові метрики AI-фандрайзингу: Donor Retention Rate (ціль: 45%+ для зрілих НКО), Cost Per Dollar Raised (ціль: $0.10-0.20), Average Gift Size. Персоналізовані поводження з правильною сумою запиту підвищують average gift на 15-25% - люди дають більше, коли їм пропонують конкретну суму з описом її впливу.







