Back to Home

Python for Literary Analysis: Alice Selezneva's Space Routes

Learn how Python and regular expressions are used for analyzing the corpus of Kir Bulychev's texts about Alice Selezneva, identifying mentioned and visited planets. Detailed case for IT specialists.

Python and Regular Expressions: Cartography of Alice Selezneva's Planets
Advertisement 728x90

Literary Analysis with Python: Mapping Alisa Selezneva's Cosmic Journeys with Regular Expressions

Applying programmatic methods to analyze literary works unlocks new frontiers in understanding textual data. This article presents a case study on using Python and regular expressions for an in-depth analysis of the literary corpus surrounding Alisa Selezneva's adventures. The research aimed not only to identify all mentioned planets but also to determine which ones the protagonist personally visited, employing contextual analysis techniques.

Data Collection and Preprocessing

The foundational step in any text analysis is data collection and preparation. In this particular case, the disparate stories and novellas about Alisa Selezneva's adventures were aggregated into a single .txt file. Given the diverse nature of the sources, automatically detecting the file encoding was a critical step, for which the chardet library was employed. This prevented issues with incorrect character display and ensured unified text processing.

For the subsequent analysis, standard Python libraries were utilized:

Google AdInline article slot
  • re: The built-in module for working with regular expressions, indispensable for searching and extracting text patterns.
  • collections: Provides specialized container datatypes, such as defaultdict, which was used to create dictionaries with default values, and Counter for counting element frequencies.

Identifying Planets: From Simple Search to Precise Extraction

The task of identifying all planets mentioned in the text proved more complex than initially perceived. The initial approach involved searching for the word 'planet' in its various grammatical cases, then extracting the subsequent word as the planet's name. This utilized a regular expression that accounted for different endings of 'planet' (planet) and captured the following word, provided it started with a capital letter.

def find_planets_after_word(text):
    if text is None:
        return [], []
    pattern_planet_name = r'''
        (?<![.\!\?\n])          
        (planets[aeuy]?|planets)   
        \s+                        
        ([A-Z][a-z]+)           
    '''
    # Originally used to exclude sentence beginnings
    # pattern_sentence_start = r'[.\!\?][\s]+([A-Z][a-z]+)' 
    found_planets = []
    all_matches = []
    for match in re.finditer(pattern_planet_name, text, re.IGNORECASE | re.VERBOSE):
        full_match = match.group(0)
        planet_word = match.group(1)  
        planet_name = match.group(2)
        # Additional logic for filtering and contextual analysis was added later

However, the initial application of this pattern with the re.IGNORECASE flag (case-insensitive search) led to numerous false positives. For instance, adjectives ('another' - 'another', 'new' - 'new') or other nouns might follow 'planet' and be mistakenly interpreted as planet names. The total count of 'planets' exceeded 600, clearly indicating the need for algorithm refinement.

To improve accuracy, the following adjustments were made:

Google AdInline article slot
  • Case Sensitivity for Names: Limiting the search to names starting only with a capital letter. This significantly reduced false positives by excluding adjectives and other functional words.
  • Stop Word List: Creating and applying a stop word list, including common nouns (e.g., "system," "star," "orbit," "atmosphere") that might follow "planet" but are not its name. Checking for word inclusion in this list helped filter out irrelevant matches.
  • Minimum Word Length: Introducing a minimum word length constraint for planet names to exclude prepositions and conjunctions.
  • Excluding Sentence Beginnings: An additional check to determine if the found word was at the beginning of a sentence (after punctuation), to avoid mistakenly identifying ordinary capitalized words as planet names.

After a series of iterations and regular expression refinements, the list of identified planets was reduced to 281. This is a more realistic outcome, reflecting the diversity of worlds mentioned in the Alisa Selezneva books.

Contextual Analysis of Visits: Mapping Alisa's Itinerary

A mere mention of a planet in the text does not imply that the protagonist actually visited it. To determine Alisa's actual travels, a contextual analysis method was developed. The core hypothesis was that a planet visit should be corroborated by the simultaneous mention of Alisa's name (in various grammatical cases) and verbs indicating movement or presence, in close proximity to the planet's name.

To implement this approach, the following were created:

Google AdInline article slot
  • Alisa's Name Patterns: A list of regular expressions covering all grammatical cases of the name "Alisa" (e.g., r'\balice\b', r'\balice\b', r'\balice\b'). The use of \b (word boundaries) ensured precise matching.
  • Travel Verbs: An extensive list of verbs indicating movement, arrival, or presence (e.g., "arrived" - 'flew in', "visited" - 'visited', "turned out" - 'found herself'). Each verb was also formatted as a regular expression with word boundaries for increased accuracy.

The algorithm operated as follows: for each identified planet name, a context was defined – a text fragment within 100 characters before and after the word. Within this context, matches for Alisa's name patterns and travel verbs were sought. If both types of patterns were found within the specified context, the planet was considered visited. This approach allowed distinguishing planets that merely served as background or were mentioned in passing from those where active events involving Alisa took place.

