🚀 Analyse 2: Keyword in Context (KWIC)#

🔔 Feinlernziel(e) dieses Kapitels
Sie können die Darstellungsmethode Keywords in Context beschreiben, Wörter zur Anzeige auswählen und diese anzeigen lassen.

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 werden die annotierten Dateien (CSV-Format) analysiert. Unser Ziel ist es, den annotierten Korpus zu nutzen, um KWIC-Ausgaben zu erzeugen.

Dafür werden folgendene Schritte durchgeführt:

  1. Einlesen des Korpus, der Metadaten und der Grippe-Wortliste

  2. Extraktion und Darstellung der Wortkontexte durch KWIC

Informationen zum Ausführen des Notebooks – Zum Ausklappen klicken ⬇️

Voraussetzungen zur Ausführung des Jupyter Notebooks

  1. Installieren der Bibliotheken
  2. Pfad zu den Daten setzen
  3. Laden der Daten (z.B. über den Command `wget` (s.u.))
Zum Testen: Ausführen der Zelle "load libraries" und der Sektion "Einlesen der Daten".
Alle Zellen, die mit 🚀 gekennzeichnet sind, werden nur bei der Ausführung des Noteboos in Colab / JupyterHub bzw. lokal ausgeführt.
Hide code cell content
#  🚀 Install libraries 
! pip install pandas bokeh 
Hide code cell content
import re
from pathlib import Path
import pandas as pd
import requests

## for interactivity in jupyter books
from bokeh.io import output_notebook, show
from bokeh.layouts import column, layout
from bokeh.models import  ColumnDataSource, DataTable, DateFormatter, TableColumn
# Ensure Bokeh output is displayed in the notebook
output_notebook()
Loading BokehJS ...

1. Einlesen der Daten, Metadaten#

1.1 Einlesen des Korpus (CSV-Dateien)#

Informationen zum Ausführen des Notebooks – Zum Ausklappen klicken ⬇️ Zuerst wird der Ordner angelegt, in dem die CSV-Dateien gespeichert werden. Der Einfachheit halber wird die gleich Datenablagestruktur wie in dem GitHub Repository, in dem die Daten gespeichert sind, vorausgesetzt.
Danach werden alle CSV-Dateien im Korpus heruntergeladen und gespeichert. Dafür sind folgende Schritte nötig:
  1. Es wird eine Liste erstellt, die die URLs zu den einzelnen CSV-Dateien beinhaltet.
  2. Die Liste wird als txt-Datei gespeichert.
  3. Alle Dateien aus der Liste werden heruntergeladen und in dem Ordner ../data/csv gespeichert.
Sollten die Dateien schon an einem anderen Ort vorhanden sein, können die Dateipfade zu den Ordnern angepasst werden.
Hide code cell content
# 🚀 Create data directory path
corpus_dir = Path("../data/csv")
if not corpus_dir.exists():
    corpus_dir.mkdir(parents=True)
Hide code cell content
# 🚀 Create download list 
github_api_txt_dir_path = "https://api.github.com/repos/dh-network/quadriga/contents/data/csv"
txt_dir_info = requests.get(github_api_txt_dir_path).json()
url_list = [entry["download_url"] for entry in txt_dir_info]

# 🚀 Write download list as txt file
url_list_path = Path("github_csv_file_urls.txt")
with url_list_path.open('w') as output_txt:
    output_txt.write("\n".join(url_list))
Hide code cell content
# ⚠️ Only execute, if you haven't downloaded the files yet!
# 🚀 Download all csv files – this step will take a while (ca. 7 minutes)
! wget -i github_csv_file_urls.txt -P ../data/csv

Setzen des Pfads:

# set the path to csv files to be processed
csv_dir = Path(r"../data/csv")
# Create dictionary to save the corpus data (filenames and tables)
corpus_annotations = {}

# Iterate over csv files 
for file in csv_dir.iterdir():
    # check if the entry is a file, not a directory
    if file.is_file():
        # check if the file has the correct suffix csv
        if file.suffix == '.csv':
            # read the csv table to a data frame
            data = pd.read_csv(file) 
            # save the data frame to the dictionary, key=filename (without suffix), value=dataframe
            corpus_annotations[file.name] = data

1.2 Einlesen der Metadaten#

Informationen zum Ausführen des Notebooks – Zum Ausklappen klicken ⬇️ Zuerst wird der Ordner angelegt, in dem die Metadaten-Datei gespeichert wird. Wieder wird die gleich Datenablagestruktur wie in dem GitHub Repository vorausgesetzt.
Der Text wird aus GitHub heruntergeladen und in dem Ordner ../data/metadata/ abgespeichert.
Der Pfad kann in der Variable metadata_path angepasst werden. Die einzulesende Datei muss die Endung `.csv` haben.
Hide code cell content
# 🚀 Create metadata directory path
metadata_dir = Path("../data/metadata")
if not metadata_dir.exists():
    metadata_dir.mkdir()
Hide code cell content
# 🚀 Load the metadata file from GitHub 
! wget https://raw.githubusercontent.com/dh-network/quadriga/refs/heads/main/data/metadata/QUADRIGA_FS-Text-01_Data01_Corpus-Table.csv -P ../data/metadata
# set path to metadata file
metadata_path = '../data/metadata/QUADRIGA_FS-Text-01_Data01_Corpus-Table.csv'

