How to Group Meteorite Classes into Stony, Iron and Stony-Iron

On this page

Problem statement

The recclass column of NASA's Meteorite Landings table holds 466 different labels: L6, H5, CM2, "Iron, IIIAB", Eucrite-pmict, Martian (shergottite), Pallasite, and hundreds more used a handful of times. A chart with 466 categories says nothing, and the labels follow a scientific scheme rather than a tidy hierarchy: a letter for the chemical group, a digit for how much the rock was heated, and words for everything that fits no scheme. This page maps every label to a few groups a reader can follow, checks what the rules catch wrongly, and compares the groups' shares among falls, finds and mass.

Quick answer

Test the label's prefix in order, from the most specific names to the single letters:

def group(c):
    if pd.isna(c): return "unknown"
    if c.startswith("Iron"): return "iron"
    if c.startswith(("Pallasite", "Mesosiderite")): return "stony-iron"
    if c.startswith(("Martian", "Lunar")): return "Mars and Moon"
    if c.startswith(("Eucrite", "Diogenite", "Howardite", "Ureilite", "Aubrite", "Angrite", "Acapulcoite", "Lodranite", "Winonaite", "Brachinite", "Achondrite")): return "achondrite"
    if c.startswith("Chondrite"): return "other chondrite"
    if c.startswith(("H", "L", "OC")): return "ordinary chondrite"
    if c.startswith("C"): return "carbonaceous chondrite"
    if c.startswith(("E", "R", "K")): return "other chondrite"
    return "unknown"

met["group"] = met.recclass.map(group)
print(met.group.value_counts().to_string())
group
ordinary chondrite        39843
achondrite                 1831
carbonaceous chondrite     1584
iron                       1069
other chondrite             761
Mars and Moon               284
stony-iron                  281
unknown                      63

Ordinary chondrites are 39,843 of the 45,716 meteorites, nearly nine in ten. Achondrites, rocks melted on their parent asteroid, are 1,831, carbonaceous chondrites 1,584 and irons 1,069. 284 come from Mars or the Moon and 281 are stony-irons. The order of the tests matters: "Howardite" starts with H and "Lunar" with L, so the named classes have to be tested before the single letters, and "Chondrite-ung" starts with C.

Horizontal bars on a log scale of meteorites by group: ordinary chondrites 39,843, achondrites 1,831, carbonaceous chondrites 1,584, irons 1,069, down to 63 unknown. Horizontal bars on a log scale of meteorites by group: ordinary chondrites 39,843, achondrites 1,831, carbonaceous chondrites 1,584, irons 1,069, down to 63 unknown.
Meteorites by group.

What the labels encode

1. 466 labels

print(f"distinct recclass values: {met.recclass.nunique()}; used once: {(met.recclass.value_counts() == 1).sum()}")
print(met.recclass.value_counts().head(8).to_string())
distinct recclass values: 466; used once: 145
recclass
L6     8285
H5     7142
L5     4796
H6     4528
H4     4211
LL5    2766
LL6    2043
L4     1253

145 of the 466 labels are used by one meteorite only. The eight most common are all ordinary chondrites, L6 with 8,285 and H5 with 7,142 first. H, L and LL say how much iron the rock holds, high, low and low-iron low-metal, and the digit from 3 to 7 how strongly it was heated inside its asteroid.

2. What the prefix rules catch wrongly

for g_ in ["ordinary chondrite", "other chondrite", "unknown"]:
    print(g_, met.loc[met.group == g_, "recclass"].value_counts().head(6).to_dict())
ordinary chondrite {'L6': 8285, 'H5': 7142, 'L5': 4796, 'H6': 4528, 'H4': 4211, 'LL5': 2766}
other chondrite {'E3': 206, 'EH3': 120, 'EL6': 72, 'Relict OC': 65, 'R4': 42, 'R5': 20}
unknown {'Stone-uncl': 50, 'Unknown': 7, 'Fusion crust': 4, 'Impact melt breccia': 1, 'Stone-ung': 1}

Look at what lands in each group, not only the counts. The ordinary chondrite group holds what it should. "Other chondrite" collects the enstatite chondrites (E3, EH3, EL6), the R chondrites, and 65 "Relict OC", ordinary chondrites so weathered that only their chromite grains survive; keep them out of an ordinary-chondrite count if you are comparing chemistry. "Unknown" is 50 "Stone-uncl", stones never classified, and a few labels such as "Fusion crust", which describe a fragment rather than a meteorite type.

3. Ordinary chondrites by type

oc = met[met.group == "ordinary chondrite"]
chem = oc.recclass.str.extract(r"^(LL|L|H)")[0]
petro = oc.recclass.str.extract(r"^(?:LL|L|H)(\d)")[0]
print(pd.crosstab(chem.rename("chemical group"), petro.rename("petrologic type")).to_string())
petrologic type    3     4     5     6   7
chemical group                            
H                839  4782  7427  4534  12
L                841  1375  4971  8359  21
LL               319   318  2855  2053  23

