Skip to content

Note

Click here to download the full example code

correlations

an iron formation drilled by 187 diamond holes: hematite ore, compact (HC) and friable (HF), in itabirite, compact (IC) and friable (IF), with canga (CG), laterite (LAT) and mafic intrusions (MAF). every composite carries six oxides that share one whole, so they cannot vary independently. the correlations between them, and how fast those fade with distance, decide whether to estimate them together.

import sys
from pathlib import Path

HERE = Path(__file__).parent if "__file__" in globals() else Path.cwd()
sys.path.insert(0, str(HERE.parents[1]))
import boitata as bt
import matplotlib.pyplot as plt
import numpy as np
from common import save

data = bt.datasets.iron_formation_plateau()
intervals = bt.merge_intervals(data["assays"], data["lithology"])
holes = bt.Drillholes(data["collars"], data["surveys"], intervals)
OXIDES = ["FE_PCT", "SIO2_PCT", "AL2O3_PCT", "P_PCT", "MN_PCT", "LOI_PCT"]
composites = holes.composite(2.0, [*OXIDES, "DENSITY"], domain="LITH")
lith = composites["LITH"]
hematite = composites.filter(np.isin(lith, ["HC", "HF"]))
itabirite = composites.filter(np.isin(lith, ["IC", "IF"]))
print(f"{len(composites)} composites of 2 m: {len(hematite)} hematite, {len(itabirite)} itabirite")

Out:

24875 composites of 2 m: 7585 hematite, 13403 itabirite

correlation matrices

correlation returns the pearson or rank (spearman) correlation matrix of some columns, each pair over the rows where both are present, optionally weighted. plot.correlation draws it with every cell written out. the rank correlation is the safer one on skewed grades.

labels = ["Fe", "SiO₂", "Al₂O₃", "P", "Mn", "LOI"]
fig, axes = plt.subplots(1, 2, figsize=(10, 4), layout="constrained")
for ax, rock, name in zip(axes, [itabirite, hematite], ["Itabirite", "Hematite"], strict=True):
    r = bt.correlation(rock, columns=OXIDES, method="spearman")
    print(
        f"{name}, Fe against", "  ".join(f"{c} {v:+.2f}" for c, v in zip(labels[1:], r[0, 1:], strict=True))
    )
    bt.plot.correlation(rock, columns=OXIDES, labels=labels, method="spearman", colorbar=ax is axes[1], ax=ax)
    ax.set_title(f"{name}, Spearman")
save(fig, "correlation")

Itabirite, Spearman, Hematite, Spearman

Out:

Itabirite, Fe against SiO₂ -1.00  Al₂O₃ -0.17  P +0.05  Mn +0.15  LOI +0.24
Hematite, Fe against SiO₂ -0.63  Al₂O₃ -0.81  P -0.36  Mn -0.15  LOI -0.52

in itabirite, a banded rock of hematite and quartz, Fe and SiO₂ are opposed at -1.00: one oxide replaces the other, so SiO₂ adds nothing to Fe. in the hematite ore most of the silica is gone, and Fe falls instead with Al₂O₃ (-0.81) and LOI (-0.52), the clay and goethite that dilute it. the same six oxides relate differently in each rock, one more reason to estimate the two apart.

scatter-plot matrix

plot.scatter_matrix shows the pairs behind the numbers: scatters off the diagonal, histograms on it, and in each panel the pearson (r) and rank correlation of the pair. columns= picks and orders the columns. density was measured on only part of the composites, and each panel uses those where both of its values are present.

columns = ["FE_PCT", "AL2O3_PCT", "LOI_PCT", "DENSITY"]
print(f"density measured on {np.mean(~np.isnan(hematite['DENSITY'])):.0%} of the hematite composites")
fig, axes = bt.plot.scatter_matrix(hematite, columns=columns, labels=["Fe", "Al₂O₃", "LOI", "Density"])
fig.suptitle("Hematite composites", x=0.02, ha="left", fontweight="bold", fontsize=10)
save(fig, "scatter_matrix")

Hematite composites

Out:

density measured on 40% of the hematite composites

density splits into two groups that Fe does not separate: friable and compact hematite, alike in grade and unlike in density. density follows the rock type, so a regression of density on Fe would miss it.

plot.completeness counts the composites by how many of the columns they hold, the complete ones in color. plot.conditional draws the mean of one column and its P10 to P90 in bins of the other, each bin holding a tenth of the composites, which shows the relation that a dense scatter hides. Al₂O₃ falls steadily as Fe rises, and its spread narrows in the richest ore.

fig, (a, b) = plt.subplots(1, 2, figsize=(9, 3.4), layout="constrained")
bt.plot.completeness(hematite, columns=columns, ax=a)
a.set_title("Hematite composites by columns present")
bt.plot.conditional("FE_PCT", "AL2O3_PCT", data=hematite, ax=b)
b.set(title="Al₂O₃ given Fe, hematite", xlabel="Fe (%)", ylabel="Al₂O₃ (%)")
b.legend(loc="upper right")
save(fig, "completeness")

Hematite composites by columns present, Al₂O₃ given Fe, hematite

h-scatterplots

h_scatter gives the correlation of a grade with itself a lag apart. it pairs the composites separated by lag within tolerance, in any direction unless you give an azimuth, and returns the values at both ends with their correlation. as the lag grows the cloud widens and the correlation drops, the mirror image of the variogram rising.

fig, axes = plt.subplots(1, 3, figsize=(10, 3.4), layout="constrained", sharey=True)
for ax, lag in zip(axes, [2.0, 8.0, 32.0], strict=True):
    head, tail, r = bt.h_scatter(itabirite, "FE_PCT", lag, 0.1 * lag)
    print(f"h = {lag:>3.0f} m: {len(head):>6} pairs, correlation {r:.2f}")
    ax.hexbin(tail, head, gridsize=30, bins="log", linewidths=0)
    ax.set(title=f"h = {lag:g} m, ρ = {r:.2f}", xlabel="Fe at x (%)", aspect="equal")
axes[0].set_ylabel("Fe at x + h (%)")
save(fig, "h_scatter")

h = 2 m, ρ = 0.80, h = 8 m, ρ = 0.32, h = 32 m, ρ = 0.08

Out:

h =   2 m:  18924 pairs, correlation 0.80
h =   8 m:  21880 pairs, correlation 0.32
h =  32 m:  66886 pairs, correlation 0.08

Fe in itabirite correlates at 0.80 between neighboring composites, 0.32 at 8 m and 0.08 at 32 m. the bands that make the grade are thin, and beyond a few tens of meters a composite says little about the Fe of its neighbor. the variogram (experimental variograms) measures the same loss of correlation lag by lag.

Total running time of the script: ( 0 minutes 1.268 seconds)

Download Python source code: example_03_11.py

Download Jupyter notebook: example_03_11.ipynb

Gallery generated by mkdocs-gallery