micheledpierri.com: statistics, data analysis and coding

Nexus of Statistics, Data analysis, Coding, Art and Medicine

Menu
  • Home
  • Courses
    • Python Foundation
    • Statistics
    • Data Analysis
    • Machine Learning
  • Blog
    • All Pages
    • Health Informatics
    • Programming
    • Art
  • Illustrations
  • About
  • Contact
Menu
Home / Archives for Michele Danilo Pierri / Page 7

Author: Michele Danilo Pierri

Michele D. Pierri is a cardiac surgeon and cardiovascular physiopathology researcher with a strong interest in artificial intelligence, medical data science, clinical decision support, and digital health. His work focuses on the intersection between medicine, technology, and computational methods, with the aim of translating complex biomedical concepts into clear, practical, and clinically meaningful insights.
Elderly bearded man in early 20th-century attire examines a framed tablet covered with archaic symbols inside a worn hospital ward, surrounded by an iron bed, anatomical charts, glass bottles, and antique medical instruments.

Character Encoding

Posted on October 1, 2024June 20, 2026 by Michele Danilo Pierri

Character encoding is the process of assigning a unique number to each character, enabling computers to exchange data in a standardized and unambiguous manner.

Various encoding systems have developed over time and across different regions. These systems often lack compatibility, have space limitations (and consequently character limitations), and may use the same encoding for different characters.

To address these issues, the Unicode system was developed in the 1980s. It aimed to create a universal encoding that includes characters used in all languages worldwide, as well as symbols and emojis.

The first Unicode standard, published in 1991, included 7,000 characters. Currently, it encompasses 143,000 characters and is adopted by all operating systems, programming languages, and communication systems.

Despite Unicode’s introduction, many pre-existing and subsequent encodings continue to exist. This persistence is due to legacy systems using pre-Unicode encodings, the higher memory requirements of Unicode, and the preference for optimized encodings in specific contexts (such as for Chinese or Japanese languages).

As a result, pre-Unicode encodings and Unicode-implementing systems currently coexist. The most widely used ones are listed below.

ASCII (American Standard Code for Information Interchange)

ASCII, one of the earliest encodings, comprises 128 characters. It’s primarily suited for the English language, as it doesn’t include accented or special characters.

ISO-8859-1 (Latin-1)

ISO-8859-1 can be considered an extension of ASCII encoding that includes accented letters. It’s suitable for many European languages and encompasses 256 characters. However, it still lacks some accented characters used in certain languages.

UTF-8 (Unicode Transformation Format 8-bit)

UTF-8 is the most widespread encoding. It uses 1 to 4 bytes to encode not only ASCII characters but also characters from other languages such as Chinese and Arabic, as well as symbols. It complies with Unicode standards.

UTF-16

UTF-16 uses 2 to 4 bytes to represent characters. It’s less efficient than UTF-8 for English and some Latin texts and is used in some Windows systems.

UTF-32

UTF-32 has a fixed length of 4 bytes per character. It’s simpler than the previous encodings but less efficient.

The existence of multiple encoding systems can cause significant problems. If you try to open a text file using a different encoding from the original, you may see strange or illegible characters.

To detect the encoding of a text using Python, you can use two libraries: chardet and charset-normalizer. Both libraries need to be installed in your system using pip.

Opening a file in binary mode allows chardet to analyze its content and determine the encoding:

import chardet

# Open the file in binary mode to read its content
with open('example_text.txt', 'rb') as f:
    content = f.read()

# Use chardet to detect the encoding
result = chardet.detect(content)

# Print the detected encoding
print(f"Detected encoding: {result['encoding']}")

When using charset-normalizer, the process differs slightly, as opening the file isn’t necessary:

from charset_normalizer import from_path

# Detect the encoding of the file
result = from_path('example_text.txt').best()

# Show the detected encoding
print(f"Detected encoding: {result.encoding}")

Using chardet, we can also convert text from one encoding to another, such as UTF-8:

import chardet

# Step 1: Read the file content in binary mode
with open('example_text.txt', 'rb') as f:
    content = f.read()

# Step 2: Detect the original encoding using chardet
result = chardet.detect(content)
original_encoding = result['encoding']

# Step 3: Decode the content using the detected encoding
decoded_text = content.decode(original_encoding)

# Step 4: Re-encode the text as UTF-8 and save it to a new file
with open('example_text_utf8.txt', 'w', encoding='utf-8') as f:
    f.write(decoded_text)

print("File has been successfully converted to UTF-8.")

The chardet library can decode character formats in text files (txt), HTML, XML, and CSV files. However, its detection capability may be less effective for text embedded in binary files. For databases where encoding information is needed, it might be necessary to extract the textual data first (for instance, by using SQL queries to dump text files) before applying chardet to the extracted text.

A man in early 20th-century clothing stands beside a monumental hourglass in an old hospital room, surrounded by faded medical symbols, a large clock mural, and an iron bed.

Moments

Posted on September 24, 2024August 1, 2026 by Michele Danilo Pierri

The concept of “moment” has various interpretations depending on context, but generally refers to a unit of time, a specific occasion, or a particular state. In mechanics, a “moment” is the tendency of a force to rotate a body around a point or axis. In other contexts, it can refer to a precise instant in time, an emotionally significant period in psychology, or a notable event or period in history and culture.

Our focus, however, is on statistical “moments,” which are used to describe the distribution of data.

Absolute moments

Absolute moments are calculated around the origin. They consider the values of a variable to the zero point, rather than the mean value. In essence, absolute moments measure how much our values deviate from zero.

\mu'_k = E(X^k) = \int_{-\infty}^{\infty} x^k f(x) dx

For example, if our variable measures heights, absolute moments evaluate how much each individual value deviates from zero, without considering the mean.

In the formula, the expected value of the first moment (k=1) represents the mean.

Central moments

Central moments are more significant as they are calculated relative to the mean.

The most important central moments are:

  • First central moment: always equals zero, representing the average difference between values and their mean.
  • Second central moment: the variance (σ2) of the distribution, measuring dispersion around the mean.
  • Third central moment: this measures skewness, describing the distribution’s symmetry relative to the mean.
  • Fourth central moment: measures kurtosis, indicating the “heaviness” of the distribution’s tails—how pronounced or thin they are compared to a normal distribution.

The general formula for central moments is:

\mu_k = \frac{1}{N} \sum_{i=1}^{N} (x_i - \overline{x})^k

Where: N is the number of data points, xi is each individual data point, x̄ is the mean of the data, k is the order of the moment.

For k = 1 (first-order moment), we obtain the mean—the expected value of a distribution.

For k = 2 (second-order moment), we obtain the variance, which measures how much the data deviates from the mean.

For k = 3 (third-order moment), we obtain the skewness, indicating how much the distribution is tilted to the right or left.

For k = 4 (fourth-order moment), we obtain the kurtosis, representing the “heaviness” of the distribution’s tails.

These concepts form the foundation of data analysis, statistical inference, and hypotheses about random phenomena.

