Pure Classification Project ยท ML & DL

Name That LLM:
ML vs DL
Classification

A complete walkthrough of the Name That LLM dataset from Kaggle. Build 5 scikit-learn models and 1 TensorFlow neural network to predict which LLM generated the text. This is a pure classification project โ€” handling both binary and multiclass scenarios dynamically. Every line of code is explained for beginners.

Start the Walkthrough View Dataset
๐Ÿค–LLM text data
5ML classifiers
1DL neural network
MultiClass support
load_dataset.py
# Name That LLM โ€” KaggleHub
import kagglehub
from kagglehub import KaggleDatasetAdapter

df = kagglehub.load_dataset(
    KaggleDatasetAdapter.PANDAS,
    "prvsiyan/name-that-llm...",
    file_path,
)

print("First 5 records:", df.head())
Pure Classificationno regression task
Copy & Runfull project code
Predict LLMmulticlass support
Step 01 / Data Loading

Load the dataset with KaggleHub.

Stream the Name That LLM dataset straight into a pandas DataFrame โ€” no manual download needed.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Before You Start

What is this dataset? The Name That LLM dataset contains data about text prompts or names, designed to classify which Large Language Model (LLM) generated the text or belongs to the name. Each row is one text sample or name entry. It’s perfect for learning classification because it combines text features with a categorical target (the LLM identity).

What is KaggleHub? Kaggle is a website where people share datasets for machine learning. KaggleHub is a Python library that lets you load those datasets directly into your code with one line โ€” no manual downloading.

What is a DataFrame? A pandas DataFrame is like an Excel spreadsheet inside Python. It has rows (one per text sample) and columns (text length, character count, target LLM, etc.). The variable df we create here holds all the data.

Why check shape, head(), info(), describe()?

  • df.shape โ†’ How many rows (samples) and columns?
  • df.head() โ†’ Show the first 5 rows so you can see column names and sample values
  • df.info() โ†’ What type of data is in each column? (text vs. numbers) How many missing values?
  • df.describe() โ†’ Basic statistics for numeric columns

Important: The file_path is the CSV filename inside the dataset. Visit the Kaggle dataset page โ†’ Files tab to find the exact filename. Also, check df.head() to identify the exact column name for the LLM label/target โ€” it might be called llm, model, label, or something else. The code in Step 3 auto-detects it.

step1_load_data.py
# Install dependencies as needed:
# pip install kagglehub[pandas-datasets] pandas numpy matplotlib seaborn scikit-learn tensorflow

import kagglehub
from kagglehub import KaggleDatasetAdapter
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Set the path to the file you'd like to load
# Check the Kaggle dataset page โ†’ Files tab for the exact filename
file_path = "name_that_llm.csv"

# Load the latest version
df = kagglehub.load_dataset(
    KaggleDatasetAdapter.PANDAS,
    "prvsiyan/prvsiyans-extended-name-that-llm-dataset",
    file_path,
)

print("Dataset shape:", df.shape)
print("First 5 records:")
print(df.head())
print(df.info())
print(df.describe())
โžœ~/name-that-llm-mlpython step1_load_data.py
Dataset shape: (N, M) โ† depends on the datasetFirst 5 records: text_prompt char_count word_count … llm_label 0 Explain… 150 25 … chatgpt 1 Write a… 200 40 … claude 2 What is… 80 15 … geminiโ† actual columns and values depend on the dataset
โœ“Dataset loaded โ€” check df.head() to identify exact column names
๐Ÿ“– Code Walkthrough โ€” What Each Line Does
import kagglehub …
Lines 1โ€“6: Import the libraries. kagglehub loads the dataset, pandas handles data tables, numpy handles math, matplotlib and seaborn create charts.
file_path = “…”
Line 8: The CSV filename inside the Kaggle dataset. Check the Files tab on the Kaggle page to confirm the exact name.
df = kagglehub.load_dataset(…)
Lines 10โ€“14: The magic line. We tell KaggleHub: (1) we want a pandas DataFrame, (2) the dataset is "prvsiyan/prvsiyans-extended-name-that-llm-dataset", (3) load the file we specified. Result stored in df.
print(df.shape)
Line 16: Prints the number of rows (samples) and columns. First sanity check.
print(df.head())
Line 18: Shows the first 5 rows. Pay attention to column names โ€” you’ll need to know which column represents the LLM label for Steps 2 and 3.
print(df.info())
Line 20: Lists each column’s name and data type. object = text (categorical), int64/float64 = numbers. Also shows missing values.
print(df.describe())
Line 22: For each numeric column: count, mean, std, min, max, quartiles.
Step 02 / EDA

