視聴率・選挙・アンケート分析AI|機械学習で世論とトレンドを予測

 

概要

視聴率、選挙結果、アンケート調査は社会の動向を把握する重要な指標です。機械学習を活用することで、従来の統計分析を超えた精密な予測と洞察が可能になります。本記事では、これらの分析領域における機械学習手法の実装と活用方法を詳しく解説します。

各分析領域の特徴と課題

視聴率分析の重要性

テレビ・配信コンテンツの視聴率は、広告価値や番組制作戦略を決定する基幹指標です:

  • リアルタイム性: 放送中の視聴動向の即座な把握
  • 多変量影響: 時間帯、競合番組、社会情勢等の複合的要因
  • 個人化: 視聴者属性による嗜好の違い
  • 季節性: 年間を通じた視聴パターンの変動

選挙分析の特殊性

選挙予測は高度な統計的手法と社会科学的知見が必要な領域です:

  • サンプリング: 代表性のある調査設計
  • バイアス補正: 回答者の偏りの調整
  • 時系列変化: 選挙戦期間中の支持率変動
  • 地域性: 地域別の政治的特性

アンケート分析の応用範囲

顧客満足度から商品開発まで、幅広い意思決定を支援:

  • 感情分析: 自由記述回答からの感情抽出
  • 潜在因子: 回答パターンから隠れた要因の発見
  • 予測モデリング: 将来の行動や意向の予測

視聴率予測システムの実装

データ準備と特徴量エンジニアリング

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, TimeSeriesSplit
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.metrics import mean_absolute_error, r2_score
import matplotlib.pyplot as plt

# 視聴率データの生成
def create_viewership_data():
    np.random.seed(42)
    
    # 2年間の日次データ
    dates = pd.date_range('2022-01-01', '2023-12-31', freq='D')
    n_days = len(dates)
    
    # 番組カテゴリ
    genres = ['ドラマ', 'バラエティ', 'ニュース', 'アニメ', 'スポーツ', 'ドキュメンタリー']
    time_slots = ['朝', '昼', '夕方', '夜', '深夜']
    
    data = []
    
    for i, date in enumerate(dates):
        # 曜日効果
        weekday = date.weekday()
        is_weekend = weekday >= 5
        
        # 季節効果
        month = date.month
        season_effect = 1.0
        if month in [12, 1, 2]:  # 冬
            season_effect = 1.2
        elif month in [7, 8]:    # 夏
            season_effect = 0.9
        
        # 各時間帯の番組データ
        for time_slot in time_slots:
            for genre in genres:
                # ベース視聴率
                base_rating = {
                    'ドラマ': 12.0, 'バラエティ': 10.0, 'ニュース': 8.0,
                    'アニメ': 6.0, 'スポーツ': 15.0, 'ドキュメンタリー': 5.0
                }[genre]
                
                # 時間帯効果
                time_effect = {
                    '朝': 0.6, '昼': 0.8, '夕方': 0.9, '夜': 1.3, '深夜': 0.4
                }[time_slot]
                
                # 曜日効果
                weekday_effect = 1.2 if is_weekend else 1.0
                if genre == 'ニュース':
                    weekday_effect = 0.8 if is_weekend else 1.0
                
                # 競合番組数(ランダム)
                competing_shows = np.random.poisson(3) + 1
                competition_effect = 1.0 / (1 + 0.1 * competing_shows)
                
                # 特別イベント(ランダム)
                special_event = np.random.random() < 0.05
                event_effect = 2.0 if special_event else 1.0
                
                # 最終視聴率計算
                final_rating = (base_rating * time_effect * weekday_effect * 
                              season_effect * competition_effect * event_effect)
                
                # ノイズ追加
                final_rating += np.random.normal(0, 1.5)
                final_rating = max(0.1, final_rating)  # 最低0.1%
                
                data.append({
                    'date': date,
                    'genre': genre,
                    'time_slot': time_slot,
                    'weekday': weekday,
                    'is_weekend': is_weekend,
                    'month': month,
                    'competing_shows': competing_shows,
                    'special_event': special_event,
                    'viewership_rating': final_rating
                })
    
    return pd.DataFrame(data)