An elderly woman with a cane speaks to a bearded street medicine vendor beside a table of amber bottles in a misty, early 20th-century cobblestone alley.

Elixir of Love: Udite, udite rustici

Posted on September 17, 2024June 20, 2026 by Michele Danilo Pierri

(Hear me, hear me, listen, o countrimen) – The Elixir of Love by Gaetano Donizetti

The Composer

Gaetano Donizetti (1797–1848) was a leading Italian composer of the 19th century, renowned primarily for his operas. Alongside Gioachino Rossini and Vincenzo Bellini, he is considered one of the main exponents of bel canto—a lyrical style of operatic singing.

The Opera

Composed in 1832, “The Elixir of Love” stands as one of Donizetti’s most beloved comic operas. It captivates audiences with its sparkling melodies, vibrant orchestration, and vividly drawn characters.

Set in an Italian village, the opera centers around Nemorino, a shy young peasant in love with Adina, a wealthy and capricious woman. Adina, however, is being courted by Sergeant Belcore.

Enter Dulcamara, a charlatan who sells Nemorino a “love elixir”—which is actually just wine—promising it will win Adina’s heart. Believing in the elixir’s power, Nemorino’s newfound confidence makes Adina jealous. In a moment of anger, she agrees to marry Belcore.

Desperate, Nemorino joins in the army to buy more elixir. Coincidentally, he inherits a fortune, suddenly attracting the attention of all the village girls. Seeing this, Adina realizes her true feelings for Nemorino. She buys out his enlistment contract, freeing him from the army. The opera concludes with Nemorino and Adina confessing their love for each other.

Historical Medical Context

Dulcamara, a character in Donizetti’s “The Elixir of Love,” provides a fascinating lens through which to examine medical history—specifically, the prevalence of charlatans and itinerant doctors in the 18th and 19th centuries.

In 18th and 19th century Europe, itinerant doctors—often called “charlatans”—were a common sight. These colorful characters roamed from town to town, hawking an array of “miracle” remedies: elixirs promising long life and potions claiming to cure every imaginable malady. Theatrical and silver-tongued, they combined showmanship with resourcefulness. Taking advantage of widespread medical ignorance and lax regulations, these charlatans promoted products that, more often than not, possessed no actual therapeutic value.

In the era depicted by the opera, medicine was still a nascent science. The scarcity of effective treatments for numerous ailments, coupled with a lack of robust scientific understanding, bred widespread skepticism towards conventional medicine. This climate of doubt created fertile ground for characters like Dulcamara to flourish. These self-proclaimed “doctors” capitalized on people’s gullibility, hawking quick fixes and simple remedies for intricate health issues.

Historically, miracle remedies were peddled as quick fixes for everything—from chronic illnesses to matters of the heart—mirroring Dulcamara’s tactics in the opera.

Dulcamara embodies a pivotal moment in medical history, as the field began shifting towards a more scientific, evidence-based approach. His comical portrayal as a crafty charlatan offers a subtle critique of unscientific medicine and its practitioners. Through this character, the opera cleverly satirizes the medical chicanery that was prevalent during this transitional period.

Characters like Dulcamara played a complex role in shaping public perception of medicine. They highlighted the importance of critical thinking, cautioning against blindly accepting any proposed “cure.” However, these charlatans also fostered distrust in legitimate medical practices—a skepticism that persisted until evidence-based medicine took hold in the late 19th century.

An elderly physician speaks with a seated young woman in an early 20th-century hospital room filled with antique medical instruments, iron beds, glass bottles, and warm sepia light.

The Barber of Seville by Gioacchino Rossini

Posted on September 13, 2024August 5, 2026 by Michele Danilo Pierri

(“A un dottor della mia sorte” – “to a doctor of my station”)

““The Barber of Seville,” a witty comedy written by Pierre-Augustin Caron de Beaumarchais in 1775, was later transformed into a lively opera by Gioachino Rossini in 1816. Rossini’s adaptation breathed new musical life into this classic tale.

The Story

Rosina lives under the supervision of Doctor Bartolo, who wishes to marry her for her dowry. Count Almaviva, smitten with Rosina, enlists the help of Figaro, the clever barber of Seville, to devise a series of plans to approach her.

The Count first disguises himself as a drunken soldier with a fake lodging order. Later, he poses as a music teacher, replacing Don Basilio, the actual instructor Bartolo had invited to teach Rosina.

Through these disguises and Figaro’s cunning, the Count manages to meet Rosina and confess his feelings. Charmed by his advances, Rosina falls in love with him.

Despite Doctor Bartolo’s schemes to thwart their union, Count Almaviva and Rosina ultimately marry, thanks in large part to Figaro’s assistance. The opera concludes with Bartolo’s defeat and the celebration of the Count and Rosina’s triumphant love.

The Doctor’s Role in the Opera

Don Bartolo, an elderly, greedy, and jealous doctor, seeks to marry his young ward, Rosina, primarily for her fortune. This central character is frequently mocked for his futile attempts to control Rosina and thwart Count Almaviva’s advances.

Don Bartolo embodies the negative stereotype of the 18th-century doctor: greedy, incompetent, and more concerned with his own profits than his patients’ well-being. This portrayal reflects society’s criticism of a profession often perceived as corrupt and prioritizing money over care.

Despite his position as a doctor, Don Bartolo is frequently portrayed as inept and ignorant. This is evident in numerous scenes where he’s easily deceived by other characters, particularly the clever barber Figaro and the cunning Count Almaviva.

As a doctor, Don Bartolo holds a position of authority in society, yet his authority is frequently mocked and challenged. This criticism extends beyond doctors to all powerful figures who exploit their positions for personal gain.

Ultimately, Don Bartolo’s character serves as a satirical critique of society and its institutions. Beaumarchais uses this figure to expose the hypocrisy and corruption not only within the medical profession but also among other powerful figures of the time.

Aria text

Historical context

In the 18th century, the figure of the doctor differed greatly from today’s. Medicine was still an evolving science, with many physicians viewed as charlatans rather than true professionals. Limited medical training, often accessible only to the wealthy, created a class of doctors more interested in social prestige and personal gain than patient care.

Beaumarchais’ satire reflects this reality, exposing the hypocrisy and corruption in the medical profession. Doctors like Don Bartolo are portrayed as authoritative figures who frequently abuse their power, prioritizing their own interests over their patients’ well-being.

In “The Barber of Seville,” the doctor emerges as a sharp social critique, embodying the flaws and hypocrisies of the 18th-century medical establishment through the character of Don Bartolo.

The Medical Inspection by Henri de Toulouse-Lautrec

Posted on September 5, 2024August 8, 2026 by Michele Danilo Pierri

The Artist

The author of “The Medical Inspection” Henri de Toulouse-Lautrec was born into an aristocratic family on November 24, 1864, in Albi, France. He suffered from a genetic disorder that caused bone fragility, compromising his development. While his torso developed normally, his legs remained stunted.

Henri stood only 1.52 m (5 ft) tall as an adult. His physical appearance significantly impacted his social interactions, often leading to isolation. Yet, this experience fostered a deep empathy for marginalized individuals—a trait that would define his life and work.

