3.4. 🚀 Auswahl des Forschungskorpus#

Diese Fallstudie untersucht, wie deutschsprachige literarische Texte des 19. Jahrhunderts die abnehmende LuftqualitÀt reflektieren und diskursivieren.
Ein zentraler Schritt besteht darin, ein geeignetes Forschungskorpus auszuwÀhlen, das den historischen Zeitraum und die thematische Breite unserer Forschungsfrage abdeckt.

Im Unterschied zur vorherigen Fallstudie, in der das Korpus selbst aufgebaut wurde, liegt der Fokus hier auf der reflektierten Auswahl eines bestehenden Korpus.

Lernziel

Nach diesem Abschnitt können Sie die Kriterien fĂŒr die Auswahl eines geeigneten Forschungskorpus benennen, bestehende Korpora vergleichen und den Auswahlprozess datenbasiert begrĂŒnden.


3.4.1. Vom Aufbau zur Auswahl#

WĂ€hrend in der Fallstudie 1 ein eigenes Zeitungskorpus zur Spanischen Grippe 1918/19 aufgebaut wurde, greifen wir in dieser Fallstudie auf bereits existierende digitale Korpora deutschsprachiger Prosa zurĂŒck. Wir stehen also nicht vor der Aufgabe, Texte selbst zu digitalisieren, sondern mĂŒssen reflektiert entscheiden, welches existierende Korpus fĂŒr unsere Forschungsfrage geeignet ist.

Die im Kapitel „Korpora als Forschungsobjekte“ beschriebenen Strategien – VollstĂ€ndigkeit, ReprĂ€sentativitĂ€t, Balance und Opportunismus – bilden dabei unseren Bewertungsrahmen (Schöch, 2017).


3.4.2. Vorhandene Korpora deutschsprachiger Prosa#

Im Folgenden werden drei frei verfĂŒgbare Korpora vorgestellt, die sich fĂŒr literaturwissenschaftliche Analysen deutscher Prosa eignen. Konkret wurden fĂŒr diese Fallstudie das d-Prose-Korpus, das Corpus of German-Language Fiction sowie das German ELTeC-Korpus herangezogen.

Korpus

Beschreibung

Zeitraum

Format

Auswahlstrategie

StÀrken

SchwÀchen

d-Prose 1870–1920 (Zenodo)

ca. 150 Werke, TEI/XML, kuratiert

1870–1920

TEI/XML

balanciert

gute Metadaten, literaturwissenschaftlich gepflegt

begrenzter Zeitraum

Corpus of German-Language Fiction (Figshare)

ca. 1 200 Romane in Plain Text mit Metadaten

1750–1950

TXT

opportunistisch / balanciert

großer Umfang, gute zeitliche Abdeckung

uneinheitliche Metadaten, OCR-Fehler

ELTeC-German (Zenodo)

ca. 100 Werke, nach ELTeC-Samplingprotokoll

1840–1920

TEI/XML

reprÀsentativ

methodisch solide, Gender-Balance

relativ klein, LĂŒcken vor 1840

Hinweis

Bereits in dieser Übersicht zeigt sich, dass kein Korpus „perfekt“ ist. Die Entscheidung fĂŒr ein Korpus hĂ€ngt immer vom Zusammenspiel zwischen Forschungsfrage, zeitlicher Abdeckung, DatenqualitĂ€t und praktischer ZugĂ€nglichkeit ab.


3.4.3. Explorative Analyse der Metadaten#

Um die Eignung der Korpora genauer zu prĂŒfen, untersuchen wir zunĂ€chst ihre Metadaten. Ziel ist es, ein erstes GefĂŒhl fĂŒr die zeitliche Verteilung, VollstĂ€ndigkeit und Struktur der Daten zu gewinnen. Um dies zu erreichen, mĂŒssen wir mithilfe von Code einige Metadaten von Korpora analysieren. Dieser Code wird unten als ausfĂŒhrbares Notebook prĂ€sentiert.

Hinweise zur AusfĂŒhrung des Notebooks#