# 特徴量エンジニアリング
def create_viewership_features(df):
    df = df.copy()
    
    # 日付特徴量
    df['day_of_year'] = df['date'].dt.dayofyear
    df['quarter'] = df['date'].dt.quarter
    
    # 周期的特徴量
    df['day_sin'] = np.sin(2 * np.pi * df['weekday'] / 7)
    df['day_cos'] = np.cos(2 * np.pi * df['weekday'] / 7)
    df['month_sin'] = np.sin(2 * np.pi * df['month'] / 12)
    df['month_cos'] = np.cos(2 * np.pi * df['month'] / 12)
    
    # カテゴリカル変数のエンコーディング
    le_genre = LabelEncoder()
    le_time = LabelEncoder()
    
    df['genre_encoded'] = le_genre.fit_transform(df['genre'])
    df['time_slot_encoded'] = le_time.fit_transform(df['time_slot'])
    
    # ラグ特徴量(前日、前週の視聴率)
    df = df.sort_values(['genre', 'time_slot', 'date'])
    df['rating_lag_1'] = df.groupby(['genre', 'time_slot'])['viewership_rating'].shift(1)
    df['rating_lag_7'] = df.groupby(['genre', 'time_slot'])['viewership_rating'].shift(7)
    
    # 移動平均
    df['rating_ma_7'] = df.groupby(['genre', 'time_slot'])['viewership_rating'].rolling(7).mean().values
    df['rating_ma_30'] = df.groupby(['genre', 'time_slot'])['viewership_rating'].rolling(30).mean().values
    
    return df.dropna(), le_genre, le_time

# データ生成と前処理
df = create_viewership_data()
df, le_genre, le_time = create_viewership_features(df)

print(f"データサイズ: {len(df):,}行")
print(f"期間: {df['date'].min()} - {df['date'].max()}")

視聴率予測モデルの構築

# 特徴量の選択
feature_cols = ['genre_encoded', 'time_slot_encoded', 'weekday', 'is_weekend',
                'month', 'quarter', 'competing_shows', 'special_event',
                'day_sin', 'day_cos', 'month_sin', 'month_cos',
                'rating_lag_1', 'rating_lag_7', 'rating_ma_7', 'rating_ma_30']

X = df[feature_cols]
y = df['viewership_rating']

# 時系列分割による訓練・テスト
split_date = pd.Timestamp('2023-07-01')
train_mask = df['date'] < split_date
test_mask = df['date'] >= split_date

X_train, X_test = X[train_mask], X[test_mask]
y_train, y_test = y[train_mask], y[test_mask]

# 複数モデルの訓練と評価
models = {
    'RandomForest': RandomForestRegressor(n_estimators=100, random_state=42),
    'GradientBoosting': GradientBoostingRegressor(n_estimators=100, random_state=42)
}

model_results = {}

for name, model in models.items():
    # モデル訓練
    model.fit(X_train, y_train)
    
    # 予測
    y_pred = model.predict(X_test)
    
    # 評価
    mae = mean_absolute_error(y_test, y_pred)
    r2 = r2_score(y_test, y_pred)
    
    model_results[name] = {
        'model': model,
        'mae': mae,
        'r2': r2,
        'predictions': y_pred
    }
    
    print(f"{name}:")
    print(f"  MAE: {mae:.3f}")
    print(f"  R²: {r2:.3f}")

# 最良モデルの選択
best_model_name = min(model_results.keys(), key=lambda x: model_results[x]['mae'])
best_model = model_results[best_model_name]['model']

print(f"\n最良モデル: {best_model_name}")

# 特徴量重要度の分析
feature_importance = pd.DataFrame({
    'feature': feature_cols,
    'importance': best_model.feature_importances_
}).sort_values('importance', ascending=False)