Exploratory Data Analysis in seaborn.

Before any model touches the data, we visualize the class distribution and check correlations.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Understanding EDA

What is EDA? Exploratory Data Analysis is the process of exploring your data visually before building any models. It’s like reviewing the text samples before drawing conclusions โ€” you want to know what patterns exist.

What is a countplot? A countplot counts how many samples belong to each class. For a classification dataset, this is the most important chart โ€” it shows if your classes are balanced (roughly equal counts) or imbalanced (one class dominates). Imbalanced data requires special handling.

What is a histogram? A histogram counts how many samples fall into each numeric range. For example, how many text prompts have 50โ€“100 characters, how many 100โ€“150, etc.

What is correlation? Correlation measures how strongly two numeric variables move together, from -1 to +1. If character count and word count correlate above 0.8, it means longer texts naturally have more words. The heatmap shows all pairwise correlations at once.

Why does EDA matter? The class distribution plot reveals whether you’re dealing with binary or multiclass classification, and whether the data is balanced. This tells you which metrics (accuracy vs F1) to prioritize.

2.1 ยท Missing values, target detection & class distribution

step2_eda.py โ€” part 1
# Check for missing values
print("Missing values:\n", df.isnull().sum())
print("\nDuplicates:", df.duplicated().sum())

categorical_cols = df.select_dtypes(include=['object']).columns
numeric_cols = df.select_dtypes(include=[np.number]).columns
print(f"\nCategorical columns: {list(categorical_cols)}")
print(f"Numeric columns: {list(numeric_cols)}")

# Auto-detect the classification target column
target_col = None
for candidate in ['llm', 'model', 'label', 'class', 'category',
               'target', 'name', 'llm_name', 'model_name', 'type']:
    if candidate in df.columns.str.lower().tolist():
        target_col = df.columns[df.columns.str.lower() == candidate][0]
        break
if target_col is None:
    if len(categorical_cols) > 0:
        target_col = categorical_cols[0]
    else:
        target_col = numeric_cols[-1]
        df[target_col] = pd.qcut(df[target_col], q=2, labels=[0, 1])

print(f"Classification target column: '{target_col}'")
print(f"Number of classes: {df[target_col].nunique()}")
print(f"Class distribution:\n{df[target_col].value_counts()}")

# Plot target distribution
plt.figure(figsize=(10, 6))
sns.countplot(data=df, x=target_col, palette='viridis')
plt.title(f'Distribution of {target_col}')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
Auto-detection: The code tries to automatically find the classification target column by checking common names (llm, model, label, etc.). If none match, it falls back to the first categorical column. Always verify the detected column name in the output.

2.2 ยท Numeric distributions & correlation heatmap

step2_eda.py โ€” part 2
# Distributions of key numeric features
key_cols = list(numeric_cols[:4])
if len(key_cols) > 0:
    fig, axes = plt.subplots(1, len(key_cols), figsize=(5*len(key_cols), 5))
    colors = ['#4C72B0', '#55A868', '#C44E52', '#8172B2']
    for ax, col, color in zip(axes, key_cols, colors):
        sns.histplot(df[col], kde=True, color=color, ax=ax)
        ax.axvline(df[col].mean(), color='black', linestyle='--', label=f"Mean: {df[col].mean():.1f}")
        ax.set_title(f'Distribution of {col}')
        ax.legend()
    plt.tight_layout()
    plt.show()

# Correlation heatmap
if len(numeric_cols) > 1:
    plt.figure(figsize=(10, 8))
    sns.heatmap(df[numeric_cols].corr(), annot=True, cmap='coolwarm', fmt='.2f',
                square=True, linewidths=0.5)
    plt.title('Correlation Between Numeric Features')
    plt.show()

The class distribution countplot is the most important visualization for a classification project. It reveals whether you’re dealing with binary (2 classes) or multiclass (3+ classes) classification, and whether the classes are balanced. The correlation heatmap shows relationships between numeric features like character count and word count.

Step 03 / Preprocessing

Encode, scale โ€” without leakage.

Handle missing values, encode categorical features and the target, scale features.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Why Preprocessing Matters

Why do we need preprocessing? Machine learning models only understand numbers. If the dataset has text columns (like the LLM name or text prompts), we need to convert them to numbers using label encoding.

Handling missing values: We use dropna() to remove rows with missing data. If the dataset has many missing values, you might want to fill them with the mean or median instead.

Label encoding for categorical features: We use LabelEncoder to convert text columns to numbers. Example: ChatGPT=0, Claude=1, Gemini=2. This is essential for the target column because ML models require numeric labels.