Toulouse-Lautrec identified with the poor, prostitutes, and alcoholics, eventually considering the brothels of Montmartre as a second home—a refuge where he found acceptance. His artistic focus centered on life in brothels and cabarets, offering a disenchanted vision that highlighted everyday moments in these places without idealization or judgment.

Henri de Toulouse-Lautrec

The Painting

“The Medical Inspection” vividly captures a scene from the marginalized sector of 19th-century Parisian society. The painting depicts a group of women in a brothel, lined up for their mandatory medical examination—a practice implemented in an attempt to control the spread of venereal diseases. This routine inspection, while ostensibly for public health, underscores the harsh realities and lack of autonomy faced by sex workers of the time.

Toulouse-Lautrec’s masterful use of color and light is evident in this piece. The muted, subdued palette he employs—soft pinks, pale yellows, and muted greens—creates a somber, almost oppressive atmosphere. This choice of colors, combined with the subtle, diffused lighting, enhances the overall melancholic mood of the scene. The artist’s technique here serves not just an aesthetic purpose, but also a narrative one, effectively communicating the emotional weight of the situation.

The women’s expressions, carefully rendered by Toulouse-Lautrec, are particularly telling. Their faces, inscribed with a mixture of resignation and ennui, convey a profound message about their circumstances. The boredom visible in their eyes and the posture of their bodies suggest a routine familiarity with this dehumanizing process. Yet, there’s also a sense of quiet dignity, a silent resilience in the face of their circumstances.

Through this paint, Toulouse-Lautrec invites the viewer to confront the harsh realities of life on the margins of society, challenging us to see beyond societal judgments and recognize the humanity in these often-overlooked individuals.

Like many of Lautrec’s works, this painting offers no idealization—it presents the scene in stark reality. However, the artist’s empathy and deep understanding of these marginalized women are evident throughout the piece.

Historical Context

The late 19th century coincided with the Belle Époque, a period when Paris became a vibrant hub where avant-garde ideas, artists, and intellectuals converged and flourished.

Yet, this cultural dynamism was overshadowed by a pressing social issue—the rampant spread of venereal diseases, which escalated into a significant public health crisis.

Syphilis, often called “the great imitator” for its ability to mimic other diseases, could lead to severe consequences including paralysis, dementia, and death. No effective treatment existed; mercury, the only option available, caused serious side effects. Gonorrhea was another widely prevalent disease.

In France, where prostitution was legal and regulated, Napoleon introduced a law in 1804 mandating periodic medical examinations for sex workers. Lautrec’s painting depicts one such inspection.

These examinations were not only humiliating and invasive but also a source of intense anxiety. A positive test result meant quarantine or confinement in medical facilities, effectively ending a woman’s means of livelihood.

This system highlighted a stark gender inequality that permeated 19th-century society: while men could freely visit brothels without any restrictions or consequences—potentially spreading diseases in the process—they faced no such oppressive controls or mandatory medical examinations. The burden of disease prevention and control fell entirely on the women working in these establishments, who were subjected to invasive and humiliating inspections. This disparity not only reflected the social norms of the time but also perpetuated a cycle of discrimination and health risks, as infected men could continue to spread diseases unchecked while women shouldered the burden of both social stigma and medical scrutiny.

Toulouse-Lautrec’s painting thus serves as both a testament to the artist’s remarkable ability to capture these specific situations and a valuable historical document of the era’s health and social challenges.

Images from Wikimedia Commons

A lecturer in formal early 20th-century dress stands on a small stage addressing a seated audience in a historic hall, rendered as a warm sepia-toned painterly illustration with columns, red drapery, and soft antique light.

How many Sums of Squares we’re dealing with in Repeated Measures ANOVA?

Posted on September 4, 2024August 1, 2026 by Michele Danilo Pierri

When setting up a repeated measures ANOVA test in SPSS, the dialog box for the model has “Type 3 sum of squares” selected by default. By exploring the window further, you’ll find that you can also choose multiple sums of squares: Type 1, Type 2, or Type 4.

How many types of Sums of Squares are there, and when should you use each one?

This issue is relevant because choosing one type over another can significantly affect the analysis results, particularly with unbalanced data or when certain assumptions are violated.

Let’s examine the different types.

The examples will be based on a hypothetical experiment with two factors: Factor A (with 2 levels: A1 and A2) and Factor B (with 2 levels: B1 and B2). Let’s assume we also have an interaction between A and B (A x B).

Type 1 SS

In Type 1 Sum of Squares, the calculation process follows a sequential order, which means that each effect is evaluated conditionally based on the effects that precede it in the model. This approach allows for a hierarchical assessment of the factors and their interactions.

The sequential nature of Type 1 SS results in the following order of calculations:

  1. SS(A) = Variation explained by factor A This represents the amount of variability in the dependent variable that can be attributed solely to factor A, without considering any other factors or interactions.
  2. SS(B|A) = Variation explained by factor B after accounting for factor A This calculation determines the additional variability explained by factor B, but only after the effects of factor A have been taken into account. It essentially measures the unique contribution of factor B beyond what has already been explained by factor A.
  3. SS(AB|A,B) = Variation explained by the interaction of AxB after considering both A and B This final step evaluates the amount of variability that can be attributed to the interaction between factors A and B, but only after the individual effects of both A and B have been accounted for. It represents the synergistic or antagonistic effects that occur when the two factors are combined.

It’s important to note that the order in which factors are entered into the model can significantly impact the results of Type 1 SS, especially in cases of unbalanced designs or when there are correlations between the predictors.

Type 2 SS

Type 2 Sum of Squares (SS) evaluates each effect independently for main effects, without considering interactions. This approach provides a more balanced assessment of each factor’s contribution to the overall variability in the data.

The calculation process for Type 2 SS follows a specific order, which allows for a comprehensive analysis of the main effects while maintaining the integrity of each factor’s individual impact. The sequence of calculations is as follows:

  1. SS(A|B): This step calculates the variation explained by Factor A, while taking into account the presence of Factor B. It’s important to note that this calculation does not consider any potential interaction between the two factors. This allows for an isolated assessment of Factor A’s main effect, controlling for the influence of Factor B.
  2. SS(B|A): Similarly, this calculation determines the variation explained by Factor B, while accounting for the presence of Factor A. Again, the interaction between the factors is not considered at this stage. This step provides insight into the unique contribution of Factor B to the overall variability, independent of Factor A’s influence.
  3. SS(AB|A, B): The final step in Type 2 SS involves calculating the variation explained by the interaction between Factors A and B, after both main effects have been accounted for. This calculation is identical to the one used in Type I SS for the interaction term. It reveals any additional variability that can be attributed to the combined effect of the two factors, beyond their individual main effects.

Type 2 SS is most useful when the primary focus is on main effects, and interactions are either not of interest or absent. This approach is particularly effective in balanced experimental designs.

Type 3 SS