print("\n特徴量重要度:")
print(feature_importance.head(10))

リアルタイム視聴率予測システム

class ViewershipPredictor:
    def __init__(self, model, label_encoders, feature_cols):
        self.model = model
        self.le_genre, self.le_time = label_encoders
        self.feature_cols = feature_cols
        self.historical_data = []
    
    def predict_rating(self, program_info):
        """
        番組情報から視聴率を予測
        """
        # 入力データの前処理
        processed_data = self.preprocess_input(program_info)
        
        # 予測実行
        prediction = self.model.predict([processed_data])[0]
        
        # 信頼区間の推定(簡略版)
        confidence_interval = self.estimate_confidence_interval(processed_data)
        
        return {
            'predicted_rating': prediction,
            'confidence_lower': prediction - confidence_interval,
            'confidence_upper': prediction + confidence_interval
        }
    
    def preprocess_input(self, program_info):
        """
        入力データの前処理
        """
        # 基本特徴量
        genre_encoded = self.le_genre.transform([program_info['genre']])[0]
        time_slot_encoded = self.le_time.transform([program_info['time_slot']])[0]
        
        weekday = program_info['date'].weekday()
        is_weekend = 1 if weekday >= 5 else 0
        month = program_info['date'].month
        quarter = (month - 1) // 3 + 1
        
        # 周期的特徴量
        day_sin = np.sin(2 * np.pi * weekday / 7)
        day_cos = np.cos(2 * np.pi * weekday / 7)
        month_sin = np.sin(2 * np.pi * month / 12)
        month_cos = np.cos(2 * np.pi * month / 12)
        
        # ラグ特徴量(履歴データから取得)
        rating_lag_1 = self.get_lag_feature(program_info, 1)
        rating_lag_7 = self.get_lag_feature(program_info, 7)
        rating_ma_7 = self.get_moving_average(program_info, 7)
        rating_ma_30 = self.get_moving_average(program_info, 30)
        
        processed = [
            genre_encoded, time_slot_encoded, weekday, is_weekend,
            month, quarter, program_info['competing_shows'], 
            program_info['special_event'], day_sin, day_cos, 
            month_sin, month_cos, rating_lag_1, rating_lag_7,
            rating_ma_7, rating_ma_30
        ]
        
        return processed
    
    def get_lag_feature(self, program_info, lag_days):
        """
        ラグ特徴量の取得(履歴データから)
        """
        # 簡略化:固定値を返す(実際は履歴DBから取得)
        return 10.0  # デフォルト値
    
    def get_moving_average(self, program_info, window):
        """
        移動平均の計算
        """
        # 簡略化:固定値を返す
        return 9.5  # デフォルト値
    
    def estimate_confidence_interval(self, processed_data):
        """
        予測の信頼区間を推定
        """
        # 簡略化:モデルの過去のエラーから推定
        return 2.0  # ±2%の信頼区間

# 視聴率予測システムの使用例
predictor = ViewershipPredictor(best_model, (le_genre, le_time), feature_cols)

# サンプル番組情報
sample_program = {
    'date': pd.Timestamp('2023-12-01 20:00:00'),
    'genre': 'ドラマ',
    'time_slot': '夜',
    'competing_shows': 4,
    'special_event': 0
}

prediction_result = predictor.predict_rating(sample_program)
print(f"予測視聴率: {prediction_result['predicted_rating']:.2f}%")
print(f"信頼区間: {prediction_result['confidence_lower']:.2f}% - {prediction_result['confidence_upper']:.2f}%")

選挙予測システムの実装

世論調査データの分析