What is train/test split? We divide data into 80% for training and 20% for testing. random_state=42 makes the split reproducible.

What is scaling? Standardization rescales every feature so mean=0, std=1. This matters because char_count might range from 10โ€“500 while word_count ranges from 5โ€“100 โ€” without scaling, features with larger ranges would dominate.

What is data leakage? When information from the test set accidentally influences training. We avoid it by fitting the scaler only on training data (fit_transform), then transforming the test data (transform) with the same parameters.

step3_preprocess.py
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split

data = df.copy()
data = data.dropna()

le = LabelEncoder()
# Encode all categorical columns
for col in categorical_cols:
    data[col] = le.fit_transform(data[col].astype(str))

# If target wasn't in categorical_cols but is object, encode it
if data[target_col].dtype == 'object':
    data[target_col] = le.fit_transform(data[target_col].astype(str))

# Define features (X) and target (y)
X = data.drop(columns=[target_col])
y = data[target_col]

# Train/test split (80/20)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42)

# Feature scaling (no leakage)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

num_classes = len(np.unique(y_train))
print(f"Number of classes for modeling: {num_classes}")
Important: The file_path from Step 1 and the target_col from Step 2 must be correct. Visit the Kaggle dataset page to verify the CSV filename, and check df.head() output to confirm the exact column name for the LLM label.
โžœ~/name-that-llm-mlpython step3_preprocess.py
Number of classes for modeling: X Train shape: (XX, XX) Test shape: (XX, XX)
โœ“Preprocessing complete โ€” ready for ML & DL classification training
๐Ÿ“– Code Walkthrough โ€” Step by Step
data = df.dropna()
Step 3.0: Copy the DataFrame and drop rows with missing values. Keeps only complete records.
le.fit_transform(data[col])
Step 3.1: Label encode all categorical (text) columns โ€” converts LLM names, text prompts, etc. to numbers.
X = data.drop(…)
Step 3.2: Separate features (X) from the target (y). We drop the target column from X.
train_test_split(X, y, …)
Step 3.3: Split 80% train, 20% test. random_state=42 = reproducible.
scaler.fit_transform(X_train)
Step 3.4: fit_transform on train (learns mean/std), transform on test (applies same parameters). No data leakage.
num_classes = len(np.unique(y_train))
Step 3.5: Count how many unique classes exist. This determines whether we use binary or multiclass metrics and DL output layers.
Step 04 / ML Classification

Five scikit-learn
classification models.

We train five models to predict the LLM label. The code automatically switches to weighted metrics for multiclass scenarios.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Machine Learning Basics

What is classification? Training a model on labeled examples so it can predict which category a new, unseen sample belongs to. Example: “This text was generated by ChatGPT (0), Claude (1), or Gemini (2).”

The five models, explained simply:

  • Logistic Regression: estimates the probability of belonging to each class. Simple, fast baseline.
  • Random Forest: builds 100 decision trees and votes on the class. “Wisdom of the crowd.”
  • Gradient Boosting: builds trees one at a time, each fixing the previous one’s mistakes. Often the strongest on tabular data.
  • SVM: finds the best boundary between classes. Good for small datasets, sensitive to scaling.
  • KNN: for a new sample, finds the 5 most similar samples and votes on the class. Simple but scaling-sensitive.

Classification metrics:

  • Accuracy: fraction of all predictions that were correct.
  • Precision: of all predicted “Class X,” how many actually were? (Weighted average across all classes for multiclass).
  • Recall: of all actual “Class X” samples, how many did we catch?
  • F1: harmonic mean of precision and recall. Best metric for imbalanced data.

4.1 ยท Train & Evaluate ML Models

step4_ml_classification.py
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix

# Use 'weighted' average for multiclass compatibility
avg_method = 'weighted' if num_classes > 2 else 'binary'

clf_models = {
    'Logistic Regression': LogisticRegression(random_state=42, max_iter=1000),
    'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
    'Gradient Boosting': GradientBoostingClassifier(n_estimators=100, random_state=42),
    'Support Vector Classifier': SVC(kernel='rbf', random_state=42, probability=True),
    'K-Nearest Neighbors': KNeighborsClassifier(n_neighbors=5),
}

clf_results = []
for name, model in clf_models.items():
    model.fit(X_train_scaled, y_train)
    y_pred = model.predict(X_test_scaled)
    clf_results.append({
        'Model': name,
        'Accuracy': round(accuracy_score(y_test, y_pred), 4),
        'Precision': round(precision_score(y_test, y_pred, average=avg_method, zero_division=0), 4),
        'Recall': round(recall_score(y_test, y_pred, average=avg_method, zero_division=0), 4),
        'F1 Score': round(f1_score(y_test, y_pred, average=avg_method, zero_division=0), 4),
    })