Type III sum of squares evaluates each main effect and interaction while controlling for all other effects (both main effects and interactions). This approach provides a comprehensive assessment of each factor’s unique contribution to the model.

The calculation process for Type 3 Sum of Squares follows a specific order, ensuring that each effect is evaluated while controlling for all other effects in the model. This comprehensive approach allows for a more nuanced understanding of each factor’s unique contribution to the overall variability. The sequence of calculations is as follows:

  1. SS(A|B, AB): This step calculates the variation explained by Factor A, while simultaneously controlling for both Factor B and the interaction between A and B (AB). By doing so, we isolate the unique effect of Factor A, independent of any influence from Factor B or their interaction. This provides a pure measure of Factor A’s contribution to the model.
  2. SS(B|A, AB): Similarly, this calculation determines the variation explained by Factor B, while controlling for Factor A and the AB interaction. This approach allows us to assess the unique impact of Factor B on the dependent variable, separate from any effects of Factor A or their interaction. It offers insight into Factor B’s individual contribution to the overall variability in the data.
  3. SS(AB|A, B): The final step involves calculating the variation explained by the interaction between Factors A and B, while controlling for both main effects. This calculation reveals any additional variability that can be attributed to the synergistic or antagonistic effects of the two factors combined, beyond what can be explained by their individual main effects. It provides crucial information about how the factors work together to influence the dependent variable.

Type 3 SS is particularly valuable in complex experimental designs, especially when dealing with unbalanced data or when interactions between factors are of primary interest. By controlling for all other effects, it provides a robust and unbiased assessment of each factor’s unique contribution to the model, regardless of the order in which the factors are entered into the analysis.

This method is widely used across many statistical software packages and is the default option in SPSS.

Type 4 SS

Type 4 sums of squares are designed to handle cases with missing data or particularly complex and unbalanced designs. They account for empty cells (missing data), enabling a more precise analysis in these challenging situations.

Type 5 SS

Type 5 SS is less common and is specifically used for certain experimental designs, particularly those involving covariates or mixed models.

Interaction Between Factors

When conducting a repeated measures ANOVA test with two or more factors, we must consider not only the effect of individual factors on the dependent variable but also the interactions between them.

If there’s an interaction between two factors, A and B, the final effect isn’t simply the sum of A’s effect and B’s effect. Instead, it includes their interaction as well.

Consider testing a drug’s effectiveness in treating hypertension (Factor A: A1 drug present, A2 drug absent) while also putting patients on a diet (Factor B: B1 diet with high protein present, B2 diet absent). The final effect on blood pressure won’t just be the combined effect of the drug and diet. It will also depend on how they interact. For instance, the drug’s effect might be enhanced when combined with the diet and diminished without it.

When interaction occurs, it complicates the attribution of effects to individual factors and makes interpreting the phenomenon more challenging. Moreover, the interaction itself may become the study’s primary focus, often proving more intriguing than the effects of individual factors alone.

Let’s visually represent how factors A (drug) and B (diet) affect blood pressure values, both with and without interaction.

import matplotlib.pyplot as plt
import numpy as np

# Hypothetical data for interaction plot
# Factor A with two levels: A1 and A2
# Factor B with two levels: B1 and B2

# Levels of Factor A (e.g., Drug: Present (A1) and Absent (A2))
A_levels = ['A1', 'A2']

# Example with interaction between factors
# Blood pressure reduction for different levels
# Effect of the drug (Factor A) at different levels of diet (Factor B)
reduction_B1_interaction = [10, 4]  # Effect of A1 and A2 with Diet B1 (High Protein)
reduction_B2_interaction = [5, 8]   # Effect of A1 and A2 with Diet B2 (Low Protein)

# Plotting the interaction graph
plt.figure(figsize=(8, 6))

# Plot lines for different levels of Factor B
plt.plot(A_levels, reduction_B1_interaction, marker='o', label='Diet B1 (High Protein)', linestyle='-', linewidth=2)
plt.plot(A_levels, reduction_B2_interaction, marker='o', label='Diet B2 (Low Protein)', linestyle='-', linewidth=2)

# Adding labels and title
plt.xlabel('Levels of Factor A (Drug)', fontsize=12)
plt.ylabel('Blood Pressure Reduction (mmHg)', fontsize=12)
plt.title('Interaction Plot between Drug (A) and Diet (B)', fontsize=14)

# Adding a legend
plt.legend(title='Levels of Factor B (Diet)', fontsize=10)

# Display the plot
plt.grid(True)
plt.show()

# Example without interaction between factors
# Blood pressure reduction for different levels
# Here, the effect of the drug (Factor A) is consistent across both diets (Factor B)
reduction_B1_no_interaction = [6, 4]  # Effect of A1 and A2 with Diet B1 (High Protein)
reduction_B2_no_interaction = [6, 4]  # Effect of A1 and A2 with Diet B2 (Low Protein)

# Plotting the non-interaction graph
plt.figure(figsize=(8, 6))

# Plot lines for different levels of Factor B
plt.plot(A_levels, reduction_B1_no_interaction, marker='o', label='Diet B1 (High Protein)', linestyle='-', linewidth=2)
plt.plot(A_levels, reduction_B2_no_interaction, marker='o', label='Diet B2 (Low Protein)', linestyle='-', linewidth=2)

# Adding labels and title
plt.xlabel('Levels of Factor A (Drug)', fontsize=12)
plt.ylabel('Blood Pressure Reduction (mmHg)', fontsize=12)
plt.title('Plot without Interaction between Drug (A) and Diet (B)', fontsize=14)

# Adding a legend
plt.legend(title='Levels of Factor B (Diet)', fontsize=10)

# Display the plot
plt.grid(True)
plt.show()
Interaction plot between two features

Interaction Plot: This graph illustrates the interaction between the drug (Factor A) and diet (Factor B). The drug’s effect on blood pressure reduction varies depending on the diet type. With Diet B1 (High Protein), the reduction is greater when the drug is present (A1) compared to when it’s absent (A2). Conversely, for Diet B2 (Low Protein), this pattern reverses. This clear reversal demonstrates a significant interaction between the two factors.

Plot without interactione between drugs

Plot without Interaction: This graph shows no interaction between the drug and diet. The drug’s effect (A1 vs. A2) remains consistent across both diet types (B1 and B2). The parallel lines indicate that the diet doesn’t influence how the drug affects blood pressure reduction.

Two impoverished boys kneel in a war-damaged street, placing coins into a piggy bank amid rubble and crumbling buildings, in a warm sepia-toned historical painting style.

SQL databases

Posted on August 31, 2024July 29, 2026 by Michele Danilo Pierri

In Python data management, SQL databases become essential when dealing with large data volumes. These databases efficiently handle extensive structured data, offering robust features for complex querying, maintaining data integrity, and managing storage effectively. As datasets grow in size and complexity, SQL databases provide the necessary scalability, performance optimization, and data consistency mechanisms crucial for effective large-scale data analysis and manipulation.