Dieses Notebook kann auf unterschiedlichen Levels erarbeitet werden (siehe Abschnitt “Technische Voraussetzungen”):

  1. Book-Only Mode

  2. Cloud Mode: DafĂŒr auf 🚀 klicken und z.B. in Colab ausfĂŒhren.

  3. Local Mode: DafĂŒr auf Herunterladen ↓ klicken und “.ipynb” wĂ€hlen.

Übersicht#

Im Folgenden wird die Auswahl eines geeigneten Forschungskorpus auf Basis von Metadaten vorgenommen. Ziel dieses Schrittes ist es, vor der eigentlichen Textanalyse zu prĂŒfen, welche Korpora fĂŒr die vorliegende Forschungsfrage geeignet sind und welche EinschrĂ€nkungen sie mit sich bringen.

Im Fokus stehen dabei zeitliche Abdeckung, Verteilung der Texte und strukturelle Eigenschaften verschiedener Korpora deutschsprachiger Prosa. Die Analyse dient nicht der inhaltlichen Interpretation einzelner Texte, sondern der methodisch reflektierten Korpusentscheidung als Grundlage fĂŒr die nachfolgenden Analyseschritte.

Dazu werden die folgenden Schritte durchgefĂŒhrt:

  1. Vorstellung und Einordnung mehrerer verfĂŒgbarer Korpora

  2. Einlesen und Aufbereitung der zugehörigen Metadaten

  3. Explorative Analyse der zeitlichen Verteilung der Texte

  4. Vergleich der Korpora hinsichtlich Abdeckung und Balance

  5. BegrĂŒndete Auswahl eines Korpus fĂŒr die weitere Analyse

Hide code cell content

import pandas as pd
import plotly.express as px
import plotly.io as pio
pio.renderers.default = "notebook"
from itables import show

3.4.4. Option 1. ELTeC-DEU corpus#

Einlesen der Korpusmetadaten in Python#

meta = pd.read_csv("https://zenodo.org/records/4662482/files/metadata.csv")
show(meta)
Loading ITables v2.6.1 from the internet... (need help?)

Analyse der zeitlichen Verteilung des Korpus#

Pro Jahr

Hide code cell content

# Anzahl der Texte pro Jahr

def summarize_texts_per_year(df, year_column):
    """Return per-yearcounts and summary stats for the given year column."""
    bins = df[year_column].dropna()
    if bins.empty:
        raise ValueError(f"No year values found in column '{year_column}'.")
    bins = bins.astype(int)
    counts = bins.value_counts().sort_index()
    full_index = pd.RangeIndex(counts.index.min(), counts.index.max() + 1)
    counts = counts.reindex(full_index, fill_value=0)
    stats = counts.agg(['mean', 'max', 'min']).rename({'mean': 'avg_per_year'})
    return counts, stats

year_counts, year_stats = summarize_texts_per_year(meta, 'year')

print("Textanzahl der Texte im ELTEC-DEU pro Jahr:")
print(year_stats)
Textanzahl der Texte im ELTEC-DEU pro Jahr:
avg_per_year    1.234568
max             5.000000
min             0.000000
Name: count, dtype: float64

Hide code cell content

fig_year = px.bar(
    x=year_counts.index,
    y=year_counts.values,
    labels={
        "x": "Jahr",
        "y": "Anzahl Texte"
    },
    title="Zeitliche Verteilung der Texte im ELTEC-DEU pro Jahr"
)

fig_year.update_layout(
    height=350,
    margin=dict(l=40, r=40, t=60, b=40),
    xaxis=dict(
        tickmode="linear",
        tickformat="d"  # ensure clean integer years
    ),
)
fig_year.show()

Pro Jahrzehnt

Hide code cell content

# Anzahl der Texte pro Jahrzehnt
def summarize_texts_per_decade(df, decade_column):
    """Return per-yearcounts and summary stats for the given year column."""
    bins = df[decade_column].dropna()
    if bins.empty:
        raise ValueError(f"No year values found in column '{decade_column}'.")
    bins = bins.astype(int)
    counts = bins.value_counts().sort_index()
    stats = counts.agg(['mean', 'max', 'min']).rename({'mean': 'avg_per_year'})
    return counts, stats