def find_alisa_visited_planets(text, planets_list):
    if text is None:
        return [], []
    alisa_patterns = [
        r'\balice\b', r'\balice\b', r'\balice\b', 
        r'\balice\b', r'\balice\b', r'\balice\b'
    ]
    travel_verbs = [
        r'\barrived\b', r'\barrived\b', r'\barrived\b',
        r'\blanded\b', r'\blanded\b',
        r'\bvisited\b', r'\bvisited\b', r'\bvisited\b',
        r'\bleft\b', r'\bleft\b', r'\bleft\b',
        r'\bwas\b', r'\bwere\b', r'\bwas\b',
        r'\bvisited\b', r'\bvisited\b',
        r'\bset off\b', r'\bset off\b',
        r'\breached\b', r'\breached\b',
        r'\bflew to\b', r'\bflew to\b',
        r'\barrived\b', r'\barrived\b',
        r'\bwas located\b', r'\bwas located\b',
        r'\btraveled\b', r'\btraveled\b',
        r'\bturned out\b', r'\bturned out\b'
    ]
    visited_planets = []
    all_planet_checks = []
    # Simulating planet_pattern from the previous stage
    # For demonstration, we assume that planets_list already contains filtered planet names
    # and for each of them, we search for context
    for planet_name_entry in planets_list:
        planet_name = planet_name_entry # Assuming this is just a string with the planet name
        planet_pattern = r'\b' + re.escape(planet_name) + r'\b'
        planet_visits = []
        for match in re.finditer(planet_pattern, text, re.IGNORECASE):
            position = match.start()
            context_start = max(0, position - 100)
            context_end = min(len(text), position + 100)
            context = text[context_start:context_end].replace('\n', ' ')
            alisa_found = False
            for alisa_pattern in alisa_patterns:
                if re.search(alisa_pattern, context, re.IGNORECASE):
                    alisa_found = True
                    break
            verb_found = False
            matched_verb = None
            for verb_pattern in travel_verbs:
                verb_match = re.search(verb_pattern, context, re.IGNORECASE)
                if verb_match:
                    verb_found = True
                    matched_verb = verb_match.group()
                    break                     
            is_visited = alisa_found and verb_found
            visit_data = {
                'planet': planet_name,
                'position': position,
                'context': context,
                'alisa_found': alisa_found,
                'verb_found': verb_found,
                'matched_verb': matched_verb,
                'is_visited': is_visited
            }
            planet_visits.append(visit_data)
        visited = any(v['is_visited'] for v in planet_visits)
        visit_count = sum(1 for v in planet_visits if v['is_visited'])
        all_planet_checks.append({
            'planet': planet_name,
            'total_mentions': len(planet_visits),
            'visited_mentions': visit_count,
            'is_visited': visited,
            'examples': [v for v in planet_visits if v['is_visited']][:3]
        })
        if visited:
            visited_planets.append({
                'planet': planet_name,
                'total_mentions': len(planet_visits),
                'visited_mentions': visit_count,
                'examples': [v for v in planet_visits if v['is_visited']][:3]
            })
    return visited_planets, all_planet_checks

As a result of this analysis, it was determined that out of 281 mentioned planets, Alisa Selezneva visited 12. This number demonstrates how selectively the author utilized the geography of their world, focusing on key adventure points for the protagonist while still creating the impression of a vast and detailed universe through numerous, though not always visited, mentions. For a 10-year-old girl, 12 visited planets represent a significant amount of travel, especially considering the need to balance it with her studies.

Data Visualization and Conclusions

The final stage of the research involved visualizing the collected data. The plotly library was used to create interactive charts and travel maps. The visualization clearly presented:

  • The distribution of all mentioned planets.
  • A map of Alisa's actual travels, showing which planets she truly visited.
  • The frequency of visits to each planet, providing insight into the most significant locations in her adventures.

The graphical representation of the data makes the analysis results more accessible and intuitive, allowing for a quick assessment of the protagonist's cosmic wanderings. For example, it becomes evident that some planets were visited multiple times, becoming key action sites, while others were mentioned only once to create atmosphere or expand the lore.

The obtained data and methods can be used for further analysis of literary works, including studying authorial style, plot development, and even for creating interactive encyclopedias of fictional universes. This case study demonstrates the potential of text analytics in the humanities, transforming large volumes of unstructured text into valuable quantitative insights.

Key Insights

  • Applying Python and regular expressions enables in-depth literary analysis of large text volumes, extracting structured data.
  • Entity identification (e.g., planets) requires iterative pattern refinement to eliminate false positives and account for context.
  • Contextual analysis is crucial for distinguishing a mere mention from an actual action or event, which is vital for accurate data interpretation.
  • The re, collections, chardet, and plotly libraries are powerful tools for text analytics and result visualization.
  • Even in fiction, quantitative data can be extracted and analyzed, opening new avenues for research in digital humanities.

— Editorial Team

Advertisement 728x90

Read Next