SQL is a powerful language for data manipulation, enabling complex queries, joins, and aggregations of structured data. Python offers various libraries that facilitate interaction with SQL databases, efficiently executing CRUD operations (Create, Read, Update, Delete). These libraries include sqlite3 for SQLite, pymysql for MySQL, psycopg2 for PostgreSQL, and SQLAlchemy as an ORM (Object-Relational Mapping) library. Below, I’ll demonstrate how to use some of these libraries with code examples.

SQLite

SQLite is a lightweight, serverless database that can be directly integrated into Python applications. It is widely appreciated for its simplicity, portability, and ease of use. These qualities make it ideal for desktop applications, mobile apps, small websites, development tools, and other scenarios where a complex, server-based database management system is unnecessary.

In SQLite, all data—including table definitions, indexes, and the data itself—is stored in a single file. This design makes the database portable and easy to manage. Despite its simplicity, SQLite supports most SQL standards.

Python’s built-in sqlite3 module is used for working with SQLite databases. As part of Python’s standard library, the SQLite module requires no additional installation.

 # Import the sqlite3 module, which is part of Python's standard library
import sqlite3  

# Create a connection to an SQLite database.
# If the database file 'example.db' does not exist, it will be created in the current directory.
conn = sqlite3.connect('example.db')

# Create a cursor object.
# A cursor is used to execute SQL commands and interact with the database.
cursor = conn.cursor()

# Execute an SQL command to create a new table named 'users' if it doesn't already exist.
# The table has three columns: 'id', 'name', and 'age'.
# - 'id' is an INTEGER and serves as the PRIMARY KEY, which is unique for each row and auto-incremented.
# - 'name' is a TEXT field and cannot be NULL.
# - 'age' is an INTEGER field.
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    age INTEGER
)
''')

# Insert a new row into the 'users' table.
# The '?' placeholders are used to securely insert the values ('Alice' and 30) to prevent SQL injection.
cursor.execute('INSERT INTO users (name, age) VALUES (?, ?)', ('Alice', 30))

# Commit the current transaction. This saves all the changes made to the database since the last commit.
# Without this, the changes (inserting data in this case) would not be saved to the 'example.db' file.
conn.commit()

# Execute a SQL query to retrieve all rows from the 'users' table.
cursor.execute('SELECT * FROM users')

# Fetch all the results of the last executed SQL command (SELECT).
# This returns a list of tuples, where each tuple represents a row from the result set.
rows = cursor.fetchall()

# Iterate over the rows and print each one.
# Each 'row' is a tuple containing the values of each column for that specific row.
for row in rows:
    print(row)

# Close the connection to the database.
# This is important to ensure all changes are saved and to free up resources.
conn.close()

MySQL

MySQL is a robust and feature-rich relational database management system (RDBMS) that requires installation and setup outside of Python.

Unlike SQLite, which is serverless and embedded, MySQL operates as a separate database server running independently of Python applications.

To use MySQL, you must install the MySQL server software on your machine or use a managed MySQL service (e.g., AWS RDS, Azure Database for MySQL). The MySQL server needs to be configured and started separately from your Python environment. Once installed, the server runs as a service or process that manages database operations and responds to client requests.

Your Python application acts as a client, connecting to the MySQL server using a network protocol (typically TCP/IP). Multiple clients can connect to the server simultaneously, enabling high concurrency and centralized database management.

To connect to a MySQL database from Python, you need to use an external library or driver, such as mysql-connector-python, PyMySQL, or MySQLdb. These libraries must be installed separately using the package manager pip.

To connect to a MySQL database from Python, you first need to install the MySQL Connector library.

pip install mysql-connector-python

After installing the library, you can import and use it in Python as follows:

import mysql.connector  # Import the mysql-connector library

# Establish a connection to the MySQL server
# Replace 'localhost', 'user', 'password', and 'database_name' with your MySQL server details
connection = mysql.connector.connect(
    host='localhost',        # Hostname of the MySQL server (e.g., 'localhost' or an IP address)
    user='your_username',    # Your MySQL username
    password='your_password',# Your MySQL password
    database='database_name' # The name of the database to connect to
)

# Create a cursor object to interact with the database
cursor = connection.cursor()

# Example: Execute an SQL query to create a new table
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INT
)
''')

# Example: Insert a new row into the 'users' table
cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))

# Commit the transaction to save changes
connection.commit()

# Example: Execute a query to fetch data from the 'users' table
cursor.execute('SELECT * FROM users')

# Fetch all rows from the result set
rows = cursor.fetchall()

# Loop through the rows and print each one
for row in rows:
    print(row)

# Close the cursor and connection to free up resources
cursor.close()
connection.close()

Another popular library used in Python to interact with MySQL databases is PyMySQL.

Before using PyMySQL, you need to install it via pip:

pip install PyMySQL

The use of PyMySQL in Python doesn’t differ significantly from the previously illustrated mysql-connector-python library. Both provide similar functionality for interacting with MySQL databases.

import pymysql  # Import the PyMySQL library

# Establish a connection to the MySQL server
# Replace 'localhost', 'user', 'password', and 'database_name' with your MySQL server details
connection = pymysql.connect(
    host='localhost',        # Hostname of the MySQL server (e.g., 'localhost' or an IP address)
    user='your_username',    # Your MySQL username
    password='your_password',# Your MySQL password
    database='database_name' # The name of the database to connect to
)

# Create a cursor object to interact with the database
cursor = connection.cursor()

# Example: Execute an SQL query to create a new table
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INT
)
''')

# Example: Insert a new row into the 'users' table
cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))

# Commit the transaction to save changes
connection.commit()

# Example: Execute a query to fetch data from the 'users' table
cursor.execute('SELECT * FROM users')

# Fetch all rows from the result set
rows = cursor.fetchall()

# Loop through the rows and print each one
for row in rows:
    print(row)

# Close the cursor and connection to free up resources
cursor.close()
connection.close()

PostgreSQL

PostgreSQL is a versatile database management system, akin to a Swiss Army knife. It’s highly sophisticated and capable of handling diverse tasks, ranging from traditional data storage to cutting-edge applications requiring complex data processing. Its popularity stems from several key attributes:

PostgreSQL exhibits exceptional robustness and resilience, demonstrating high fault tolerance and stability under various operational conditions. It implements advanced data integrity mechanisms and ensures ACID (Atomicity, Consistency, Isolation, Durability) compliance, safeguarding data accuracy and reliability. The system adheres rigorously to SQL standards, facilitating seamless integration and interoperability. PostgreSQL’s extensible architecture allows for the incorporation of custom functions, data types, and procedural languages, enhancing its adaptability to diverse use cases. Furthermore, it demonstrates remarkable scalability, efficiently managing increasing data volumes and concurrent user loads without compromising performance.

These technical attributes render PostgreSQL an optimal choice for both individual developers and large-scale enterprises seeking a database management system that combines reliability with high-performance capabilities.

PostgreSQL, like most traditional relational database management systems (RDBMS), requires installation on a local or remote server and employs a client-server architecture. This setup means your Python application (or any other client application) must establish a connection to the PostgreSQL server via TCP/IP or through a local Unix socket.

Psycopg2 is the most popular Python library for interacting with PostgreSQL. It must be installed using pip, Python’s package installer.

pip install psycopg2-binary

The use in Python is in sameway similar to the others libraries:

import psycopg2  # Import the psycopg2 library

# Establish a connection to the PostgreSQL server
# Replace 'localhost', 'user', 'password', and 'database_name' with your PostgreSQL server details
connection = psycopg2.connect(
    host='localhost',        # Hostname of the PostgreSQL server (e.g., 'localhost' or an IP address)
    port='5432',             # Port number (default is 5432 for PostgreSQL)
    user='your_username',    # Your PostgreSQL username
    password='your_password',# Your PostgreSQL password
    dbname='database_name'   # The name of the database to connect to
)

# Create a cursor object to interact with the database
cursor = connection.cursor()

# Example: Execute an SQL query to create a new table
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INT
)
''')

