Domain: Business Operations & Analytics

You have a social media performance dataset (`social_media_performance.csv`) covering posts across four platforms (Instagram, LinkedIn, Medium, YouTube) from 2025.

We need to measure engagement quality, not just volume. Define an engagement depth score for each post: likes count once, comments twice, shares three times, all divided by views.

For each platform separately, remove posts in the bottom 5% and top 5% of views. Then keep only posts from business hours (weekdays, 9 AM to 5 PM).

Classify posts by sentiment_score: below -0.3 is Negative, from -0.3 through 0.3 is Neutral, above 0.3 is Positive. For each platform and sentiment bucket, compute the harmonic mean of the per-post engagement depth scores (column: harmonic_mean_eds), the number of posts (column: post_count), and the proportion of viral posts (column: viral_rate). Save this table to `sentiment_analysis.csv`.

Which platform has the highest overall harmonic mean engagement depth score? For that platform, compute Kendall's tau between sentiment_score and engagement depth score.

Compute the coefficient of variation (population standard deviation) of engagement depth score per platform. Which one is most consistent?

Find the platform-sentiment group with the highest harmonic mean engagement depth score. What fraction of that group's total engagement (likes + comments + shares) comes from viral posts?

Print all results.

Grading rubric:
criterion: A file named sentiment_analysis.csv is produced containing columns: platform, sentiment_bucket, and harmonic_mean_eds.
weight: 5
criterion: Kendall's tau for Medium, rounded to 2 decimal places, equals 0.18.
weight: 5
criterion: The platform-sentiment group with the highest harmonic mean engagement depth score is Medium-Positive.
weight: 10
criterion: The engagement concentration ratio for the top group, rounded to 2 decimal places, equals 0.79.
weight: 10
criterion: The harmonic mean engagement depth score for LinkedIn-Positive, rounded to 4 decimal places, equals 0.0966.
weight: 20
criterion: The harmonic mean engagement depth score for Medium-Positive, rounded to 3 decimal places, equals 0.161.
weight: 15
criterion: The coefficient of variation for Medium (population standard deviation), rounded to 2 decimal places, equals 42.58%.
weight: 20