clf_results_df = pd.DataFrame(clf_results).sort_values('Accuracy', ascending=False)
print(clf_results_df.to_string(index=False))

# Confusion matrix for best model
best_clf = clf_models[clf_results_df.iloc[0]['Model']]
y_pred_best = best_clf.predict(X_test_scaled)
cm = confusion_matrix(y_test, y_pred_best)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title(f'Confusion Matrix โ€” {clf_results_df.iloc[0]["Model"]}')
plt.show()
โžœ===== Classification Results ===== Model Accuracy Precision Recall F1 Score Gradient Boosting 0.XXXX 0.XXXX 0.XXXX 0.XXXX Random Forest 0.XXXX 0.XXXX 0.XXXX 0.XXXX SVC 0.XXXX 0.XXXX 0.XXXX 0.XXXX KNN 0.XXXX 0.XXXX 0.XXXX 0.XXXX Logistic Regression 0.XXXX 0.XXXX 0.XXXX 0.XXXX
โœ“Run the code to see actual accuracy values
Step 05 / Deep Learning

One TensorFlow neural network
with dynamic output.

The architecture automatically adapts: sigmoid + binary_crossentropy for 2 classes, softmax + sparse_categorical_crossentropy for 3+ classes.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Deep Learning Basics

What is a neural network? A stack of layers, each containing “neurons” (math units). Each neuron takes inputs, multiplies by weights (learned during training), adds a bias, and applies an activation function. “Deep” = many layers.

The architecture, explained:

  • Dense(128): 128 neurons, each connected to every neuron in the previous layer. First layer takes our features.
  • Dense(64) โ†’ Dense(32): the “funnel” โ€” captures complex patterns then narrows.
  • ReLU: if input is negative, output 0; if positive, output as-is. Lets the network learn non-linear patterns.

Regularization โ€” preventing overfitting:

  • BatchNormalization: normalizes layer outputs during training. Stabilizes learning.
  • Dropout(0.3): randomly disables 30% of neurons each step. Forces the network to learn redundant representations.

Dynamic output layer (KEY for classification):

  • Binary (2 classes): Dense(1, activation='sigmoid') + binary_crossentropy. Outputs a single probability.
  • Multiclass (3+ classes): Dense(num_classes, activation='softmax') + sparse_categorical_crossentropy. Outputs a probability distribution across all classes.

5.1 ยท Build & Train the DL Classification Model

step5_dl_classification.py
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau

tf.random.set_seed(42)
np.random.seed(42)

def build_dl_classification_model(input_dim, num_classes):
    model = Sequential([
        Dense(128, activation='relu', input_shape=(input_dim,)),
        BatchNormalization(), Dropout(0.3),
        Dense(64, activation='relu'),
        BatchNormalization(), Dropout(0.2),
        Dense(32, activation='relu'),
        Dropout(0.1)
    ])
    
    if num_classes == 2:
        model.add(Dense(1, activation='sigmoid'))
        model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    else:
        model.add(Dense(num_classes, activation='softmax'))
        model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
    return model

dl_clf_model = build_dl_classification_model(X_train_scaled.shape[1], num_classes)

early_stop = EarlyStopping(monitor='val_loss', patience=20, restore_best_weights=True, verbose=1)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=10, min_lr=1e-6, verbose=1)

history = dl_clf_model.fit(
    X_train_scaled, y_train,
    validation_split=0.2,
    epochs=200,
    batch_size=32,
    callbacks=[early_stop, reduce_lr],
    verbose=1
)

# Evaluate DL
dl_pred_prob = dl_clf_model.predict(X_test_scaled)
if num_classes == 2:
    dl_pred = (dl_pred_prob >= 0.5).astype(int).flatten()
else:
    dl_pred = np.argmax(dl_pred_prob, axis=1)

dl_acc = accuracy_score(y_test, dl_pred)
dl_f1 = f1_score(y_test, dl_pred, average=avg_method, zero_division=0)
print(f"\nDL Classification - Accuracy: {dl_acc:.4f}, F1 Score: {dl_f1:.4f}")
โžœ~/name-that-llm-mlpython step5_dl.py
Epoch XX: val_loss did not improve โ€” EarlyStopping triggeredDL Classification – Accuracy: 0.XXXX, F1 Score: 0.XXXX
โœ“Neural network trained successfully โ€” dynamic output layer adapted to num_classes
Step 06 / ML vs DL Comparison

The final leaderboard.

Concatenate the ML results with the DL metrics and sort.

