Computation for Linguists

Pandasmonium: Day 4

Dr. Andrew M. Byrd

2025-10-24

Review

  • What did you learn last time?

Recap from Last Time

  • Modifying DataFrame()s
    • .concat(), .drop(), .rename(), .reset_index()
    • .sort_index(), .sort_values(ascending=False)
    • .fillna(0)
  • Adding:
    • columns: df[series_1].add(df[series_2])
    • rows: df.sum()

Review Activity

  • Import the following data as a .DataFrame(), setting the “Language” Series as the index.
import pandas as pd

stops = {
    "Language": ["English", "Spanish", "Hindi"],
    "Nasals": [3, 3, 4],
    "Oral Stops": [6, 6, 5]
}
  • Use .sum() to find the total number of nasals & oral stops.
  • Use .add() to combine the number of nasals and oral stops in each language.

Reading & Writing csv and xls files

Writing a csv file

  • df.to_csv("file_name.csv", index=False)
    • What happens when index=True?
import pandas as pd

# Create the data
data = {
    "Consonant": ["p", "b", "t", "d", "k", "g", "s", "z", "m", "n", "l", "r", "w", "j", "h"],
    "Place": ["bilabial", "bilabial", "alveolar", "alveolar", "velar", "velar",
              "alveolar", "alveolar", "bilabial", "alveolar", "alveolar", "alveolar",
              "labial-velar", "palatal", "glottal"],
    "Manner": ["stop", "stop", "stop", "stop", "stop", "stop",
               "fricative", "fricative", "nasal", "nasal", "lateral", "trill",
               "glide", "glide", "fricative"],
    "Voicing": ["voiceless", "voiced", "voiceless", "voiced", "voiceless", "voiced",
                "voiceless", "voiced", "voiced", "voiced", "voiced", "voiced",
                "voiced", "voiced", "voiceless"]
}

# Create DataFrame
df = pd.DataFrame(data)

# Show DataFrame
print(df)

# Save to CSV
df.to_csv("conlang_c.csv", index=False)

.csv Activity:

  • Convert the stops df from the Review Activity into a .csv file

Writing to Excel:

  • You can also write Excel files, but you have to pip install openpyxl first.
import openpyxl
import pandas as pd

data = {
    "Consonant": ["p", "b", "t", "d", "k", "g", "s", "z", "m", "n", "l", "r", "w", "j", "h"],
    "Place": ["bilabial", "bilabial", "alveolar", "alveolar", "velar", "velar",
              "alveolar", "alveolar", "bilabial", "alveolar", "alveolar", "alveolar",
              "labial-velar", "palatal", "glottal"],
    "Manner": ["stop", "stop", "stop", "stop", "stop", "stop",
               "fricative", "fricative", "nasal", "nasal", "lateral", "trill",
               "glide", "glide", "fricative"],
    "Voicing": ["voiceless", "voiced", "voiceless", "voiced", "voiceless", "voiced",
                "voiceless", "voiced", "voiced", "voiced", "voiced", "voiced",
                "voiced", "voiced", "voiceless"]
}

# Create DataFrame
df = pd.DataFrame(data)

df.to_excel("conlang_c.xlsx", index=False)

.xlsx Activity:

  • Convert the stops df from the Review Activity into a .xlsx file

Reading .csv and .xlsx

stops_csv_df = pd.read_csv("conlang_c.csv")
stops_csv_df.head()

print("\n-------------------------------------\n")

stops_excel_df = pd.read_excel("conlang_c.xlsx")
stops_excel_df.head()

Activity:

  • Now read both of your newly created .csv and .xlsx files in a pandas df

Grouping & Aggregation

Grouping & Aggregation

  • Let’s create a new df
ref_df = pd.DataFrame({
    "Language": ["Latin","Greek","Sanskrit","Gothic","OCS","Oscan"],
    "Family":   ["Italic","Hellenic","Indic","Germanic","Slavic","Italic"],
    "Reflexes": [8,10,12,4,3,5]
})

Grouping & Aggregation

  • We’ve already used .sum()
  • This adds all of the values of a Series together
int(ref_df["Reflexes"].sum())

Grouping & Aggregation

  • We can also use .sum() to add .Series() together by a certain property
  • Use the method .groupby()
ref_df.groupby("Family")["Reflexes"].sum()

Grouping & Aggregation

  • The method .agg aggregates – it collects different types of mathematical operations:
    • .sum() – total reflexes per family
    • .mean() – average reflexes per family
    • count – number of languages in that family.
ref_df.groupby("Family").agg(
    total=("Reflexes","sum"),
    mean=("Reflexes","mean"),
    n=("Reflexes","count")
)

Activity: Aggregation

  • Copy the following code:
import pandas as pd

df = pd.DataFrame({
    "Language": ["English","German","Dutch","Spanish","Italian","French","Greek","Hindi","Bengali"],
    "Family":   ["Germanic","Germanic","Germanic","Romance","Romance","Romance","Hellenic","Indic","Indic"],
    "Consonants": [24, 25, 20, 17, 23, 22, 25, 33, 29],
    "Vowels": [20, 16, 13, 5, 7, 15, 7, 11, 7]
})

Activity:

Using .agg(), calculate:

  1. Find the average number of consonants and vowels per family:
  2. Find the total number of consonants and vowels per family.
  3. The number of languages in each family.
  • Hint:
    • Use .groupby("Family")
    • Narrow your df to just [["Consonants","Vowels"]]

Our First Visualization

Install one more library

PC:

pip install matplotlib  # python -m pip install matplotlib

Mac:

pip3 install matplotlib # python3 -m pip3 install matplotlib

Creating our First Visualization

import matplotlib.pyplot as plt

counts = ref_df.groupby("Family")["Reflexes"].sum()
ax = counts.plot(kind="bar", title="Reflex Counts by Family")
ax.set_xlabel("Family")
ax.set_ylabel("Total Reflexes")

plt.tight_layout()   # optional, avoids label cutoff
plt.show()           # displays the plot

Activity: Visualization

  • Copy the following code, which will import conlang_c.csv and will count the number of stops by place of articulation.
import matplotlib.pyplot as plt

con_c_df = pd.read_csv("conlang_c.csv")
stops_df = con_c_df[(con_c_df["Manner"] == "stop")]

stop_counts = stops_df["Place"].value_counts().sort_index()
stop_counts

Activity: Visualization

  • Use matplotlib.pyplot to create a bar chart that shows the number of Cs by place of articulation.
    • x axis == “Place”
    • y axis == “Number of Consonants”

Appendix — Reference Guide for pd

Selection Cheatsheet

  • Columns: df["col"], df[["col1","col2"]]
  • Rows (position): df.iloc[0], df.iloc[1:3]
  • Rows (label): df.loc["a"], df.loc["a":"c"]
  • Cell: df.loc["a","col"] or df.iloc[0, 1]
  • Filter: df[df["col"] == value], df[(cond1) & (cond2)]

Common Operations

df.rename(columns={"old":"new"})
df.drop(columns=["col"])
df.set_index("col")
df.reset_index(drop=True)
df.sort_values(by="col", ascending=False)
df.isna().sum()
df.fillna(0)

Alignment & Combining

s1.add(s2, fill_value=0)
pd.concat([df1, df2], axis=0, ignore_index=True)  # vertical
pd.concat([s1, s2], axis=1)                       # side-by-side