chatgpt-sentiment-loop-all

textmining
nlp
transformer
chatgpt
sentiment
Published

December 20, 2023

Aufgabe

Fragen Sie ChatGPT via API zum Sentiment der Texte aus dem Germeval-2018-Datensatz (Test).

Hinweise:











Lösung

Achtung

OpenAI hat eine neue API (Stand: 2023-11-23), V1.3.5. Der Code der alten API bricht. 💔 \(\square\)

Setup

Die richtige venv nutzen:

library(reticulate)
#virtualenv_create("chatgpt")
use_virtualenv("chatgpt")

Check zu Python:

reticulate::py_config()

Ggf. noch Module installieren:

#reticulate::py_install("pandas")
#py_install("tiktoken")
#py_install("datar")
#py_install("scikit-learn")

R-Pakete und Python-Module

library(tidyverse)
library(tidymodels)
library(plotly)

Module importieren:

from openai import OpenAI
import pandas as pd
import numpy as np
import time
from datetime import datetime
#from sklearn.metrics import classification_report
from sklearn.metrics import accuracy_score

Versionen der importierten Module:

pd.__version__
```{zsh openai-version-zsh}
pip list | grep openai
```

Wir brauchen >= 1.35.

Der Operator | ist die “Pfeife” der Kommandozeile, also sozusagen der “UND-DANN-Befehl”.

Daten

Daten importieren:

csv_file_path_test = 'https://github.com/sebastiansauer/pradadata/raw/master/data-raw/germeval_test.csv'

germeval_test = pd.read_csv(csv_file_path_test)

Die ersten paar Texte herausziehen:

start_pos = 0
end_pos = 3531
tweets = germeval_test["text"].iloc[start_pos:(end_pos+1)].tolist()

Prompt

Prompt definieren:

prompt_stem  = "Als KI mit Exertise in natürlicher Sprache und Emotionserkennung ist es Ihre Aufgabe, das Sentiment des folgenden Textes einzuschätzen. Bitte antworten Sie nur mit einem einzigen Wort, entweder 'positiv', 'neutral' oder 'negativ'. Ihre Antwort soll Ihre Insgesamt-Einschätzung zum Sentiments des Textes zusammenfassen. Nach dem Doppelpunkt folgt der Text, dessen Sentiment Sie einschätzen sollen: "

Gute Prompts können helfen, gute Antworten vom Modell zu erhalten.

Mit “List Comprehension” können wir die Tweets jeweils mit dem Prompt verknüpfen:

prompts = [prompt_stem + tweet for tweet in tweets]
prompts[0]

Check: Wie viele Elemente hat die Liste prompts?

len(prompts)

Laut OpenAI kostet 1k Token für das Modell gpt-3.5-turbo-1106 $0.001.

Authentifizieren

Anmelden bei OpenAI:

client = OpenAI()
Note

Dieses Anmeldeverfahren setzt voraus, dass in .Renviron die Variable OPENAI_API_KEY hinterlegt ist. \(\square\)

Anfrage an die API, in eine Funktion gepackt:

def get_completion(prompt, client_instance, model="gpt-3.5-turbo"):
  messages = [{"role": "user", "content": prompt}]
  response = client_instance.chat.completions.create(
    model=model,
    messages=messages,
    max_tokens=50,
    temperature=0,
  )
  return response.choices[0].message.content

API anfragen

Und jetzt als Schleife. Ergebnisliste anlegen, am Anfang noch leer:

predicted_values = []
start_time = time.time()

for prompt in prompts:
  result = get_completion(prompt, client) 
  predicted_values.append(result)

end_time = time.time()
end_time - start_time

Voilà:

print(predicted_values[:5])

Als CSV speichern

id_seq = [i for i in range(start_pos, end_pos + 1)]
predicted_values_df = pd.DataFrame(id_seq, columns = ["id"])
predicted_values_df["pred"] = predicted_values

now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
csv_output_name = "germeval_test_preds_at_" + now
predicted_values_df.to_csv(csv_output_name)

Oder Vorhersagen aus CSV importieren

preds_path = 'https://raw.githubusercontent.com/sebastiansauer/Datenwerk2/main/posts/chatgpt-sentiment-loop-all/germeval_test_preds_at_2023-12-20%2014%3A06%3A00'

preds = pd.read_csv(preds_path)

preds.head()

Man kann eine Python-Variable an R übergeben:

preds_r <- py$preds

Vorhersagen (Predictions) betrachten

Zählen wir mal kurz aus:

preds_r |> 
  count(pred) |> 
  slice(3:5)  # zwei komische, kaputte Zeilen, weg damit

Oder in Python:

preds["pred"].value_counts()

Puh, das ist ein bisschen was kaput gegangen.

Predictions reparieren

allowed_preds = ["positiv", "neutral", "negativ"]
preds.loc[~preds["pred"].isin(allowed_preds), "pred"] = np.nan

Check:

preds["pred"].value_counts()

Passt!

Scoring vorbereiten

Was waren noch mal die Variablen unser Tabelle?

germeval_test.columns

Die ersten paar Werte:

germeval_test.head()

Rescore im Test-Set:

df = germeval_test
df["c1"] = df["c1"].replace({"OFFENSE": "negativ"})

df["c1"].value_counts()

Rescore in den Vorhersagen

preds["pred"] = preds["pred"].replace({"neutral": "OTHER", "positiv": "OTHER"})

preds["pred"].value_counts()
preds_list = preds["pred"].tolist()

Hier ist die Liste der wahren Werte:

y = df["c1"].values.tolist()

Scoring

accuracy = accuracy_score(y, preds_list)
print("Accuracy:", accuracy)

Oder mit tidymodels; zuerst aufbereiten:

y_truth = as.factor(py$y)
y_pred = py$preds_list 

# replace NAN with NA and convert to factor:
y_pred = as.character(y_pred) 
y_pred[is.nan(y_pred)] <- NA
y_pred[!y_pred %in% c("negativ", "OTHER")] <- NA
y_pred <- as.factor(y_pred)

table(y_pred)
accuracy_vec(truth = y_truth,
             estimate = y_pred)

Fun

fig <- plot_ly(
  domain = list(x = c(0, 1), y = c(0, 1)),
  value = 74,
  title = list(text = "Accuracy"),
  type = "indicator",
  mode = "gauge+number") 
fig <- fig %>%
  layout(margin = list(l=20,r=30))

fig