Grouping Results¶
PyFIA supports grouping estimation results by various FIA classification columns. When you group by common columns like forest type or ownership, PyFIA automatically adds descriptive name columns to make results more readable.
Basic Grouping¶
Use the grp_by parameter to group results:
from pyfia import FIA, volume, area
db = FIA("georgia.duckdb")
db.clip_by_state("GA")
# Group volume by forest type
result = volume(db, grp_by="FORTYPCD")
# Group area by ownership
result = area(db, grp_by="OWNGRPCD")
# Group by multiple columns
result = volume(db, grp_by=["FORTYPCD", "OWNGRPCD"])
Auto-Enhanced Columns¶
PyFIA automatically adds descriptive name columns for common grouping variables:
| Grouping Column | Auto-Added Column | Example Values |
|---|---|---|
FORTYPCD |
FOREST_TYPE_GROUP |
"Loblolly/Shortleaf Pine", "Oak/Hickory" |
OWNGRPCD |
OWNERSHIP_GROUP |
"Private", "Forest Service", "State and Local Government" |
Example Output¶
result = volume(db, grp_by="FORTYPCD", totals=True)
print(result.columns)
# ['YEAR', 'FORTYPCD', 'FOREST_TYPE_GROUP', 'VOLCFNET_TOTAL', 'VOLCFNET_ACRE', ...]
The output includes both the original code (FORTYPCD) and the descriptive name (FOREST_TYPE_GROUP):
| FORTYPCD | FOREST_TYPE_GROUP | VOLCFNET_TOTAL |
|---|---|---|
| 161 | Loblolly/Shortleaf Pine | 15,913,000,000 |
| 503 | Oak/Hickory | 8,592,600,000 |
| 701 | Oak/Gum/Cypress | 2,145,000,000 |
Ownership Groups¶
| OWNGRPCD | OWNERSHIP_GROUP | AREA |
|---|---|---|
| 10 | Forest Service | 858,952 |
| 20 | Other Federal | 1,014,500 |
| 30 | State and Local Government | 909,473 |
| 40 | Private | 21,390,000 |
Species Names¶
Species names require database access and are not auto-enhanced. Use join_species_names() after estimation:
from pyfia import volume, join_species_names
# Group by species
result = volume(db, by_species=True)
# Add species names from reference table
result = join_species_names(result, db)
print(result.head())
| SPCD | COMMON_NAME | VOLCFNET_TOTAL |
|---|---|---|
| 131 | Loblolly pine | 8,234,000,000 |
| 316 | Red maple | 1,456,000,000 |
| 802 | White oak | 987,000,000 |
Reference Table Functions¶
For columns that aren't auto-enhanced, use the reference table functions:
from pyfia import (
join_species_names,
join_forest_type_names,
join_state_names,
join_multiple_references,
)
# Add species names
result = join_species_names(result, db)
# Add forest type names (if FORTYPCD present but not auto-enhanced)
result = join_forest_type_names(result, db)
# Add state names
result = join_state_names(result, db)
# Add multiple references at once
result = join_multiple_references(
result, db,
species=True,
forest_type=True,
state=True
)
Convenience Flags¶
Some estimators support convenience flags for common groupings:
# Group by species
result = volume(db, by_species=True)
# Group by size class (available for tpa, volume, biomass, mortality, growth, removals)
result = tpa(db, by_size_class=True)
result = mortality(db, by_size_class=True)
result = growth(db, by_size_class=True)
result = removals(db, by_size_class=True)
Size Class Types¶
For estimators that support by_size_class, you can choose the classification system:
from pyfia import mortality, growth, removals
# Standard FIA size classes (default)
# Categories: 1.0-4.9, 5.0-9.9, 10.0-19.9, 20.0-29.9, 30.0+
result = mortality(db, by_size_class=True, size_class_type="standard")
# Descriptive labels
# Categories: Saplings, Small, Medium, Large
result = mortality(db, by_size_class=True, size_class_type="descriptive")
# Timber market categories (TimberMart-South style)
# All species: Pre-merchantable (< 5" DBH)
# Pine: Pulpwood (5-8.9"), Chip-n-Saw (9-11.9"), Sawtimber (12"+)
# Hardwood: Pulpwood (5-10.9"), Sawtimber (11"+)
result = removals(db, by_size_class=True, size_class_type="market")
# Include pre-merchantable trees (requires tree_type="live")
result = mortality(
db,
tree_type="live", # Include all live trees, not just growing stock
by_size_class=True,
size_class_type="market"
)
The "market" size class type uses species-aware thresholds that align with timber pricing reports. Note that pre-merchantable trees (< 5" DBH) require tree_type="live" since growing stock defaults to ≥5" DBH.
Combining Groupings¶
You can combine multiple grouping columns:
# Volume by forest type and ownership
result = volume(db, grp_by=["FORTYPCD", "OWNGRPCD"])
# Both auto-enhanced columns are added
print(result.columns)
# [..., 'FORTYPCD', 'FOREST_TYPE_GROUP', 'OWNGRPCD', 'OWNERSHIP_GROUP', ...]
Geographic and Administrative Groupings¶
PyFIA supports grouping by geographic and administrative units from the PLOT table:
from pyfia import volume, mortality
# Group by FIA survey unit
result = volume(db, grp_by="UNITCD")
# Group by county
result = volume(db, grp_by="COUNTYCD")
# Group by state and county
result = volume(db, grp_by=["STATECD", "COUNTYCD"])
# Group by state and survey unit (common for regional analysis)
result = mortality(db, grp_by=["STATECD", "UNITCD"])
Available Plot-Level Columns¶
| Column | Description |
|---|---|
STATECD |
FIPS state code |
COUNTYCD |
FIPS county code |
UNITCD |
FIA survey unit code |
INVYR |
Inventory year |
CYCLE |
Inventory cycle number |
SUBCYCLE |
Inventory subcycle number |
Plot-Condition Level Grouping¶
You can group by PLT_CN and CONDID to get plot-condition level estimates. This is useful for linking pyFIA estimates to external plot-level models (e.g., harvest probability predictions, growth models).
from pyfia import FIA, biomass
with FIA("georgia.duckdb") as db:
db.clip_by_evalid(132301)
# Plot-condition level biomass
result = biomass(db, grp_by=["PLT_CN", "CONDID", "FORTYPCD"])
# Returns one row per plot-condition with biomass estimate
Each row represents a single plot-condition's contribution to the population estimate. This enables direct integration with external models keyed by PLT_CN + CONDID without needing raw SQL.
Mortality-Specific Groupings¶
For mortality estimation, you can group by cause of death:
from pyfia import mortality
# Group by mortality agent (tree-level cause of death)
result = mortality(db, grp_by="AGENTCD")
# AGENTCD: 10=Insect, 20=Disease, 30=Fire, 50=Weather, etc.
# Group by disturbance code (condition-level)
result = mortality(db, grp_by="DSTRBCD1")
# DSTRBCD1: 30=Fire, 52=Hurricane/wind, 54=Drought, etc.
# Combined grouping for detailed analysis
result = mortality(db, grp_by=["AGENTCD", "SPCD"])
# Combine mortality cause with geographic grouping
result = mortality(db, grp_by=["STATECD", "UNITCD", "AGENTCD"], variance=True)
This is useful for timber casualty loss analysis where losses must be classified by cause for tax purposes.
Summary¶
| Column | Auto-Enhanced? | Manual Function | Source Table |
|---|---|---|---|
FORTYPCD |
Yes | join_forest_type_names() |
COND |
OWNGRPCD |
Yes | N/A | COND |
SPCD |
No | join_species_names() |
TREE |
STATECD |
No | join_state_names() |
PLOT |
COUNTYCD |
No | N/A | PLOT |
UNITCD |
No | N/A | PLOT |
INVYR |
No | N/A | PLOT |
PLT_CN |
No | N/A | TREE/COND (plot-condition detail) |
CONDID |
No | N/A | TREE/COND (plot-condition detail) |
AGENTCD |
No | N/A | TREE (mortality only) |
DSTRBCD1 |
No | N/A | COND (mortality only) |