# 選挙予測用データの生成
def create_election_data():
    np.random.seed(42)
    
    # 調査期間(選挙3ヶ月前から当日まで)
    dates = pd.date_range('2023-09-01', '2023-12-01', freq='D')
    
    # 候補者
    candidates = ['候補者A', '候補者B', '候補者C', '候補者D']
    
    # 地域
    regions = ['北海道', '東北', '関東', '中部', '関西', '中国', '四国', '九州']
    
    # 年齢層
    age_groups = ['18-29', '30-39', '40-49', '50-59', '60-69', '70+']
    
    data = []
    
    # 各候補者の基礎支持率
    base_support = {'候補者A': 0.35, '候補者B': 0.30, '候補者C': 0.25, '候補者D': 0.10}
    
    for date in dates:
        days_to_election = (pd.Timestamp('2023-12-01') - date).days
        
        for region in regions:
            for age_group in age_groups:
                for candidate in candidates:
                    # 基礎支持率
                    support = base_support[candidate]
                    
                    # 時期効果(選挙が近づくと変動が大きくなる)
                    time_factor = 1.0 - (days_to_election / 90) * 0.3
                    
                    # 地域効果
                    if candidate == '候補者A' and region in ['関東', '関西']:
                        region_boost = 0.05
                    elif candidate == '候補者B' and region in ['東北', '中国']:
                        region_boost = 0.04
                    else:
                        region_boost = 0.0
                    
                    # 年齢効果
                    if candidate == '候補者A' and age_group in ['18-29', '30-39']:
                        age_boost = 0.03
                    elif candidate == '候補者B' and age_group in ['50-59', '60-69']:
                        age_boost = 0.04
                    else:
                        age_boost = 0.0
                    
                    # 最終支持率
                    final_support = support + region_boost + age_boost
                    final_support *= time_factor
                    
                    # ノイズ追加
                    final_support += np.random.normal(0, 0.03)
                    final_support = max(0.01, min(0.8, final_support))
                    
                    # サンプルサイズ
                    sample_size = np.random.randint(800, 1200)
                    
                    data.append({
                        'date': date,
                        'region': region,
                        'age_group': age_group,
                        'candidate': candidate,
                        'support_rate': final_support,
                        'sample_size': sample_size,
                        'days_to_election': days_to_election
                    })
    
    return pd.DataFrame(data)

# 選挙予測モデル
class ElectionPredictor:
    def __init__(self):
        self.models = {}
        self.feature_encoders = {}
        self.is_fitted = False
    
    def prepare_features(self, df):
        """
        特徴量エンジニアリング
        """
        df = df.copy()
        
        # カテゴリカル変数のエンコーディング
        for col in ['region', 'age_group', 'candidate']:
            if col not in self.feature_encoders:
                self.feature_encoders[col] = LabelEncoder()
                df[f'{col}_encoded'] = self.feature_encoders[col].fit_transform(df[col])
            else:
                df[f'{col}_encoded'] = self.feature_encoders[col].transform(df[col])
        
        # 時系列特徴量
        df['month'] = df['date'].dt.month
        df['week_of_year'] = df['date'].dt.isocalendar().week
        
        # トレンド計算
        df = df.sort_values(['candidate', 'region', 'age_group', 'date'])
        df['support_trend'] = df.groupby(['candidate', 'region', 'age_group'])['support_rate'].diff()
        
        # 移動平均
        df['support_ma_7'] = df.groupby(['candidate', 'region', 'age_group'])['support_rate'].rolling(7).mean().values
        
        return df.fillna(0)
    
    def fit(self, df):
        """
        予測モデルの訓練
        """
        processed_df = self.prepare_features(df)
        
        feature_cols = ['region_encoded', 'age_group_encoded', 'candidate_encoded',
                       'days_to_election', 'month', 'week_of_year', 'sample_size',
                       'support_trend', 'support_ma_7']
        
        X = processed_df[feature_cols]
        y = processed_df['support_rate']
        
        # 各候補者別にモデルを作成
        for candidate in processed_df['candidate'].unique():
            candidate_mask = processed_df['candidate'] == candidate
            X_candidate = X[candidate_mask]
            y_candidate = y[candidate_mask]
            
            model = GradientBoostingRegressor(n_estimators=100, random_state=42)
            model.fit(X_candidate, y_candidate)
            
            self.models[candidate] = model
        
        self.feature_cols = feature_cols
        self.is_fitted = True
    
    def predict_election_outcome(self, prediction_date, regions=None, age_groups=None):
        """
        選挙結果の予測
        """
        if not self.is_fitted:
            raise ValueError("モデルが訓練されていません")
        
        if regions is None:
            regions = ['北海道', '東北', '関東', '中部', '関西', '中国', '四国', '九州']
        if age_groups is None:
            age_groups = ['18-29', '30-39', '40-49', '50-59', '60-69', '70+']
        
        predictions = {}
        
        for candidate in self.models.keys():
            candidate_predictions = []
            
            for region in regions:
                for age_group in age_groups:
                    # 入力データの作成
                    input_data = pd.DataFrame({
                        'date': [prediction_date],
                        'region': [region],
                        'age_group': [age_group],
                        'candidate': [candidate],
                        'days_to_election': [(pd.Timestamp('2023-12-01') - prediction_date).days],
                        'sample_size': [1000]  # 標準サンプルサイズ
                    })
                    
                    # 特徴量準備
                    processed_input = self.prepare_features(input_data)
                    X_input = processed_input[self.feature_cols]
                    
                    # 予測
                    pred = self.models[candidate].predict(X_input)[0]
                    candidate_predictions.append(pred)
            
            predictions[candidate] = np.mean(candidate_predictions)
        
        # 正規化(全候補者の支持率合計を1にする)
        total_support = sum(predictions.values())
        normalized_predictions = {k: v/total_support for k, v in predictions.items()}
        
        return normalized_predictions

