Verletzende Sprache in der deutschsprachigen Twittersphäre


Dies ist der erste Teil rund um die Einführung von Hexis API, der zeigen soll wie – nicht handverlesene Beispiele, sondern – echte Daten durch die Linse des Klassifikationssystems aussehen. Wir werden ein paar Ausschnitte von Python-Code verwenden, um die Daten zu analysieren und unsere Ergebnisse zu veranschaulichen.

Über die Daten

Die Grundlage für diese Untersuchung ist eine Stichprobe von Twitter-Nachrichten oder Tweets, die während eines Tages Anfang Dezember gesammelt wurden. Die Stichprobe besteht aus tausend zufällig ausgewählten Tweets für jeden der 93 Ballungsräume mit mehr als 100.000 Einwohnern in Deutschland, Österreich und der Schweiz.

Laden der Daten

Wir gehen davon aus, dass data.csv das folgende Format hat:

tweet near latitude longitude
...
"Über Qualitätsjournalisten, Arsch und Grundeis Folge 2 URL …" Herne 51.5380394 7.219985
"So etwas lesen zu müssen, macht mich unendlich traurig. Ist #Deutschland wirklich wieder so weit dunkle Kapitel zu wiederholen?" Herne 51.5380394 7.219985
"Edi Glieder ein Schalke-Flop? Das ist eine bodenlose Frechheit!!!!!!!! URL …" Herne 51.5380394 7.219985
"Kommt in deine KGB Akte, du Loser! Und Milli bleibt Genosse, wie $adam Hü$$€¥N oder MATERNUS PILS!!!" Herne 51.5380394 7.219985
"Guten Morgen verehrte TL ☕️" Herne 51.5380394 7.219985
"Sicher. Aber bis so etwas möglich ist ... Hilfe, Aufarbeitung ist ein komplexer, vielschichtiger und langwieriger Prozess, der meist Psychotherapie benötigt. Oft dauert es Jahre. Kurze Empfehlungen gibt es da nicht sondern können irritieren, weil es auf das konkrete Kind ankommt" Herne 51.5380394 7.219985
"USER sind sie schon daaaa. Schon alles fertig Ganz nervös hier.😁😁😂🤪" Herne 51.5380394 7.219985
...


Um diese Daten verwenden zu können, wollen wir sie zunächst in eine tabellen-artige Datenstruktur laden, die als dataframe bezeichnet wird.

import pandas as pd

df = pd.read_csv('data.csv', header=0, engine='python')

Klassifikation

Jetzt, da wir unsere Daten vorliegen haben, ist es an der Zeit, mit der Klassifizierung zu beginnen. Dies ist ein unkomplizierter Prozess: Wir werden den Hexis API-Endpunkt (Dokumentation) verwenden, der ein Stück JSON als Input erwartet. Die Eingabe sollte ein Element namens Text enthalten, dessen Wert der Textinhalt des Tweets ist. Der Endpunkt antwortet wiederum mit einer Aggressivitäts-Punktzahl für jeden Text. Sie können eine Punktzahl für bis zu 120 Wörter lange Textstücke erhalten. Natürlich macht es auch Sinn, längere Texte zu analysieren, es ist nur darauf zu achten, dass diese geteilt werden müssen (oder von der API automatisch geteilt werden).

Hinweis: Wenn Sie noch keinen API-Schlüssel haben, gehen Sie zur Ihrem Konto und erstellen Sie kostenlos einen.

import requests
from time import sleep

URL = 'https://api.hexis.ai/mod-1/de'
API_KEY = 'your_api_key_here'

for i, row in df.iterrows():
    # escape characters for JSON compliance
    text = row['tweet'].replace('"','\\"').replace('\n', ' ')

    # send to API
    header = {'Authorization': 'Bearer ' + API_KEY}
    data = {'text': text}
    response = requests.post(URL, json=data, headers=header)

    # process response
    score = response.json()['scores'][0]
    df.loc[i, 'score'] = score

    sleep(0.1)

Das dataframe df sollte nun aussehen wie folgt:

tweet near latitude longitude score
...
"Über Qualitätsjournalisten, Arsch und Grundeis Folge 2 URL …" Herne 51.5380394 7.219985 0.9908769726753236
"So etwas lesen zu müssen, macht mich unendlich traurig. Ist #Deutschland wirklich wieder so weit dunkle Kapitel zu wiederholen?" Herne 51.5380394 7.219985 0.018021326512098312
"Edi Glieder ein Schalke-Flop? Das ist eine bodenlose Frechheit!!!!!!!! URL …" Herne 51.5380394 7.219985 0.9930542111396791
"Kommt in deine KGB Akte, du Loser! Und Milli bleibt Genosse, wie $adam Hü$$€¥N oder MATERNUS PILS!!!" Herne 51.5380394 7.219985 0.9801527857780457
"Guten Morgen verehrte TL ☕️" Herne 51.5380394 7.219985 0.0029989404138177638
"Sicher. Aber bis so etwas möglich ist ... Hilfe, Aufarbeitung ist ein komplexer, vielschichtiger und langwieriger Prozess, der meist Psychotherapie benötigt. Oft dauert es Jahre. Kurze Empfehlungen gibt es da nicht sondern können irritieren, weil es auf das konkrete Kind ankommt" Herne 51.5380394 7.219985 0.30031758546829224
"USER sind sie schon daaaa. Schon alles fertig Ganz nervös hier.😁😁😂🤪" Herne 51.5380394 7.219985 0.03731132298707962
...

Visualisierung

Next we will employ the visualization framework Altair/Vega Lite alongside freely available TopoJSON files to produce a geographical mapping of our data.

import altair as alt

TOPOJSON_URL = 'https://raw.githubusercontent.com/deldersveld/topojson/master/countries/germany/dach.json'
map_data = df.groupby(['near']).mean()
topo = alt.topo_feature(TOPOJSON_URL, feature='layer')

background = alt.Chart(topo).mark_geoshape(
    fill='lightgray',
    fillOpacity=1.0,
    stroke='white',
    strokeWidth=1
).properties(
    width=500,
    height=500
).project('mercator')

points = alt.Chart(map_data).mark_circle().encode(
    longitude='longitude:Q',
    latitude='latitude:Q',
    size=alt.Size('score:Q', title='score (mean)'),
    color='score:Q',
    tooltip=['near:N','score:Q']
).properties(title='Aggression in the German-speaking Twittersphere')

plot = background + points
plot.save('map.html')

Das Ergebnis ist eine ansehnliche interaktive Karte im HTML-Format.

Es ist interessant, die Verteilung der höheren Durchschnittswerte über die historisch eher industriell geprägten Gebiete zu sehen. Dennoch geben uns die Durchschnittswerte nicht das vollständige Bild. Lassen Sie uns unsere Daten verwenden, um ein Balkendiagramm zu erstellen, in dem jedes Ballungsgebiet und seine einzelnen Werte, aufgeteilt in Klassen zu je 10%, dargestellt werden.

df.columns = ['tweet', 'Area', 'latitude', 'longitude', 'Score']  # rename columns for plotting

plot = alt.Chart(df).mark_bar().encode(
    x='count(Score)',
    y=alt.Y(
        'Area',
        sort=alt.EncodingSortField(
            field='Score',
            op='sum',
            order='descending')
        ), color=alt.Color(
            'Score:Q',
            bin=alt.Bin(maxbins=10))
).properties(title='Scores by metropolitan area')

plot.save('barchart.html')

Daraus ergibt sich ein ziemlich großer, aber recht informativer Blick auf unsere Daten, der es ermöglicht, einen allumfassenden Gradienten der Aggressivität in unserem Datensatz zu erkennen. Ungefähr 4% aller Tweets sind problematisch (entsprechend dem oberen 90- bis 100%-Bereich der Scores) und sollten von menschlichen Moderatoren genau unter die Lupe genommen werden, um jegliche Haftung seitens der Plattform zu vermeiden.

Abschließend

Wir hoffen, dass Ihnen diese kleine und schnell umgesetzte Untersuchung der Schattenseiten der deutschsprachigen Twittersphäre gefallen hat. Wie bei jedem anderen empirischen Ansatz, der darauf abzielt, valide Schlussfolgerungen zu einem bestimmten Thema zu ziehen, ist die Datenerhebung und -kuration nach wie vor der schwierigste Teil. Wenn Sie jedoch bereits über die Daten verfügen, stehen die Chancen gut, dass Sie die Hilfe einer leistungsfähigen Maschine nutzen können, damit Sie als Experte nur einen Bruchteil aller Daten betrachten müssen. Bei einem gut abgestimmten System läuft das nur auf die Grenzfälle hinaus – das sollte unserer Meinung nach im Handumdrehen möglich sein. Deshalb haben wir Hexis API entwickelt.

Bleiben Sie dran für unsere nächste Untersuchung.