meta['decade'] = (meta['year'] // 10) * 10
decade_counts, decade_stats = summarize_texts_per_decade(meta, 'decade')

print("Textanzahl der Texte im ELTEC-DEU pro Jahrzehnt:")
print(decade_stats)
Textanzahl der Texte im ELTEC-DEU pro Jahrzehnt:
avg_per_year    11.111111
max             16.000000
min              1.000000
Name: count, dtype: float64

Hide code cell content

# Visualisierung der Dekadenverteilung (Textanzahl pro Dekade)
fig_decade = px.bar(
    x=decade_counts.index.astype(str),
    y=decade_counts.values,
    labels={
        "x": "Jahrzehnt",
        "y": "Anzahl Texte"
    },
    title="Zeitliche Verteilung der Texte im ELTEC-DEU pro Jahrzehnt"
)

fig_decade.update_layout(
    height=350,
    margin=dict(l=40, r=40, t=60, b=40),
)
fig_decade.show()

3.4.5. Option 2. d-Prose corpus#

Einlesen der Korpusmetadaten in Python#

## code to analyse the metadata of the d-Prose corpus

meta_d_prose = pd.read_csv("https://zenodo.org/records/5015008/files/d-prose_V2_norm_year.csv", 
                           sep=';')
show(meta_d_prose)
Loading ITables v2.6.1 from the internet... (need help?)

Analyse der zeitlichen Verteilung des Korpus#

Pro Jahr (d-Prose)

Hide code cell content

year_counts, year_stats = summarize_texts_per_year(meta_d_prose, 'norm_year')

print("Textanzahl der Texte im d-Prose pro Jahr:")
print(year_stats)
Textanzahl der Texte im d-Prose pro Jahr:
avg_per_year     49.235294
max             136.000000
min               6.000000
Name: count, dtype: float64

Man sieht, dass d-Prose ein wesentlich “dichteres” Korpus ist 


Hide code cell content

# Visualisierung der Jahresverteilung (Textanzahl pro Jahr)

fig_year = px.bar(
    x=year_counts.index,
    y=year_counts.values,
    labels={
        "x": "Jahr",
        "y": "Anzahl Texte"
    },
    title="Zeitliche Verteilung der Texte im d-Prose pro Jahr"
)

fig_year.update_layout(
    height=350,
    margin=dict(l=40, r=40, t=60, b=40),
    xaxis=dict(
        tickmode="linear",
        tickformat="d"  # ensure clean integer years
    ),
)
fig_year.show()

Hide code cell content

# Anzahl der Texte pro Jahrzehnt

meta_d_prose['decade'] = (meta_d_prose['norm_year'] // 10) * 10

decade_counts, decade_stats = summarize_texts_per_decade(meta_d_prose, 'decade')

print("Textanzahl der Texte im d-Prose pro Jahrzehnt:")
print(decade_stats)
Textanzahl der Texte im d-Prose pro Jahrzehnt:
avg_per_year    418.5
max             681.0
min             106.0
Name: count, dtype: float64

Hide code cell content

# Visualisierung der Dekadenverteilung (Textanzahl pro Dekade)
fig_decade = px.bar(
    x=decade_counts.index.astype(str),
    y=decade_counts.values,
    labels={
        "x": "Jahrzehnt",
        "y": "Anzahl Texte"
    },
    title="Zeitliche Verteilung der Texte im d-Prose pro Jahrzehnt"
)

fig_decade.update_layout(
    height=350,
    margin=dict(l=40, r=40, t=60, b=40),
)
fig_decade.show()

Man sieht jedoch auch, dass dieses Korpus sehr klein ist und den fĂŒr uns relevanten Zeitraum nicht abdeckt.

3.4.6. Option 3. Corpus of German-Language Fiction#

FĂŒr das ‘’Corpus of German-Language Fiction’’ liegt keine fertige Metadatentabelle vor. SĂ€mtliche Metadaten sind hier in den Dateinamen in relativ standardisierter Form kodiert:

Author_name_-_Text_title_(year).txt

e.g.

Abraham_Manuel_Fröhlich_-_Die_Verschüttung_im_Hauenstein_(1858).txt

Daher werden die Korpusdateien in einem separaten Notebook per RegEx in Metadaten ĂŒberfĂŒhrt. An dieser Stelle arbeiten wir mit den Metadaten, die aus diesem Parsing hervorgehen.

meta_gfc = pd.read_csv('../metadata/metadata_corpus-german_language_fiction.csv')
meta_gfc = meta_gfc[meta_gfc['DC.date'] > 1500] # removing super-old outliers
show(meta_gfc)
Loading ITables v2.6.1 from the internet... (need help?)

Analyse der zeitlichen Verteilung des Korpus#

Textanzahl der Texte im ‘Corpus of German Fiction’ pro Jahr:

Hide code cell content

year_counts, year_stats = summarize_texts_per_year(meta_gfc, 'DC.date')

print("Textanzahl der Texte im 'Corpus of German Fiction' pro Jahr:")
print(year_stats)
Textanzahl der Texte im 'Corpus of German Fiction' pro Jahr:
avg_per_year     5.902808
max             66.000000
min              0.000000
Name: count, dtype: float64

Visualisierung der Verteilung pro Jahr

Hide code cell content

fig_year = px.bar(
    x=year_counts.index,
    y=year_counts.values,
    labels={
        "x": "Jahr",
        "y": "Anzahl Texte"
    },
    title="Zeitliche Verteilung der Texte im 'Corpus of German-Language Fiction' pro Jahr"
)

fig_year.update_layout(
    height=350,
    margin=dict(l=40, r=40, t=60, b=40),
    xaxis=dict(
        tickmode="linear",
        tickformat="d"  # ensure clean integer years
    ),
)
fig_year.show()

Anzahl der Texte pro Jahrzehnt

Hide code cell content

# Anzahl der Texte pro Jahrzehnt

meta_gfc['decade'] = (meta_gfc['DC.date'] // 10) * 10

decade_counts, decade_stats = summarize_texts_per_decade(meta_gfc, 'decade')

print("Textanzahl der Texte im 'Corpus of German-Language Fiction' pro Jahrzehnt:")
print(decade_stats)
Textanzahl der Texte im 'Corpus of German-Language Fiction' pro Jahrzehnt:
avg_per_year     82.818182
max             380.000000
min               1.000000
Name: count, dtype: float64

Visualisierung der Dekadenverteilung (Textanzahl pro Dekade)

Hide code cell content

# Visualisierung der Dekadenverteilung (Textanzahl pro Dekade)

fig_decade = px.bar(
    x=decade_counts.index.astype(str),
    y=decade_counts.values,
    labels={
        "x": "Jahrzehnt",
        "y": "Anzahl Texte"
    },
    title="Zeitliche Verteilung der Texte im 'Corpus of German-Language Fiction' pro Jahrzehnt"
)

fig_decade.update_layout(
    height=350,
    margin=dict(l=40, r=40, t=60, b=40),
)
fig_decade.show()

3.4.7. Bewertung und Entscheidung#

Die explorative Analyse erlaubt nun eine systematische Bewertung entlang der Kriterien von (Schöch, 2017).

Kriterium

ELTeC-German

d-Prose 1870–1920

Corpus of German Fiction

Zeitliche Abdeckung

mittel

gering

hoch

DatenqualitÀt

hoch

hoch

mittel

ReprÀsentativitÀt

hoch

mittel

mittel

Umfang

klein

mittel

groß

VerfĂŒgbarkeit

sehr gut

gut

gut

Zwischenfazit

Das Corpus of German-Language Fiction bietet die grĂ¶ĂŸte zeitliche Breite und damit die besten Voraussetzungen, um VerĂ€nderungen im sprachlichen Diskurs ĂŒber LuftqualitĂ€t im 19. Jahrhundert zu untersuchen.


Man erkennt, dass das Corpus of German-Language Fiction einerseits das einzige Korpus ist, das den fĂŒr unsere Forschung notwendigen Zeitraum abdeckt. Andererseits ist es – wie die Verteilung zeigt – eindeutig nicht balanciert. In den Metadaten oder in der Korpusbeschreibung gibt es zudem keinerlei Hinweise darauf, dass dieses Korpus als reprĂ€sentativ angelegt wurde.

FĂŒr die weiteren Analysen mĂŒssen wir das Korpus daher filtern. Dies erfolgt im nĂ€chsten Abschnitt.