# Example: Insert a new row into the 'users' table
cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))

# Commit the transaction to save changes
connection.commit()

# Example: Execute a query to fetch data from the 'users' table
cursor.execute('SELECT * FROM users')

# Fetch all rows from the result set
rows = cursor.fetchall()

# Loop through the rows and print each one
for row in rows:
    print(row)

# Close the cursor and connection to free up resources
cursor.close()
connection.close()

SQLAlchemy

SQLAlchemy isn’t a database engine like MySQL, PostgreSQL, or SQLite. It doesn’t directly manage or store data. Rather, it offers a high-level interface for connecting to and interacting with various relational databases using Python code.

SQLAlchemy is an Object-Relational Mapping (ORM) library that offers a comprehensive toolkit for database interaction. It bridges the gap between object-oriented programming and relational databases, allowing developers to work with Python objects instead of writing raw SQL queries.

SQLAlchemy is database-agnostic. This means it can work with various database backends such as MySQL, PostgreSQL, SQLite, Oracle, and Microsoft SQL Server. It enables developers to write code that doesn’t depend on a specific database engine, making it easier to switch databases if necessary.

To use SQLAlchemy, install it via pip:

pip install SQLAlchemy

Example of code using SQLAlchemy:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# Create an engine that connects to an SQLite database file named 'example.db'
# You can replace 'sqlite:///example.db' with the connection string for other databases like PostgreSQL or MySQL
engine = create_engine('sqlite:///example.db', echo=True)

# Create a base class for our class definitions
Base = declarative_base()

# Define a User class that maps to the 'users' table in the database
class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)  # 'id' column with an integer type, set as the primary key
    name = Column(String, nullable=False)   # 'name' column with a string type, cannot be NULL
    age = Column(Integer)                   # 'age' column with an integer type

    def __repr__(self):
        return f"<User(name='{self.name}', age={self.age})>"

# Create the 'users' table in the database (if it doesn't exist already)
Base.metadata.create_all(engine)

# Create a configured "Session" class and a session object to interact with the database
Session = sessionmaker(bind=engine)
session = Session()

# Add a new user to the session
new_user = User(name='Alice', age=30)
session.add(new_user)

# Commit the session to save the new user to the database
session.commit()

# Query the database to retrieve all users
users = session.query(User).all()

# Print the retrieved users
for user in users:
    print(user)

# Close the session
session.close()

Additionally, numerous commercial Database Management Systems (DBMS) exist, each offering unique features tailored for specific use cases such as data warehousing, real-time analytics, high transaction volumes, or industry-specific needs. These commercial systems often provide enterprise-grade features, professional support, advanced security, and compliance tools—making them a preferred choice for large organizations where these factors are critical. However, they typically require licenses and come at a higher cost compared to open-source alternatives.

Among these are: Oracle Database – Oracle Database, Microsoft SQL Server – Microsoft SQL Server, IBM Db2 – IBM Db2, SAP HANA – SAP HANA, Teradata – Teradata, Amazon Aurora (Part of Amazon RDS) – Amazon Aurora, Snowflake – Snowflake, Oracle TimesTen – Oracle TimesTen, Couchbase – Couchbase, Vertica – Vertica

A winged child stands solemnly among medical-themed gravestones in a historic cemetery, with a stone church glowing in the background.

Spoon River Anthology by Edgar Lee Masters

Posted on August 12, 2024August 9, 2026 by Michele Danilo Pierri

The author of “Spoon River Anthology” Edgar Lee Masters was born on August 23, 1868, in Garnett, Kansas, but grew up in Lewistown and Petersburg, Illinois. His father was a lawyer, and despite Edgar’s literary inclinations, he followed in his father’s footsteps, studying law.

After practicing law in Chicago, Masters turned to literature, composing works that initially received little attention. His unexpected breakthrough came with the publication of “Spoon River Anthology” in 1915.

“Spoon River Anthology” revolutionized American poetry. It broke away from traditional rhyme schemes and regular meter, embracing free verse and a candid, straightforward narrative style.

The work comprises a collection of poems narrating the lives and deaths of residents in a small, fictional town. Each poem serves as an epitaph for a deceased character, unveiling secrets and sorrows never revealed during their lifetime.

Masters drew inspiration for the anthology from two main sources: real epitaphs he found in Midwestern cemeteries and the works of Lucian of Samosata, an ancient Greek writer famous for his fictional dialogues with the dead. The fictional town of Spoon River and its environs are based largely on Lewistown and Petersburg, Illinois—places where Masters grew up.

The anthology contains 244 epitaphs or poems, each telling the story of a deceased resident from the fictional village of Spoon River. These brief narratives explore the characters’ lives, emotions, secrets, and hardships, creating a complex and vivid portrait of the community.

From a medical standpoint, the anthology paints a stark, realistic picture of health conditions and diseases afflicting rural America in the late 19th and early 20th centuries. The collection explores into topics such as mental health, alcoholism, infant mortality, chronic illnesses, and how socioeconomic factors impact overall health.

Let’s examine these health conditions systematically.

Epitaph in Spoon River Anthology

Infectious Diseases and Contagion

  • Typhoid: Several poems mention typhoid, a prevalent disease in areas with poor sanitation. The frequent occurrence of such infectious diseases highlights the era’s limited understanding of hygiene and the lack of effective medical treatments.
  • Pneumonia and Tuberculosis: These respiratory diseases, often fatal in the pre-antibiotic era, appear in various epitaphs. Their frequent mention underscores the high death rate linked to lung infections during this period.
  • Measles: Remembered as a widespread illness that primarily affected children, measles was a significant cause of infant mortality.
Epitaph in Spoon River Anthology

Mental and Psychological Conditions

  • Depression and Suicide: Many characters’ epitaphs reveal their struggles with deep depression, which ultimately led to suicide. The anthology explores the devastating effects of loneliness, failure, and despair on mental health.
  • Psychiatric Disorders: Several epitaphs hint at characters deemed “mad” or “out of their minds,” highlighting the era’s limited understanding and pervasive stigma surrounding mental health issues.
  • Alcoholism: Alcohol abuse emerges as a recurring theme. Many characters recount how their lives were devastated by alcohol, often intertwining their struggles with depression, personal failures, and various illnesses.