Golden answer:
## Complete Python Code
```python
import pandas as pd
import numpy as np
from scipy import stats
from scipy.stats import hmean

# Load dataset, update the path as needed
df = pd.read_csv('social_media_performance.csv')

# Data cleaning
# Standardize platform names (trailing spaces, lowercase variants)
df['platform'] = df['platform'].str.strip().str.title()
df['platform'] = df['platform'].replace({'Linkedin': 'LinkedIn', 'Youtube': 'YouTube'})

# Fix is_viral column (some rows have string "True"/"False" instead of 1/0)
df['is_viral'] = df['is_viral'].replace({'True': 1, 'False': 0})
df['is_viral'] = pd.to_numeric(df['is_viral'])

# Remove duplicate rows
df = df.drop_duplicates()

# Parse mixed date formats (some rows are DD/MM/YYYY)
df['post_datetime'] = pd.to_datetime(df['post_datetime'], format='mixed', dayfirst=True)

# Remove invalid rows: zero views, negative shares, missing sentiment
df = df[(df['views'] > 0) & (df['shares'] >= 0) & (df['sentiment_score'].notna())]

# Analysis pipeline

# Engagement depth score: likes 1x, comments 2x, shares 3x
df['eds'] = (df['likes'] + 2 * df['comments'] + 3 * df['shares']) / df['views']
df['total_engagement'] = df['likes'] + df['comments'] + df['shares']

# Sentiment buckets
def assign_bucket(s):
    if s < -0.3:
        return 'Negative'
    elif s <= 0.3:
        return 'Neutral'
    else:
        return 'Positive'

df['sentiment_bucket'] = df['sentiment_score'].apply(assign_bucket)

# Trim outlier-reach posts: bottom/top 5% of views per platform
trimmed = []
for platform in sorted(df['platform'].unique()):
    sub = df[df['platform'] == platform]
    q05 = sub['views'].quantile(0.05)
    q95 = sub['views'].quantile(0.95)
    kept = sub[(sub['views'] >= q05) & (sub['views'] <= q95)]
    trimmed.append(kept)
df = pd.concat(trimmed)

# Business hours: weekday, 9 AM to 5 PM
df['hour'] = df['post_datetime'].dt.hour
df['dow'] = df['post_datetime'].dt.dayofweek
df = df[(df['dow'] < 5) & (df['hour'] >= 9) & (df['hour'] < 17)]

# HM EDS per platform-sentiment
rows = []
for platform in sorted(df['platform'].unique()):
    for bucket in ['Negative', 'Neutral', 'Positive']:
        sub = df[(df['platform'] == platform) & (df['sentiment_bucket'] == bucket)]
        hm = hmean(sub['eds'])
        vr = sub['is_viral'].mean()
        rows.append({
            'platform': platform,
            'sentiment_bucket': bucket,
            'harmonic_mean_eds': round(hm, 6),
            'post_count': len(sub),
            'viral_rate': round(vr, 6)
        })
        print(f"{platform}-{bucket}: hm={hm:.6f}, n={len(sub)}, vr={vr:.4f}")

pd.DataFrame(rows).to_csv('sentiment_analysis.csv', index=False)

# Top platform by overall HM EDS
print("\nOverall HM EDS:")
phm = {}
for platform in sorted(df['platform'].unique()):
    hm = hmean(df[df['platform'] == platform]['eds'])
    phm[platform] = hm
    print(f"  {platform}: {hm:.6f}")
top = max(phm, key=phm.get)
print(f"Top: {top}")

# Kendall tau for top platform
sub = df[df['platform'] == top]
tau, pval = stats.kendalltau(sub['sentiment_score'], sub['eds'])
print(f"Kendall tau ({top}): {tau:.6f}")

# CV with population std
print("\nCV (pop std):")
for platform in sorted(df['platform'].unique()):
    s = df[df['platform'] == platform]['eds']
    cv = (s.std(ddof=0) / s.mean()) * 100
    print(f"  {platform}: {cv:.4f}%")

# Top combo + concentration
combos = []
for platform in sorted(df['platform'].unique()):
    for bucket in ['Negative', 'Neutral', 'Positive']:
        sub = df[(df['platform'] == platform) & (df['sentiment_bucket'] == bucket)]
        if len(sub) > 0:
            hm = hmean(sub['eds'])
            combos.append((platform, bucket, hm))

best = max(combos, key=lambda x: x[2])
print(f"\nTop combo: {best[0]}-{best[1]} (hm={best[2]:.6f})")

grp = df[(df['platform'] == best[0]) & (df['sentiment_bucket'] == best[1])]
viral_eng = grp[grp['is_viral'] == 1]['total_engagement'].sum()
total_eng = grp['total_engagement'].sum()
conc = viral_eng / total_eng
print(f"Concentration: {conc:.6f}")
```

## Explanation

The dataset has quality issues requiring preprocessing: inconsistent platform names (trailing spaces, mixed casing), duplicates, zero views, negative shares, missing sentiment, mixed date formats, and string "True"/"False" in is_viral. All are cleaned before analysis.

Engagement depth score = (likes + 2*comments + 3*shares) / views. Outlier trimming removes bottom/top 5% of views per platform independently. Business hours = weekdays, hour >= 9 and hour < 17.

Sentiment buckets: below -0.3 Negative, -0.3 to 0.3 Neutral, above 0.3 Positive. Harmonic mean is computed over per-post EDS within each group; post count and viral rate are separate columns.

Medium has the highest overall HM EDS. Kendall's tau for Medium = 0.18. CV uses population std (ddof=0); Medium is most consistent at 42.58%. Engagement concentration for Medium-Positive (fraction of total engagement from viral posts) = 0.79.