# 選挙データの生成と予測
election_df = create_election_data()
election_predictor = ElectionPredictor()
election_predictor.fit(election_df)

# 選挙1週間前の予測
prediction_date = pd.Timestamp('2023-11-24')
election_prediction = election_predictor.predict_election_outcome(prediction_date)

print("選挙予測結果:")
for candidate, support in sorted(election_prediction.items(), key=lambda x: x[1], reverse=True):
    print(f"{candidate}: {support:.1%}")

世論の時系列変化分析

# 世論変化の可視化と分析
def analyze_opinion_trends(df):
    """
    世論の時系列変化を分析
    """
    # 日別の全国平均支持率
    daily_support = df.groupby(['date', 'candidate'])['support_rate'].mean().reset_index()
    daily_pivot = daily_support.pivot(index='date', columns='candidate', values='support_rate')
    
    # トレンド分析
    trends = {}
    for candidate in daily_pivot.columns:
        # 線形回帰でトレンドを計算
        from sklearn.linear_model import LinearRegression
        
        X = np.arange(len(daily_pivot)).reshape(-1, 1)
        y = daily_pivot[candidate].values
        
        model = LinearRegression()
        model.fit(X, y)
        
        trend_slope = model.coef_[0]
        trends[candidate] = trend_slope
    
    # 可視化
    plt.figure(figsize=(12, 8))
    
    for candidate in daily_pivot.columns:
        plt.plot(daily_pivot.index, daily_pivot[candidate], 
                label=f'{candidate} (トレンド: {trends[candidate]:+.4f})')
    
    plt.title('候補者支持率の時系列変化')
    plt.xlabel('日付')
    plt.ylabel('支持率')
    plt.legend()
    plt.xticks(rotation=45)
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()
    
    return trends, daily_pivot

trends, daily_support_data = analyze_opinion_trends(election_df)

print("候補者別トレンド(1日あたりの変化率):")
for candidate, trend in sorted(trends.items(), key=lambda x: x[1], reverse=True):
    print(f"{candidate}: {trend:+.4f}")

アンケート分析と感情分析

自由記述アンケートの感情分析