Epitaph in Spoon River Anthology

Chronic and Degenerative Diseases

  • Heart Diseases: Many epitaphs mention heart attacks or cardiac ailments, highlighting cardiovascular diseases as a leading cause of death.
  • Diabetes: While not explicitly named, some characters describe symptoms associated with diabetes, such as limb amputation due to complications.
  • Kidney Diseases: Several epitaphs allude to kidney problems, with descriptions suggesting renal failure or related conditions.
Epitaph in Spoon River Anthology

Violent Deaths and Accidents

  • Murder and Lynching: Several characters describe their violent ends, often stemming from personal feuds, jealousy, or social injustice.
  • Workplace Accidents: The anthology exposes the era’s perilous working conditions, depicting deaths in factories and on farms. These accounts highlight the absence of adequate safety regulations.
  • War Casualties: Some epitaphs belong to war veterans or those who fell in battle, revealing both the physical toll and psychological scars of armed conflicts.
Epitaph in Spoon River Anthology

Maternal Health and Infant Mortality

  • Infant Mortality: Numerous epitaphs recount the deaths of newborns and young children. These poignant stories reflect the era’s high infant mortality rate, stemming from infectious diseases, malnutrition, and inadequate medical care.
  • Childbirth Complications: Several female characters describe their demise due to childbirth complications. Their tales highlight the perils of pregnancy and the scarcity of skilled obstetric care during this period.

Effects of Poverty

  • Malnutrition: Several characters hint at poverty and food scarcity as root causes of weakness and illness, highlighting the stark connection between socioeconomic status and health.
  • Limited Access to Medical Care: The scarcity of doctors and adequate healthcare facilities stands out as a primary factor in prolonged suffering and untimely deaths.

The anthology also references a medical error where a patient is given an incorrect dose of digitalis, resulting in cardiac arrest.

Epitaph in Spoon River Anthology

What really hits home is how raw and honest these stories are. Masters doesn’t sugarcoat anything. He shows us a place where getting proper medical care was a luxury, and where many people didn’t really understand what was making them sick. The characters’ tales bring to life the devastating impact of diseases, the shame associated with mental health problems, and the dangers lurking in everyday work.

But it’s not just about the illnesses themselves. The anthology digs deeper, showing how being poor or rich, respected or outcast, could determine whether you lived or died. It’s a stark reminder that health isn’t just about germs and medicine – it’s tied up with all aspects of life.

In a way, the “Spoon River Anthology” is like a time capsule. It bridges the gap between literature and medicine, giving us insights into health issues that we might not find in old medical textbooks or historical records. Through its poetic stories, we get a real sense of what it was like to live – and die – in rural America at that time.

At its heart, this book reminds us that behind every statistic about health and illness, there’s a human story. It shows us that understanding health isn’t just about studying diseases, but about understanding people’s lives, struggles, and resilience. That’s what makes the “Spoon River Anthology” more than just a great piece of literature – it’s a valuable tool for anyone wanting to understand how public health and medical care have evolved in rural America.

A nurse in an early 20th-century hospital ward holds a large horseshoe magnet over a patient lying in an iron bed, surrounded by vintage medical equipment.

Mozart aria “Eccovi il medico, signore belle”

Posted on July 31, 2024August 9, 2026 by Michele Danilo Pierri

Mozart aria “Here is yout doctor, lovely ladies”

“Here is yout doctor, lovely ladies” is an aria from the opera “Così fan tutte” by Wolfgang Amadeus Mozart.

The opera, composed between 1789 and 1790 with a libretto by Lorenzo Da Ponte, was first performed in Vienna on January 26, 1790. The full title is “Così fan tutte, ossia La scuola degli amanti,” and it is set in Naples . The plot centers on a bet between Don Alfonso and two young men, Guglielmo and Ferrando. Don Alfonso bets that the young men’s fiancées will not be faithful when tested. To prove his point, Don Alfonso organizes a series of deceptions with the help of the maid Despina.

In the opera’s second act, Don Alfonso convinces Guglielmo and Ferrando to disguise themselves as noble Albanians to test their fiancées’ fidelity. The two men pretend to be poisoned, and Despina, disguised as a doctor, enters to cure them.

The aria “Here is yout doctor, lovely ladies” introduces this moment. It plays on the absurdity of the situation and the satire of medical practices of the time. Additionally, this scene amplifies the theme of disguise and deception, which is central in “Così fan tutte”.

Text of the mozart aria "here is the doctor"

Historical context

The aria “Eccovi il medico, signore belle” is not just a comic moment in the opera; it is also a social commentary and a critique of 18th-century medical practices.

In the 18th century, medicine was undergoing a significant transition. On one hand, many practices were still based on superstitions and traditional remedies. On the other hand, more scientific medicine was emerging thanks to developments in anatomy, physiology, and chemistry.

At the far end of that spectrum stood the itinerant sellers of miracle remedies, whose theatrical performances Donizetti would immortalise a generation later in the figure of Dulcamara.

However, medicine was often seen as a mix of science and spectacle. Doctors had to balance their reputation between the effectiveness of treatments and their ability to gain patients’ trust through a certain degree of theatricality.

“if they are ill, they are certainly because of a love potion”

The phrase “because of a love potion” suggests a simplistic and romantic explanation for diseases, reflecting a pre-scientific view of medicine where emotions and external influences were often seen as causes. This conception remained common despite scientific progress.

“With this philosophical instrument, this device invented by the great Newton…”

The mention of the “philosophical instrument” and the “great Newton” introduces a parody of the scientific revolution. Isaac Newton, known for his discoveries in physics and mathematics, symbolizes the new era of science. However, Despina’s “magnet” is a ridiculous device with no real scientific basis, highlighting how many medical instruments of the time were more related to superstition than science.

“I will remove from the stomach, from the chest, and from the heart the witchcraft”

The description of Despina that “will remove from the stomach, chest, and heart the witchcraft” is an ironic reference to exorcistic and magical practices still used in some areas of folk medicine. This highlights the persistence of archaic beliefs in an era just beginning to better understand human physiology and pathology.

Mesmerism and Animal Magnetism

Mesmerism, or animal magnetism, was a theory and practice proposed by the German physician Franz Anton Mesmer in the late 18th century. Mesmer believed in a universal fluid that could be manipulated to cure diseases. He used magnets and later only his hands to direct this fluid into patients’ bodies, inducing trance states and seemingly miraculous healings.

During the 18th century, practices like mesmerism gained popularity due to their apparent effectiveness and the ability to tap into people’s desire for miraculous cures.

In the aria, Despina, disguised as a doctor, uses a “magnet” as a “philosophical instrument,” directly parodying mesmerism practices. This reflects a satire of Mesmer’s practices, which were very popular but also very controversial in Mozart’s time.


The history of medicine is full of theories and practices that were initially popular but later discredited. This still resonates today with many alternative and complementary practices that, despite their popularity, lack solid scientific foundations.