# read metadata file to pandas dataframe and set index
corpus_metadata = pd.read_csv(metadata_path, sep=';')
corpus_metadata = corpus_metadata.set_index('DC.identifier')

Kombinieren von tokenisierten Texten und deren Metadaten für KWIC-Suche#

def get_date_metadata(txtname, corpus_metadata):  
    date = corpus_metadata.loc[txtname, 'DC.date']
    date = str(date)
    year = date[:4]
    month = date[:7]
    day = date
    return year, month, day 
for filename, annotated_text in corpus_annotations.items():
    txtname = filename.replace('.csv', '')
    if txtname in corpus_metadata.index:
        year, month, day = get_date_metadata(txtname, corpus_metadata)
        annotated_text['month'] = month
        annotated_text['filename'] = filename
search_df = pd.concat(corpus_annotations.values())
search_df = search_df.reset_index()
search_df["Token"] = search_df["Token"].astype(str)
print(f'The KWIC-search will be over a corpus of {search_df.shape[0]} word occurences')
The KWIC-search will be over a corpus of 33192061 word occurences

1.3 Einlesen der Wortliste (Semantisches Feld “Grippe”)#

Hide code cell content
# 🚀 Create word list directory path
wordlist_dir = Path("../data/wordlist")
if not wordlist_dir.exists():
    wordlist_dir.mkdir()
Hide code cell content
# 🚀 Load the wordlist file from GitHub 
! wget https://raw.githubusercontent.com/dh-network/quadriga/refs/heads/main/data/wordlist/grippe.txt -P ../data/wordlist
path_to_wordlist = Path("../data/wordlist/grippe.txt")
word_list = path_to_wordlist.read_text().split("\n")

Wie sieht die Wortliste aus?

word_list
['Influenza',
 'Grippe',
 'Grippeepidemie',
 'Grippewelle',
 'Grippekranke',
 'Grippepandemie',
 'Lungenentzündung',
 'Krankheitswelle',
 'Seuchenzug',
 'Krankheitsausbruch',
 'Fieberanfall',
 'Schüttelfrost',
 'Atemnot',
 'Körpererschöpfung',
 'Genesungszeit',
 'Ansteckungsgefahr',
 'Seuchenschutz',
 'Desinfektionsmittel',
 'Schutzmaske',
 'Krankenstation',
 'Isolationsstation',
 'Sanitätsdienst',
 'Krankheitsverlauf',
 'Todesopfer',
 'Krankheitssymptom',
 'Erkrankungsfall',
 'Lungeninfektion',
 '']

2. Extraktion und Darstellung der Wortkontexte durch KWIC#

Hide code cell content
class ContextViewer:
    
    def __init__(self, search_df):
        self.full_df = search_df
        print(f'Searching in a corpus of {self.full_df.shape[0]} word occurences')
        
    def show_kwic_output(self, search_terms, n_words):
        contexts_df = self.get_context_words(search_terms, n_words)
        
        # Convert DataFrame to ColumnDataSource
        source = ColumnDataSource(contexts_df)
                
        # Create Table Columns
        columns = [TableColumn(field=col, title=col) for col in contexts_df.columns]

        # Create DataTable
        data_table = DataTable(source=source, columns=columns)

        # Display DataTable
        output_notebook()  # Use this to render in Jupyter Notebook
        show(layout([data_table]))

    
    def get_context_words(self, search_terms, n_words):
        #search_terms = input('Insert a word to search, split by comma if more than one: ')
        if len(search_terms) == 0:
            search_terms = word_list
        if isinstance(search_terms, str):
            search_terms = search_terms.split(',')
        search_terms = [x.strip() for x in search_terms]
        indices = self.full_df.query(f'Lemma.isin({search_terms})').index
        #print(indices)
        left_contexts = []
        this_words = []
        right_contexts = []
        months = []
        for indice in indices:
            left = self.full_df.iloc[indice-n_words:indice-1, ]["Token"]
            leftс = left[~left.str.contains('\n')]
            right = self.full_df.iloc[indice+1:indice+n_words, ]["Token"]
            rightс = right[~right.str.contains('\n')]
            left_contexts.append(' '.join(leftс))
            right_contexts.append(' '.join(rightс))
            this_words.append(self.full_df.iloc[indice, ]["Token"])
            months.append(self.full_df.iloc[indice, ]["month"])
        newdf = pd.DataFrame()
        newdf['left_context'] = left_contexts
        newdf['word'] = this_words
        newdf['right_context'] = right_contexts
        newdf['month'] = months
        return newdf
        
kwic = ContextViewer(search_df)
Searching in a corpus of 33192061 word occurences
kwic.show_kwic_output(word_list, n_words=5)
Loading BokehJS ...

Worteingabe für die Suche und KWIC-output (für Cloud Mode und Local Mode)#

Hide code cell content
text_input = input("Geben Sie die zu suchenden Wörter ein und trennen Sie sie durch Kommas, wenn es mehrere sind:")
# Convert the input to a list by splitting the input by comma
search_terms = [x.strip() for x in text_input.split(',')]
Hide code cell content
kwic.show_kwic_output(search_terms, n_words=5)