#Supplementary information file #Author: Maija Ozola-Schade, Technische Universität Ilmenau, #Department of Economic Sciences and Media, Germany #maija.ozola@tu-ilmenau.de #Article: A longitudinal analysis of traditional news media coverage of #immigration in Western Europe: Issue attention cycles and attribute clusters #Journal: Studies in Communication Sciences (SComS) #Vol./Issue 26/02 #DOI: https://doi.org/ 10.24434/j.scoms.2026.02.8700 #Note: The authors of the article are responsible for the layout of the appendix. #Document A1. Python script for binary classification model import pandas as pd import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, Dataset from transformers import RobertaTokenizer, RobertaForSequenceClassification from sklearn.model_selection import train_test_split import os # Check for GPU device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print("Using device:", device) # Load dataset from google.colab import drive drive.mount('/content/gdrive') %cd /content/gdrive/MyDrive/Text classification all_data = pd.read_csv('All_data_filtered.csv', delimiter=";", encoding="utf-8", engine='python', on_bad_lines='skip') # Map labels all_data['label'] = all_data['Code_nr_short'].apply(lambda x: 1 if x == 1 else 2) # Balance class 2 (randomly sample 200 cases from each of 2,3,4,5) class_2_data = all_data[all_data['Code_nr_short'].isin([2,3,4,5])] class_2_sampled = class_2_data.groupby('Code_nr_short').apply(lambda x: x.sample(n=200, random_state=42)).reset_index(drop=True) # Combine with all class 1 cases balanced_data = pd.concat([all_data[all_data['Code_nr_short'] == 1], class_2_sampled]) # Define features and labels X = balanced_data['text'].tolist() y = balanced_data['label'].tolist() # Split dataset X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y) X_dev, X_test, y_dev, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp) print(f"Training size: {len(X_train)}") print(f"Development (Validation) size: {len(X_dev)}") print(f"Test size: {len(X_test)}") # Tokenization TOKENIZER = RobertaTokenizer.from_pretrained("roberta-base") class TextDataset(Dataset): def __init__(self, texts, labels, tokenizer, max_length=512): self.texts = texts self.labels = labels self.tokenizer = tokenizer self.max_length = max_length def __len__(self): return len(self.texts) def __getitem__(self, idx): encoding = self.tokenizer( self.texts[idx], padding='max_length', truncation=True, max_length=self.max_length, return_tensors='pt' ) return { 'input_ids': encoding['input_ids'].squeeze(0), 'attention_mask': encoding['attention_mask'].squeeze(0), 'labels': torch.tensor(self.labels[idx] - 1, dtype=torch.long) } train_dataset = TextDataset(X_train, y_train, TOKENIZER) dev_dataset = TextDataset(X_dev, y_dev, TOKENIZER) test_dataset = TextDataset(X_test, y_test, TOKENIZER) train_loader = DataLoader(train_dataset, batch_size=20, shuffle=True) dev_loader = DataLoader(dev_dataset, batch_size=20, shuffle=False) test_loader = DataLoader(test_dataset, batch_size=20, shuffle=False) # Define model class BinaryRoBERTa(nn.Module): def __init__(self): super(BinaryRoBERTa, self).__init__() self.model = RobertaForSequenceClassification.from_pretrained("roberta-base", num_labels=2) def forward(self, input_ids, attention_mask): return self.model(input_ids=input_ids, attention_mask=attention_mask).logits model = BinaryRoBERTa().to(device) # Loss and optimizer criterion = nn.CrossEntropyLoss() optimizer = optim.AdamW(model.parameters(), lr=5e-6, eps=1e-8, weight_decay=0.02) # Training loop EPOCHS = 10 best_val_loss = float("inf") for epoch in range(EPOCHS): model.train() total_loss = 0 for batch in train_loader: input_ids, attention_mask, labels = batch['input_ids'].to(device), batch['attention_mask'].to(device), batch['labels'].to(device) optimizer.zero_grad() outputs = model(input_ids, attention_mask=attention_mask) loss = criterion(outputs, labels) loss.backward() optimizer.step() total_loss += loss.item() avg_train_loss = total_loss / len(train_loader) print(f"Epoch {epoch+1}: Train Loss = {avg_train_loss:.4f}") from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix import seaborn as sns import matplotlib.pyplot as plt def evaluate(model, test_loader, model_name): model.eval() all_preds, all_labels = [], [] with torch.no_grad(): for batch in test_loader: input_ids, attention_mask, labels = batch['input_ids'].to(device), batch['attention_mask'].to(device), batch['labels'].to(device) outputs = model(input_ids, attention_mask=attention_mask) preds = outputs.argmax(dim=1).cpu().tolist() all_preds.extend(preds) all_labels.extend(labels.cpu().tolist()) acc = accuracy_score(all_labels, all_preds) precision = precision_score(all_labels, all_preds) recall = recall_score(all_labels, all_preds) f1 = f1_score(all_labels, all_preds) print(f"Evaluation for model: {model_name}") print("Overall Statistics:") print(f"Accuracy: {acc:.4f}") print(f"Precision (Macro): {precision_score(all_labels, all_preds, average='macro'):.4f}") print(f"Recall (Macro): {recall_score(all_labels, all_preds, average='macro'):.4f}") print(f"F1 Score (Macro): {f1_score(all_labels, all_preds, average='macro'):.4f}") print("Per-Class Statistics:") per_class_precision = precision_score(all_labels, all_preds, average=None) per_class_recall = recall_score(all_labels, all_preds, average=None) per_class_f1 = f1_score(all_labels, all_preds, average=None) for i, class_label in enumerate(["Class 1", "Class 2"]): print(f"{class_label} - Precision: {per_class_precision[i]:.4f}, Recall: {per_class_recall[i]:.4f}, F1: {per_class_f1[i]:.4f}") print(f"Precision: {precision:.4f}") print(f"Recall: {recall:.4f}") print(f"F1 Score: {f1:.4f}") cm = confusion_matrix(all_labels, all_preds) plt.figure(figsize=(6, 6)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=["Class 1", "Class 2"], yticklabels=["Class 1", "Class 2"]) plt.xlabel("Predicted") plt.ylabel("Actual") plt.title("Confusion Matrix") plt.savefig("confusion_matrix.png") plt.show() evaluate(model, test_loader, "binary_roberta_model.pth") # Save final model torch.save(model.state_dict(), "binary_roberta_model.pth") print("Model training complete and saved!")