Mozart’s work is therefore not only entertainment but also a critical commentary on the medical practices and beliefs of the time. It highlights the tension between science and pseudoscience, emphasizing the importance of relying on evidence-based medical practices rather than popular and unscientific beliefs.

Ancient stone labyrinth with ornate carved pathways and a central spiral motif, illuminated by warm golden light.

Python Environments

Posted on July 30, 2024June 19, 2026 by Michele Danilo Pierri

Python has a rich standard library that covers basic functionalities and common tasks in programming. This includes modules for file handling, system operations, networking, and simple web development, allowing you to accomplish many tasks without additional tools. However, for more complex or specialized programs, you often need external libraries. These libraries significantly extend the program’s capabilities, enabling advanced data analysis, machine learning, scientific computing, and other specialized functions beyond what the standard library provides.

Most external Python libraries are found in a repository called PyPI (Python Package Index). It hosts thousands of libraries that can be installed in Python using the package manager “pip.”

On the PyPI site, you can search for libraries using filters or by taking advantage of the organization into categories. The filters allow you to narrow down your search based on parameters such as programming language, license type, and compatibility with different operating systems. Additionally, the categories help you find libraries specific to certain fields like web development, data science, or machine learning, making it easier to locate the tools you need for your project.

Besides PyPI, many libraries, especially those related to data science and scientific processing, are found on Conda systems (AnaConda and MiniConda), which use “conda” as a package manager.

Besides PyPI, many libraries, especially those related to data science and scientific processing, are found on Conda systems (AnaConda and MiniConda), which use “conda” as a package manager.

The Conda libraries are available on both Anaconda Cloud and Conda-Forge, containing useful packages for data science, machine learning, and bioinformatics.

Once the necessary library is identified, it can be installed and used in your Python application using a terminal command:

pip install name_library

or, in conda environment:

conda install name_library

Compared to PyPI, Conda offers more robust dependency and environment management, especially for libraries that need to be compiled or have system dependencies.


To build a Python project, especially if it is complex or highly specialized, we need to find and install the specific libraries. In a Python project, there can be dozens or even hundreds of external libraries.

Some libraries need other libraries to function, and so on, creating dependencies and dependencies of dependencies (or transitive dependencies), which can make the system even more complex.

It may happen that two libraries installed on our system have common dependencies for the same library, but in different versions. This situation can cause a conflict known as “dependency hell,” where the system struggles to satisfy the version requirements for both libraries. As a result, it can lead to issues in the functionality or stability of the software, making it difficult to manage and resolve these dependency conflicts.

Other times, there are libraries that work only with specific versions of Python.

These situations can become unmanageable if we use the same Python installation for all the applications we develop.

For these reasons, it is strongly recommended to create a “virtual environment” for each project or group of similar projects to “isolate” the libraries and avoid conflicts. A virtual environment is an “isolated” system consisting of a version of Python and all the libraries needed for a project (or a similar group of projects). We can create a dedicated virtual environment for each project.

The virtual environment is easily replicable. It can be reconstructed and regenerated on another system, facilitating collaboration and application deployment. Additionally, the environments can use different versions of Python for different projects.


The first step is to create a virtual environment to ensure dependencies and packages do not interfere with the system-wide Python environment. Once the virtual environment is set up, activate it to work within this isolated setup. Activation ensures that any installations or changes are contained within the virtual environment.

There are various ways to create virtual environments: one option is to use venv, which has been integrated into Python since version 3.3; the other option is using conda.

# The venv command is

python -m venv environment_name

# the conda command is

conda create -—name environment_name python= 3.X

Once the environment is created, it can be activated for use:

# in windows

environment_name\scripts\activate

# con conda

conda activate environment_name

# in linux or MacOS

source environment_name/bin/activate

With the activation of the environment changes occur. One primary change is that the prompt itself is modified. Specifically, the name of the activated environment appears at the beginning of the command line. This visual cue reminds the user that they are working within a particular environment, ensuring that commands and operations are executed in the correct context.

The environment can be deactivated with the command:

deactivate

# or, with conda

conda deactivate

Each time a virtual environment is created, a dedicated folder for the environment is made in the directory from which the environment was created. Typically, this is the directory where we will develop our program. This folder contains several subfolders that house various components of the virtual environment. These subfolders include executables, libraries, and scripts necessary for the isolated environment to function properly. By organizing these components within a specific directory, it ensures that the dependencies and packages used in one project do not interfere with those used in another. This approach not only prevents conflicts but also makes it easier to manage and replicate the environment on different systems.

The structure of these folders varies depending on whether you use a Windows or Linux/Mac OS environment.

On Windows:

folder structure of python environment in Window

On linux or Mac OS:

folder structure of python environment in Mac and Linux

The bin/ directory (in Linux/macOS) or Scripts/ (in Windows) contains the executables and scripts of the virtual environment, including the Python interpreter.

The lib/ folder (in Unix-MacOS) or Lib/ (in Windows) contains the libraries specific to the environment. In the site-packages/ subfolder, you will find all the installed Python packages.

The folders include/Include contain the header files for compiling Python packages that use the C or C++ languages.

pyvenv.cfg is a configuration file that stores information about the virtual environment.

Using Visual Studio Code as an IDE (Integrated Development Environment), you can issue commands directly from the integrated terminal window. Additionally, you can select the Python environment from the Command Palette. Access it through the menu by navigating to View and selecting Command Palette, or use the shortcut Ctrl+Shift+P. This flexibility allows for easy switching between different Python interpreters and environments, managing various projects and dependencies.


The creation of Python environments makes replication easy. To recreate a Python environment with all the installed libraries on another system, you first need a list of the libraries (including their versions) in the environment.

To do this, export the list of libraries and their versions to a requirements.txt file with the command:

pip freeze > requirement.txt

The structure of the requirements.txt file consists of a simple list of libraries and versions:

Example of requirements.txt

To replicate an environment on another system or after a reinstallation, create a new virtual environment, activate it, and install the libraries listed in the requirements.txt file.

# create e new virtuale environment

python -m venv new_env

# activate the new environment

new_env/Scripts/activate # in windows

source new_env/bin/activate # in linux MacOS

# intall all librarias listed in requirements.txt file

pip install -r requirements.txt

With Conda, the procedure differs slightly because a Conda environment can contain not only Python packages but also other configurations, such as dependencies required by different programming languages and various system libraries.

# Exporting environment dependencies

conda old_env export > requirements.yml

# Creation of a new environment using the exported dependencies

conda new_env create -f environment.yml

# Activation of the new environment

conda activate new_env

Essentially, the difference between replicating an environment with pip and conda is that conda uses the requirements.yml file, which includes system dependencies and other specifications. However, the purpose remains the same: exporting the configuration data of an environment and using it to recreate a similar environment.

  • Previous
  • 1
  • …
  • 4
  • 5
  • 6
  • 7
  • 8
  • Next
© 2024–2026 micheledpierri.com · Privacy Policy · Impressum