Split into chemical group and petrologic type, the ordinary chondrites show their structure. H chondrites peak at type 5, with 7,427, and L chondrites at type 6, with 8,359. Type 3, the least heated and most prized by researchers, is 839 H and 841 L. The extraction misses labels such as "H/L3" and "OC", which are left out of the table rather than forced into a cell.

Grid of ordinary chondrites by chemical group H, L and LL and petrologic type 3 to 7, with the largest cells L6 at 8,359 and H5 at 7,427. Grid of ordinary chondrites by chemical group H, L and LL and petrologic type 3 to 7, with the largest cells L6 at 8,359 and H5 at 7,427.
Ordinary chondrites by chemical group and petrologic type.

Groups among falls, finds and mass

The data used on this page

NASA's Meteorite Landings table from The Meteoritical Society's records (last updated May 2013), saved on this site on 28 October 2026. The class names follow the Society's scheme as recorded in the table; the groups are this page's own.

from pathlib import Path
import json
import zipfile

import geopandas as gpd
import numpy as np
import pandas as pd
import requests

Path("data").mkdir(exist_ok=True)
# NASA's Meteorite Landings table (The Meteoritical Society's records as NASA last updated them, May 2013), every
# fireball in NASA/JPL's Fireball Data API, and Natural Earth's countries and land. Saved 28 October 2026.
# Live: https://data.nasa.gov/docs/legacy/meteorite_landings/Meteorite_Landings.csv
#       https://ssd-api.jpl.nasa.gov/fireball.api?vel-comp=true
ARCHIVE = "nasa-meteorites-2026-10-28.zip"
if not Path(f"data/{ARCHIVE}").exists():
    Path(f"data/{ARCHIVE}").write_bytes(requests.get(f"https://data.spatialworkflow.io/{ARCHIVE}", timeout=600).content)
Z = zipfile.ZipFile(f"data/{ARCHIVE}")
met = pd.read_csv(Z.open("Meteorite_Landings.csv")).rename(columns={"mass (g)": "mass_g"})
for f in ["ne_110m_admin_0_countries.zip", "ne_50m_land.zip"]:
    Path(f"data/{f}").write_bytes(Z.read(f))
print(f"Meteorite Landings: {len(met):,} meteorites")
Meteorite Landings: 45,716 meteorites

Example 1: groups among falls and finds

print(pd.crosstab(met.group, met.fall, normalize="columns").mul(100).round(1).to_string())
fall                    Fell  Found
group                              
Mars and Moon            0.5    0.6
achondrite               7.3    3.9
carbonaceous chondrite   4.0    3.5
iron                     4.4    2.3
ordinary chondrite      77.3   87.4
other chondrite          1.7    1.7
stony-iron               1.0    0.6
unknown                  3.8    0.0

As a share of witnessed falls, irons are 4.4% and achondrites 7.3%, against 2.3% and 3.9% of finds. Finds are dominated by ordinary chondrites, 87.4%, because the ice and desert harvests collect thousands of small chondrite stones. 3.8% of falls are "unknown", almost all "Stone-uncl": stones that fell long ago, most of them before 1900, and were never classified. A find is classified before it enters the table, so the group is empty for finds.

Paired horizontal bars of each group's share of falls and of finds: achondrites 7.3% against 3.9%, irons 4.4% against 2.3%, unknown 3.8% against 0.0%. Paired horizontal bars of each group's share of falls and of finds: achondrites 7.3% against 3.9%, irons 4.4% against 2.3%, unknown 3.8% against 0.0%.
Each group's share of witnessed falls and of finds, ordinary chondrites left out.

Example 2: groups by mass

t = met.groupby("group").mass_g.agg(["median", "sum"])
t["share of mass"] = (t["sum"] / t["sum"].sum()).map(lambda v: f"{v:.1%}")
print(t.drop(columns="sum").sort_values("median", ascending=False).round(1).to_string())
                         median share of mass
group                                        
iron                    10000.0         85.0%
unknown                  1257.5          0.1%
stony-iron                496.2          3.4%
Mars and Moon              94.9          0.0%
achondrite                 88.3          1.0%
ordinary chondrite         28.7          9.8%
carbonaceous chondrite     25.2          0.6%
other chondrite            17.9          0.2%

By mass the picture turns over. Irons are 2.3% of meteorites but 85.0% of all the recorded mass, and the median iron weighs 10 kg against 28.7 g for an ordinary chondrite. Iron survives the fall through the atmosphere in large pieces and survives weathering on the ground, so the heavy end of the record is almost all iron. A count of meteorites and a weight of meteorites answer different questions.

Paired horizontal bars of share of meteorites against share of mass: irons are 2.3% of meteorites and 85.0% of the mass, ordinary chondrites 87.2% and 9.8%. Paired horizontal bars of share of meteorites against share of mass: irons are 2.3% of meteorites and 85.0% of the mass, ordinary chondrites 87.2% and 9.8%.
Share of meteorites against share of the recorded mass.