# アンケートデータの生成(サンプル)
def create_survey_data():
    np.random.seed(42)
    
    # サンプル回答(実際は大量のテキストデータ)
    positive_responses = [
        "とても満足している", "素晴らしいサービス", "期待以上の品質",
        "スタッフの対応が親切", "値段に見合った価値", "また利用したい"
    ]
    
    negative_responses = [
        "不満が残る", "期待外れだった", "改善が必要", 
        "対応が遅い", "価格が高すぎる", "もう利用しない"
    ]
    
    neutral_responses = [
        "普通だった", "可もなく不可もなく", "標準的なサービス",
        "特に問題はない", "まあまあ", "次回も検討する"
    ]
    
    all_responses = positive_responses + negative_responses + neutral_responses
    sentiments = [1] * len(positive_responses) + [-1] * len(negative_responses) + [0] * len(neutral_responses)
    
    # 追加の特徴量
    data = []
    for i, (response, sentiment) in enumerate(zip(all_responses, sentiments)):
        data.append({
            'response_id': i,
            'text_response': response,
            'sentiment_label': sentiment,
            'response_length': len(response),
            'age_group': np.random.choice(['20代', '30代', '40代', '50代', '60代']),
            'gender': np.random.choice(['男性', '女性']),
            'usage_frequency': np.random.choice(['初回', '月1回', '週1回', '毎日']),
            'satisfaction_score': np.random.randint(1, 6)  # 1-5点
        })
    
    return pd.DataFrame(data)

# テキスト特徴量の抽出
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline

class SentimentAnalyzer:
    def __init__(self):
        self.text_pipeline = Pipeline([
            ('tfidf', TfidfVectorizer(max_features=1000, ngram_range=(1, 2))),
            ('classifier', MultinomialNB())
        ])
        self.is_fitted = False
    
    def fit(self, texts, sentiments):
        """
        感情分析モデルの訓練
        """
        self.text_pipeline.fit(texts, sentiments)
        self.is_fitted = True
    
    def predict_sentiment(self, texts):
        """
        テキストの感情を予測
        """
        if not self.is_fitted:
            raise ValueError("モデルが訓練されていません")
        
        predictions = self.text_pipeline.predict(texts)
        probabilities = self.text_pipeline.predict_proba(texts)
        
        return predictions, probabilities
    
    def analyze_sentiment_distribution(self, df):
        """
        感情分布の分析
        """
        # 全体の感情分布
        sentiment_dist = df['sentiment_label'].value_counts()
        sentiment_labels = {-1: 'ネガティブ', 0: 'ニュートラル', 1: 'ポジティブ'}
        
        print("感情分布:")
        for sentiment, count in sentiment_dist.items():
            label = sentiment_labels[sentiment]
            percentage = count / len(df) * 100
            print(f"  {label}: {count}件 ({percentage:.1f}%)")
        
        # 属性別感情分析
        print("\n年齢層別感情分布:")
        age_sentiment = pd.crosstab(df['age_group'], df['sentiment_label'], normalize='index') * 100
        print(age_sentiment.round(1))
        
        return sentiment_dist, age_sentiment

# アンケート分析の実行
survey_df = create_survey_data()
sentiment_analyzer = SentimentAnalyzer()

# モデル訓練
sentiment_analyzer.fit(survey_df['text_response'], survey_df['sentiment_label'])

# 感情分布分析
sentiment_dist, age_sentiment = sentiment_analyzer.analyze_sentiment_distribution(survey_df)

# 新しいテキストの感情予測
new_texts = ["サービスが最高でした", "改善してほしい点が多い", "まずまずの対応"]
predictions, probabilities = sentiment_analyzer.predict_sentiment(new_texts)

print("\n新規テキストの感情予測:")
sentiment_labels = {-1: 'ネガティブ', 0: 'ニュートラル', 1: 'ポジティブ'}
for text, pred, prob in zip(new_texts, predictions, probabilities):
    label = sentiment_labels[pred]
    confidence = max(prob)
    print(f"「{text}」 → {label} (信頼度: {confidence:.2f})")

潜在因子分析とクラスタリング

from sklearn.decomposition import FactorAnalysis
from sklearn.cluster import KMeans