๐Ÿง‘โ€๐Ÿซ Beginner’s Guide โ€” Reading the Results

How to read the results table:

  • Accuracy: fraction of all predictions that were correct.
  • Precision/Recall/F1: for multiclass, these are weighted averages across all classes โ€” meaning they account for class imbalance by weighting each class by its frequency.

The pattern you’ll see: On this text classification dataset, Gradient Boosting and Random Forest typically match or beat the neural network. For structured/tabular data (even text-derived features), tree-based ensembles are usually the better engineering choice.

Key lesson: If the dataset is imbalanced (e.g., 90% ChatGPT, 5% Claude, 5% Gemini), accuracy can be misleading. Always check the F1 Score โ€” it’s the most reliable metric for imbalanced classification.

step6_comparison.py
# Classification comparison
combined_clf = pd.concat([clf_results_df, pd.DataFrame([{
    'Model': 'Deep Learning (Neural Network)',
    'Accuracy': round(dl_acc, 4),
    'Precision': round(precision_score(y_test, dl_pred, average=avg_method, zero_division=0), 4),
    'Recall': round(recall_score(y_test, dl_pred, average=avg_method, zero_division=0), 4),
    'F1 Score': round(dl_f1, 4)
}])], ignore_index=True).sort_values('Accuracy', ascending=False)

print(combined_clf.to_string(index=False))
โžœ============================================================ CLASSIFICATION: Predict LLM Name/Label ============================================================ Model Accuracy Precision Recall F1 Score Gradient Boosting 0.XXXX 0.XXXX 0.XXXX 0.XXXX Random Forest 0.XXXX 0.XXXX 0.XXXX 0.XXXX Deep Learning (Neural Net) 0.XXXX 0.XXXX 0.XXXX 0.XXXX Logistic Regression 0.XXXX 0.XXXX 0.XXXX 0.XXXX SVC 0.XXXX 0.XXXX 0.XXXX 0.XXXX KNN 0.XXXX 0.XXXX 0.XXXX 0.XXXX
โœ“Run the code to see actual values
The verdict: On this text classification dataset, traditional tree-based ensembles (Gradient Boosting, Random Forest) typically match or beat the neural network. For structured features, deep learning rarely pulls ahead.
07 / Key Insights

What the project
actually tells us.

Six findings from running the full classification pipeline on the Name That LLM dataset.

// text features โ†” LLM identity ยท weighted F1 for multiclass
01

Text features reveal LLM identity

Features like character count, word count, and sentence structure can distinguish between LLMs. Each model has subtle stylistic signatures.

02

Class imbalance matters

If the dataset has more ChatGPT samples than Claude or Gemini, the model will be biased toward ChatGPT. The weighted F1 score accounts for this imbalance.

03

Confusion matrix shows which LLMs are confused

The confusion matrix reveals which pairs of LLMs are most often mistaken for each other. Models with similar writing styles will have higher confusion rates.

04

Tree ensembles match or beat DL

Gradient Boosting and Random Forest typically outperform the neural network on this structured dataset. Deep learning isn’t always the answer โ€” for tabular features, tree-based ensembles win.

05

Dynamic architecture handles binary & multiclass

The code automatically switches between sigmoid (binary) and softmax (multiclass) output layers. This makes the project reusable for any classification dataset.

06

The real value is feature importance

For researchers, the most useful output isn’t the prediction โ€” it’s which features distinguish LLMs. Random Forest’s feature importance can reveal whether word count, punctuation usage, or sentence length is the strongest discriminator.

09 / FAQ

Frequently Asked Questions

What is the Name That LLM dataset? +

The Name That LLM dataset on Kaggle contains data about text prompts or names, designed to classify which Large Language Model (LLM) generated the text or belongs to the name.

Can machine learning predict which LLM generated text? +

Yes. By training a model on text features, character counts, and categorical metadata, ML learns the relationship between these features and the specific LLM, enabling classification for new text.

Is deep learning better than ML for text classification? +

Not necessarily. On this structured dataset, traditional ML models like Gradient Boosting typically match or outperform a 4-layer neural network. Deep learning tends to pull ahead on very large datasets or raw unstructured text inputs.

How do you handle multiclass classification? +

For multiclass classification, the code automatically switches to ‘weighted’ averages for precision, recall, and F1 score. The deep learning model uses a softmax output layer with sparse categorical crossentropy loss instead of sigmoid.

Run the project
yourself.

Grab the Name That LLM dataset from Kaggle, install the stack with one pip command, and run every cell end-to-end. Or click “Copy Full Project Code” at the top of this page.

Pure classification project5 ML models1 DL networkMulticlass support
Scroll to Top