- Posted on
- • Artificial Intelligence
Artificial Intelligence Player Analytics
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Artificial Intelligence Player Analytics on Linux: A Bash-First Pipeline
What if you could answer “Which players will churn next week?” or “Who are my high-value players?” from your terminal? With a few open-source tools and a sprinkle of machine learning, you can go from raw game logs to actionable insights—without leaving Linux or paying for a black-box platform.
This post shows how to build a minimal, reproducible AI-driven player analytics workflow that’s:
Bash-friendly and Git-friendly
Cheap to run on any Linux box
Transparent and customizable
We’ll collect events, engineer features at the command line, train a simple segmentation model, and produce terminal-native reports you can automate with cron.
Why AI Player Analytics is worth your time
Better retention: Segment players by behavior and target interventions before they churn.
Smarter monetization: Identify whales vs. casuals and tune offers accordingly.
Design feedback loop: Find progression bottlenecks by correlating playtime, sessions, and drop-off.
Ops at terminal speed: Simple, auditable pipelines you can run locally or in CI.
What we’ll build
Input: JSONL event logs (session ends, purchases)
Processing: jq and Bash to aggregate per-player features
Model: K-Means clustering in Python to segment players
Output: CSVs, SQLite tables, and a terminal plot
Automation: A single script and a cron entry
1) Install prerequisites
Use your package manager of choice to install core tools. Then we’ll use pip for Python libraries.
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y python3 python3-venv python3-pip jq sqlite3 git gnuplot
- Fedora/RHEL/CentOS (dnf):
sudo dnf install -y python3 python3-pip jq sqlite git gnuplot
- openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y python3 python3-pip jq sqlite3 git gnuplot
Create a virtual environment and install ML libs:
python3 -m venv .venv
. .venv/bin/activate
pip install --upgrade pip
pip install numpy pandas scikit-learn joblib
2) Capture and structure events
Assume your game/client/server emits events as one JSON object per line (JSONL). Keep PII out; prefer hashed IDs.
Example: game_events.jsonl
{"player_id":"p1","event":"session_end","session_secs":300,"ts":"2026-07-01T12:00:00Z"}
{"player_id":"p1","event":"purchase","purchase_usd":4.99,"ts":"2026-07-01T12:05:00Z"}
{"player_id":"p2","event":"session_end","session_secs":120,"ts":"2026-07-02T08:13:00Z"}
{"player_id":"p2","event":"session_end","session_secs":200,"ts":"2026-07-02T09:20:00Z"}
{"player_id":"p2","event":"purchase","purchase_usd":1.99,"ts":"2026-07-02T09:25:00Z"}
Tip:
Use ISO-8601 timestamps (UTC).
Prefer append-only logs (easy to sync and process).
Validate schema at ingest time.
3) Build features in Bash with jq
We’ll derive per-player features: sessions, total playtime, average session length, purchase count, and spend. The following command slurps all events, groups by player_id, computes aggregates, and emits CSV.
jq -s '
def ses: map(select(.event=="session_end") | .session_secs);
def pur: map(select(.event=="purchase") | .purchase_usd);
group_by(.player_id)
| map({
player_id: .[0].player_id,
sessions: (ses | length),
total_playtime: (ses | add // 0),
avg_session: (ses | if length>0 then (add / length) else 0 end),
purchases: (pur | length),
spend: (pur | add // 0)
})
| (["player_id","sessions","total_playtime","avg_session","purchases","spend"],
(.[] | [ .player_id, .sessions, .total_playtime, .avg_session, .purchases, .spend ]))
| @csv
' game_events.jsonl > features.csv
Peek at the result:
head -5 features.csv | column -s, -t
Optional: Store features in SQLite for easy querying.
tail -n +2 features.csv > features_noheader.csv
sqlite3 analytics.db <<'SQL'
.mode csv
CREATE TABLE IF NOT EXISTS player_features (
player_id TEXT,
sessions INTEGER,
total_playtime REAL,
avg_session REAL,
purchases INTEGER,
spend REAL
);
.import features_noheader.csv player_features
SQL
4) Train a first-pass AI model (K-Means segmentation)
We’ll standardize features and cluster players into 4 behavioral segments.
Create train_kmeans.py:
#!/usr/bin/env python3
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import joblib
# Load engineered features
df = pd.read_csv("features.csv")
feature_cols = ["sessions", "total_playtime", "avg_session", "purchases", "spend"]
X = df[feature_cols].fillna(0)
# Scale features (important for K-Means)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Train K-Means
kmeans = KMeans(n_clusters=4, n_init=10, random_state=42)
df["cluster"] = kmeans.fit_predict(X_scaled)
# Persist artifacts
df[["player_id", "cluster"]].to_csv("segments.csv", index=False)
centers = pd.DataFrame(
scaler.inverse_transform(kmeans.cluster_centers_),
columns=feature_cols
)
centers["cluster"] = range(len(centers))
centers.to_csv("cluster_centers.csv", index=False)
joblib.dump(
{"scaler": scaler, "model": kmeans, "features": feature_cols},
"player_segmentation.joblib"
)
print("Wrote segments.csv, cluster_centers.csv, player_segmentation.joblib")
Run it:
. .venv/bin/activate
python train_kmeans.py
Import segments into SQLite and explore:
tail -n +2 segments.csv > segments_noheader.csv
sqlite3 analytics.db <<'SQL'
.mode csv
CREATE TABLE IF NOT EXISTS player_segments (
player_id TEXT PRIMARY KEY,
cluster INTEGER
);
.import segments_noheader.csv player_segments
.mode column
.headers on
SELECT s.cluster, COUNT(*) AS players,
ROUND(AVG(f.spend),2) AS avg_spend,
ROUND(AVG(f.total_playtime),1) AS avg_playtime
FROM player_segments s
JOIN player_features f USING(player_id)
GROUP BY s.cluster
ORDER BY avg_spend DESC;
SQL
Optional: a quick terminal scatterplot (sessions vs spend) colored by cluster using gnuplot.
Join features and segments to a TSV:
awk -F, 'NR==FNR{seg[$1]=$2; next} FNR==1{print "player_id\tsessions\tspend\tcluster"; next} {print $1"\t"$2"\t"$6"\t"seg[$1]}' segments.csv features.csv > features_with_clusters.tsv
Split per-cluster data:
for i in 0 1 2 3; do
awk -F'\t' 'NR>1 && $4=='"$i"' {print $2, $3}' features_with_clusters.tsv > c$i.dat
done
Plot in ASCII (adjust terminal width/height as needed):
gnuplot -persist <<'GP'
set term dumb 120 30
set title "Sessions vs Spend by Cluster"
set xlabel "sessions"
set ylabel "spend (USD)"
plot 'c0.dat' with points title 'c0', \
'c1.dat' with points title 'c1', \
'c2.dat' with points title 'c2', \
'c3.dat' with points title 'c3'
GP
5) Automate the pipeline
Create run_pipeline.sh to tie it all together:
#!/usr/bin/env bash
set -euo pipefail
LOG_DIR="${LOG_DIR:-.}"
DATA="${DATA:-game_events.jsonl}"
DB="${DB:-analytics.db}"
# 1) venv and deps
if [ ! -d .venv ]; then
python3 -m venv .venv
fi
. .venv/bin/activate
pip install -q --upgrade pip
pip install -q numpy pandas scikit-learn joblib
# 2) Feature engineering
jq -s '
def ses: map(select(.event=="session_end") | .session_secs);
def pur: map(select(.event=="purchase") | .purchase_usd);
group_by(.player_id)
| map({
player_id: .[0].player_id,
sessions: (ses | length),
total_playtime: (ses | add // 0),
avg_session: (ses | if length>0 then (add / length) else 0 end),
purchases: (pur | length),
spend: (pur | add // 0)
})
| (["player_id","sessions","total_playtime","avg_session","purchases","spend"],
(.[] | [ .player_id, .sessions, .total_playtime, .avg_session, .purchases, .spend ]))
| @csv
' "$DATA" > features.csv
# 3) Train model
python train_kmeans.py
# 4) Load into SQLite
tail -n +2 features.csv > features_noheader.csv
tail -n +2 segments.csv > segments_noheader.csv
sqlite3 "$DB" <<'SQL'
.mode csv
CREATE TABLE IF NOT EXISTS player_features (
player_id TEXT,
sessions INTEGER,
total_playtime REAL,
avg_session REAL,
purchases INTEGER,
spend REAL
);
DELETE FROM player_features;
.import features_noheader.csv player_features
CREATE TABLE IF NOT EXISTS player_segments (
player_id TEXT PRIMARY KEY,
cluster INTEGER
);
DELETE FROM player_segments;
.import segments_noheader.csv player_segments
SQL
echo "[OK] Pipeline completed at $(date)"
Make executable and test:
chmod +x run_pipeline.sh
./run_pipeline.sh
Run nightly via cron:
crontab -e
Add:
0 2 * * * /path/to/run_pipeline.sh >> /var/log/player_analytics.log 2>&1
Real-world applications you can ship this week
Retention saves: Find clusters with high first-session time but low return sessions. Trigger a day-2 push/email with a relevant reward.
Monetization tuning: Identify clusters with moderate playtime but zero spend; test a gentler early-offer ramp or currency drip.
Difficulty smoothing: If a cluster shows falling session counts beyond level N, investigate spike points and experiment with dynamic difficulty.
UA feedback: Share cluster mix by campaign/source with marketing to allocate spend toward higher-LTV cohorts.
Conclusion and next steps
You’ve built a transparent, end-to-end AI analytics loop:
Bash and jq to transform raw events into features
Python to learn behavior segments
SQLite and gnuplot to explore results in your terminal
Cron to keep it humming
From here, consider:
Adding recency/frequency/monetary (RFM) features and day-7 retention labels
Training a churn classifier (logistic regression) using time-windowed features
Versioning data and models with Git and Makefiles
Shipping daily CSVs to your BI tool—or just keep it CLI-native
If this helped, try pointing it at a week of production logs and see what clusters pop out. Then close the loop: test one intervention per segment and measure impact.