class SurveyAnalyzer:
    def __init__(self):
        self.factor_model = None
        self.cluster_model = None
        self.numeric_cols = None
    
    def perform_factor_analysis(self, df, n_factors=3):
        """
        因子分析の実行
        """
        # 数値データの抽出
        numeric_cols = ['satisfaction_score', 'response_length']
        
        # カテゴリカル変数のダミー化
        categorical_features = pd.get_dummies(df[['age_group', 'gender', 'usage_frequency']])
        
        # 特徴量行列の作成
        feature_matrix = pd.concat([df[numeric_cols], categorical_features], axis=1)
        
        # 因子分析
        self.factor_model = FactorAnalysis(n_components=n_factors, random_state=42)
        factor_scores = self.factor_model.fit_transform(feature_matrix)
        
        # 因子負荷量の分析
        factor_loadings = pd.DataFrame(
            self.factor_model.components_.T,
            columns=[f'Factor_{i+1}' for i in range(n_factors)],
            index=feature_matrix.columns
        )
        
        print("因子負荷量:")
        print(factor_loadings.round(3))
        
        return factor_scores, factor_loadings
    
    def customer_segmentation(self, factor_scores, n_clusters=4):
        """
        因子スコアに基づく顧客セグメンテーション
        """
        self.cluster_model = KMeans(n_clusters=n_clusters, random_state=42)
        clusters = self.cluster_model.fit_predict(factor_scores)
        
        # クラスター特徴の分析
        cluster_analysis = pd.DataFrame(factor_scores)
        cluster_analysis['cluster'] = clusters
        
        cluster_summary = cluster_analysis.groupby('cluster').mean()
        cluster_summary.columns = [f'Factor_{i+1}' for i in range(factor_scores.shape[1])]
        
        print("\nクラスター別因子スコア平均:")
        print(cluster_summary.round(3))
        
        return clusters, cluster_summary
    
    def generate_insights(self, df, clusters):
        """
        分析結果からインサイトを生成
        """
        df_with_clusters = df.copy()
        df_with_clusters['cluster'] = clusters
        
        insights = {}
        
        for cluster_id in range(len(np.unique(clusters))):
            cluster_data = df_with_clusters[df_with_clusters['cluster'] == cluster_id]
            
            insights[f'Cluster_{cluster_id}'] = {
                'size': len(cluster_data),
                'avg_satisfaction': cluster_data['satisfaction_score'].mean(),
                'dominant_age_group': cluster_data['age_group'].mode().iloc[0],
                'dominant_gender': cluster_data['gender'].mode().iloc[0],
                'avg_sentiment': cluster_data['sentiment_label'].mean()
            }
        
        return insights

# 調査分析の実行
analyzer = SurveyAnalyzer()

# 因子分析
factor_scores, factor_loadings = analyzer.perform_factor_analysis(survey_df)

# クラスタリング
clusters, cluster_summary = analyzer.customer_segmentation(factor_scores)

# インサイト生成
insights = analyzer.generate_insights(survey_df, clusters)

print("\n=== セグメント別インサイト ===")
for cluster_name, insight in insights.items():
    print(f"\n{cluster_name}:")
    print(f"  サイズ: {insight['size']}人")
    print(f"  平均満足度: {insight['avg_satisfaction']:.2f}")
    print(f"  主要年齢層: {insight['dominant_age_group']}")
    print(f"  主要性別: {insight['dominant_gender']}")
    print(f"  平均感情スコア: {insight['avg_sentiment']:.2f}")

まとめ

視聴率、選挙、アンケート分析における機械学習の活用により、従来の統計分析では捉えられなかった複雑なパターンや予測が可能になります。リアルタイム予測システムの構築により、迅速な意思決定支援が実現できます。

各分析領域の特性を理解し、適切な前処理と特徴量エンジニアリングを行うことで、高精度な予測と有意義なインサイトの抽出が可能です。継続的なモデル改善により、変化する社会情勢や消費者行動に対応した分析システムを構築できます。

■テックジム「AIエンジニア養成コース」

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座