Lesson 56 · Social Media Content Analytics
Turning Social Media Data into Insights
In this lesson, we will learn how to transform raw social media metrics into useful business and content insights. You will see how content creators and…
- CourseSocial Media Content Analytics
- Lesson56 of 41
- Video32 min
- FormatJupyter notebook · 24 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbTurning Social Media Data into Insights#
- In this lesson, we will learn how to transform raw social media metrics into useful business and content insights.
- You will see how content creators and brands can discover what works, when to post, and how to improve, using real engagement data.
- We will walk through hands-on examples using public datasets representing trending videos, social media posts, and time series engagement.
- By the end of the lesson, you will be able to identify high-performing content and understand key patterns in social media analytics.
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
Core Social Media Analytics Concepts#
- Social media datasets usually track content (videos, posts) alongside engagement metrics like views, likes, comments, shares, and watch time.
- Views measure reach, while likes and comments reflect deeper engagement.
- Click-through rate (CTR) and watch time help show audience interest and quality.
- Engagement rate helps compare performance across different posts and sizes.
- It is important not to focus on one metric only or to confuse absolute vs. relative performance.
- Beginners often ignore audience size, or look at ratios like likes per view without context.
import os, pickle
from pathlib import Path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
SCOPES = ['https://www.googleapis.com/auth/youtube.readonly']
def get_yt_service():
api_key = os.environ.get('YOUTUBE_API_KEY')
if api_key:
return build('youtube', 'v3', developerKey=api_key)
if Path('client_secret.json').exists():
creds = None
if Path('token_ro.pickle').exists():
with open('token_ro.pickle', 'rb') as f:
creds = pickle.load(f)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file('client_secret.json', SCOPES)
creds = flow.run_local_server(port=0)
with open('token_ro.pickle', 'wb') as f:
pickle.dump(creds, f)
return build('youtube', 'v3', credentials=creds)
raise EnvironmentError('Set YOUTUBE_API_KEY or provide client_secret.json')
def fetch_yt_trending(max_results=200, region='US'):
youtube = get_yt_service()
records, token = [], None
while len(records) < max_results:
resp = youtube.videos().list(
part='snippet,statistics',
chart='mostPopular',
regionCode=region,
maxResults=min(50, max_results - len(records)),
pageToken=token
).execute()
for item in resp.get('items', []):
s = item['snippet']; st = item.get('statistics', {})
records.append({
'video_id': item['id'],
'trending_date': pd.Timestamp.today().date(),
'title': s.get('title', ''),
'channel_title': s.get('channelTitle', ''),
'category_id': s.get('categoryId', ''),
'views': int(st.get('viewCount', 0)),
'likes': int(st.get('likeCount', 0)),
'comment_count': int(st.get('commentCount', 0)),
})
token = resp.get('nextPageToken')
if not token: break
return pd.DataFrame(records)
try:
df_trend = fetch_yt_trending()
print('Live trending data:', df_trend.shape)
except Exception as e:
print(f'Falling back to synthetic: {e}')
np.random.seed(42)
n = 1000
df_trend = pd.DataFrame({
'video_id': [f'vid{i}' for i in range(n)],
'trending_date': pd.date_range('2023-01-01', periods=n, freq='D'),
'title': [f'Video Title {i}' for i in range(n)],
'channel_title': np.random.choice(['ChannelA','ChannelB','ChannelC'], n),
'category_id': np.random.choice([1,2,10,22,24,28], n),
'views': np.random.randint(10000, 5000000, n),
'likes': np.random.randint(100, 200000, n),
'comment_count': np.random.randint(10, 50000, n),
})
print('Synthetic fallback:', df_trend.shape)
print(df_trend.head(3))
np.random.seed(42)
n_posts = 500
views = np.random.randint(100, 100000, n_posts)
df_content = pd.DataFrame({
'post_id': range(1, n_posts+1),
'platform': np.random.choice(['YouTube','Instagram','TikTok'], n_posts),
'date': pd.date_range('2023-01-01', periods=n_posts, freq='6h'),
'views': views,
'likes': (views * np.random.uniform(0.02, 0.15, n_posts)).astype(int),
'comments': (views * np.random.uniform(0.001, 0.05, n_posts)).astype(int),
'shares': (views * np.random.uniform(0.001, 0.03, n_posts)).astype(int)
})
print(df_content.shape)
print(df_content.head(3))
print('Average view count on trending videos:', df_trend['views'].mean())
print('Typical trending video view distribution:')
print(df_trend['views'].describe())
df_content['engagement_rate'] = ((df_content['likes'] + df_content['comments'] + df_content['shares']) / df_content['views']) * 100
print(df_content[['platform','views','likes','comments','shares','engagement_rate']].head(3))
platform_eng = df_content.groupby('platform')['engagement_rate'].mean().sort_values(ascending=False)
print(platform_eng)
top_trending = df_trend.sort_values('views', ascending=False).head(5)
print('Top 5 trending videos by views:')
print(top_trending[['title', 'channel_title', 'views', 'likes', 'comment_count']])
median_eng = df_content.groupby('platform')['engagement_rate'].median()
for plat, med in median_eng.items():
print(f'Platform: {plat}, Median engagement rate: {med:.2f}%')
high_eng = df_content[df_content['engagement_rate'] > 40]
print(f'Number of posts with engagement rate above 40%: {len(high_eng)}')
print(high_eng[['platform', 'views', 'likes', 'comments', 'shares', 'engagement_rate']].head(3))
import matplotlib.pyplot as plt
plt.figure(figsize=(7,4))
plt.scatter(df_content['views'], df_content['likes'], alpha=0.5)
plt.xlabel('Views')
plt.ylabel('Likes')
plt.title('Likes vs. Views for Social Media Posts')
plt.grid(True)
plt.tight_layout()
plt.show()
df_content['comment_rate'] = (df_content['comments'] / df_content['views']) * 100
mean_comment = df_content.groupby('platform')['comment_rate'].mean()
print('Average comment rate (%) by platform:')
print(mean_comment.round(2))
# Here we define a viral post as having >20,000 views and >25% engagement
viral = df_content[(df_content['views'] > 20000) & (df_content['engagement_rate'] > 25)]
print(f'Number of viral posts identified: {len(viral)}')
print(viral[['platform', 'views', 'engagement_rate']].head())
df_content['hour'] = df_content['date'].dt.hour
hourly_eng = df_content.groupby('hour')['engagement_rate'].mean().sort_values(ascending=False)
best_hour = hourly_eng.idxmax()
print('Average engagement rate by posting hour:')
print(hourly_eng)
print(f'Best posting hour identified: {best_hour}:00')
leaderboard = df_content.copy()
leaderboard['score'] = leaderboard['engagement_rate']*0.7 + (leaderboard['views']/10000)*0.3
top_content = leaderboard.sort_values('score', ascending=False).head(5)
print('Top 5 posts by combined engagement and reach:')
print(top_content[['post_id', 'platform', 'views', 'engagement_rate', 'score']])
df_broken = df_content.copy()
df_broken.loc[5:8, 'likes'] = np.nan
missing_count = df_broken['likes'].isnull().sum()
print(f'Liking values missing for {missing_count} posts.')
df_broken['likes_filled'] = df_broken['likes'].fillna(df_broken['likes'].median())
print('Missing likes replaced with median value. Example:')
print(df_broken[['likes', 'likes_filled']].iloc[5:10])
bad_agg = df_content.groupby('platform')[['likes', 'comments', 'shares']].sum().sum(axis=1)
print('Sum of engagement across platforms (incorrect):')
print(bad_agg)
good_agg = df_content.groupby('platform').apply(lambda x: ((x['likes'] + x['comments'] + x['shares']) / x['views']).sum())
print('Total correct engagement ratio by platform:')
print(good_agg)
small = df_content[df_content['views'] < 300]
print('Posts with very few views and unusual engagement rates:')
print(small[['views', 'likes', 'engagement_rate']].head())
category_avg_views = df_trend.groupby('category_id')['views'].mean()
print('Average trending video views per category:')
print(category_avg_views.round().astype(int))
bench = df_content.groupby('platform')['views'].median()
for plat, mid in bench.items():
print(f'Median views per post on {plat}: {mid}')
df_content['quartile'] = pd.qcut(df_content['engagement_rate'], 4, labels=['Q1','Q2','Q3','Q4'])
segment_counts = df_content.groupby(['platform', 'quartile']).size().unstack().fillna(0).astype(int)
print('Count of posts per engagement rate quartile, by platform:')
print(segment_counts)
from matplotlib.dates import DateFormatter
daily_eng = df_content.groupby(df_content['date'].dt.date)['engagement_rate'].mean()
plt.figure(figsize=(10,4))
plt.plot(daily_eng.index, daily_eng.values)
plt.title('Engagement Rate Trend Over Time')
plt.xlabel('Date')
plt.ylabel('Average Engagement Rate (%)')
plt.gca().xaxis.set_major_formatter(DateFormatter('%b-%d'))
plt.xticks(rotation=45)
plt.grid(True)
plt.tight_layout()
plt.show()
def consistent_engagement(df):
return ((df['likes'].fillna(0) + df['comments'].fillna(0) + df['shares'].fillna(0)) / df['views']) * 100
df_content['cons_engage'] = consistent_engagement(df_content)
print(df_content[['engagement_rate', 'cons_engage']].head())
benchmark = df_content.groupby('platform')['engagement_rate'].mean()
top_platform = benchmark.idxmax()
print(f'Your top-performing platform for engagement is: {top_platform}')
if top_platform == 'TikTok':
print('Consider making more TikTok posts when aiming for high engagement.')
elif top_platform == 'Instagram':
print('Focus on Instagram strategies, such as Stories or Reels, for boosting engagement.')
elif top_platform == 'YouTube':
print('Emphasize YouTube Shorts, Community posts, or longer-form videos for more interaction.')
top_post = df_content.sort_values('engagement_rate', ascending=False).iloc[0]
print('Top post for engagement:')
print(top_post[['platform', 'date', 'views', 'likes', 'comments', 'shares', 'engagement_rate']])
recommendation = f'Post more on {top_post["platform"]} at {top_post["date"].hour}:00 for better engagement!'
print('Recommendation:', recommendation)
If you want more lessons like this, please like the YouTube video!#
Subscribe to the channel so you do not miss the next lesson on social data analytics!#
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



