geoml.data.drillhole
- class geoml.data.drillhole.DrillholeData(collar, survey=None, hole='HOLEID', x='X', y='Y', z='Z', length=None, dip=None, azimuth=None, depth='DEPTH', dip_positive_down=True)[source]
Bases:
_SpatialDataDrillhole data: a set of collars, their traces, and any number of interval tables.
This object is not fed to a model. It is a staging area in which the raw files are checked, desurveyed and composited, and from which point data is produced with as_point_data() or as_classification_input().
The hole path is computed by minimum curvature from the survey table. Holes with no survey are taken as straight, following the collar dip and azimuth, or vertical if those are absent.
- collar
Indexed by hole, with the X, Y and Z coordinates, the hole LENGTH, and the fallback DIP and AZIMUTH.
- Type:
DataFrame
- intervals
Name to IntervalTable.
- Type:
dict
- __init__(collar, survey=None, hole='HOLEID', x='X', y='Y', z='Z', length=None, dip=None, azimuth=None, depth='DEPTH', dip_positive_down=True)[source]
Initializer for DrillholeData.
- Parameters:
collar (DataFrame) – One row per hole, with its coordinates.
survey (DataFrame) – Downhole survey stations. Optional.
hole (str) – Column with the hole name, in every table.
x (str) – Columns in collar with the coordinates.
y (str) – Columns in collar with the coordinates.
z (str) – Columns in collar with the coordinates.
length (str) – Column in collar with the total length of the hole. Optional, but needed to check intervals running past the end of a hole.
dip (str) – Columns with the attitude, in collar (as a fallback for holes with no survey) and in survey.
azimuth (str) – Columns with the attitude, in collar (as a fallback for holes with no survey) and in survey.
depth (str) – Column in survey with the depth of each station.
dip_positive_down (bool) – Whether a positive dip points downwards, as in the rest of geoML. Databases recording downward holes as negative need False here.
add_intervals(). (Interval tables are added afterwards with)
- property n_holes
- add_intervals(name, data, on_error='warn', **kwargs)[source]
Adds an interval table.
- Parameters:
name (str) – A label for the table, used to refer to it later.
data (DataFrame or IntervalTable) – The interval file. A data frame is passed to IntervalTable along with the remaining arguments.
on_error (str) – Passed to IntervalTable.validate(): “warn”, “raise” or “ignore”.
- Returns:
self, so that calls can be chained.
- Return type:
- rename(table, columns)[source]
Renames columns of one of the interval tables.
The roles travel with the columns; see IntervalTable.rename(). This is the way to tidy the names of a database that was built for you — by datasets.macpass(), say — where the data frames were never in reach.
- Parameters:
table (str) – Name of the interval table.
columns (dict) – Maps each current column name to its new one.
- Returns:
self, so that calls can be chained.
- rename_table(name, new_name)[source]
Renames an interval table, keeping its position.
- Parameters:
name (str) – The table’s current name.
new_name (str) – What to call it instead.
- Returns:
self, so that calls can be chained.
- Return type:
- drop_table(name)[source]
Removes an interval table.
- Parameters:
name (str) – The table to remove.
- Returns:
self, so that calls can be chained.
- Return type:
- coordinates_at(holes, depths)[source]
The coordinates of the given depths in the given holes.
- Parameters:
holes (array) – Hole name of each point.
depths (array) – Depth of each point along its hole.
- Returns:
coordinates (array) – An (n_points, 3) array. Holes with no collar give NaN.
- Return type:
ndarray
- composite(length=1.0, domain=None)[source]
Composites every interval table onto a common support.
Runs of the given length are laid out along each hole and every table is aggregated onto them, so the tables come out sharing one support and can be merged row for row by as_point_data().
Numeric columns are averaged weighted by length, or by length times density where the table declares a density column, skipping missing values. Categories are decided by the greatest length within the run. A run shorter than length is kept whole and the residual of a longer one is merged into its last run, so no stubs are produced.
- Parameters:
length (float) – The length of the composites.
domain (str or tuple) – A categorical column whose boundaries the composites must honour, given as a table name, a column name, or a (table, column) pair. Without it the runs ignore geology, which smears contacts.
- Returns:
drillholes (DrillholeData) – A new object with the same collars and traces.
- Return type:
- composite_fixed(length=1.0)[source]
Composites onto runs of fixed length, ignoring any geology.
The same as composite() with no domain; kept as a separate name because ignoring domain boundaries is a deliberate choice.
- Return type:
- composite_to(table)[source]
Composites every table onto the intervals of one of them.
This is the way to bring assays onto the geological intervals that were logged, rather than onto an arbitrary run length.
- Parameters:
table (str or IntervalTable) – The table whose intervals become the support.
- Return type:
- merge_domains(domain)[source]
Merges touching intervals sharing a category into single runs.
- Parameters:
domain (str or tuple) – The categorical column, as in composite().
- Returns:
table (IntervalTable) – A table with one interval per run.
- subset_holes(holes)[source]
The given holes only, with everything logged in them.
- Parameters:
holes (str or list) – The names of the holes to keep.
- Returns:
drillholes (DrillholeData) – A new object with the selected collars, their traces, and every interval table cut down to them.
- subset_region(min_val, max_val)[source]
The holes whose collar falls within a bounding box.
The box is applied to the collars, not to the individual intervals, so a hole is kept or dropped whole: a deviated hole that wanders out of the box still comes through entire. Both bounds are inclusive.
- Parameters:
min_val (array) – Opposite corners of the box, as [x, y] or [x, y, z]. Two values select in plan view, which is the usual way to carve out an area. The min and max of a BoundingBox can be passed directly.
max_val (array) – Opposite corners of the box, as [x, y] or [x, y, z]. Two values select in plan view, which is the usual way to carve out an area. The min and max of a BoundingBox can be passed directly.
- Returns:
drillholes (DrillholeData)
- filter_intervals(table, column, values, whole_holes=False)[source]
The intervals whose column holds one of the given values.
- Parameters:
table (str) – The interval table to filter.
column (str) – The column to look at.
values (object or list) – The values to keep.
whole_holes (bool) – Whether to keep every hole containing a matching interval, with all of its data, rather than the matching intervals alone. Cutting the intervals themselves leaves the tables on different supports, so the result has to be composited again before as_point_data(); with whole_holes nothing is cut but the holes.
- Returns:
drillholes (DrillholeData)
- category_legend(domain)[source]
The distinct values of a categorical column, and how much each holds.
See IntervalTable.category_legend(). The column is named as in composite().
- group_categories(domain, groups, new_column=None, other=None)[source]
Lumps the values of a categorical column into fewer categories.
See IntervalTable.group_categories(). The column is named as in composite().
- Returns:
drillholes (DrillholeData) – A new object, with the table holding the column replaced.
- fill_unlogged(domain, label, ends=True)[source]
Gives the ground a log does not account for a category of its own.
Where only the intervals of interest are logged – the mineralised ones, say – everything else is left implicit, and a model has no way of knowing it was called anything. This makes the statement explicit, so the unlogged ground can be modelled as the waste it is, in the two ways it can be missing:
Intervals that exist but carry no value, which take label.
Depths no interval covers, which become new intervals carrying label and nothing else. With ends this reaches from the collar to the bottom of the hole, so a hole with no intervals at all comes out logged from end to end.
The result covers each hole continuously, so validate() finds no gaps in it. The table changes support, though, so the object has to be composited again before as_point_data().
- Parameters:
domain (str or tuple) – The categorical column, as in composite().
label (str) – The category to give the unlogged ground. Required: it asserts something about the rock that nobody wrote down.
ends (bool) – Whether to fill from the collar down to the first interval and from the last one to the bottom of the hole. The bottom is the LENGTH in the collar table, so holes with no recorded length keep whatever runs past their last interval.
- Returns:
drillholes (DrillholeData) – A new object, with the table holding the column replaced.
- as_point_data(tables=None, position=0.5, compositional=None, vector=None, drop_missing=True)[source]
Converts the interval data to points at the centre of each interval.
Every requested table must be on the same support, which compositing produces; the tables are then merged row for row. Numeric columns become continuous variables and categorical ones become categorical variables, unless they are claimed by a compositional or vector group.
The hole each point came from and the length it stands for are carried as the metadata columns HOLEID and LENGTH, which the models never see: they are what a leave-one-hole-out split and a support-weighted statistic read. Columns with the
recoveryrole ride beside them, for the same reason – they describe the sample, not the ground.- Parameters:
tables (str or list) – Which interval tables to convert. All of them by default.
position (float) – Where in each interval the point sits, from 0 (top) to 1 (bottom). The default puts it at the centre.
compositional (dict) – Groups of columns to convert to compositional variables, as
{name: {"columns": {"Pb_pct": "%", "Ag_ppm": "ppm"}, "rest": True}}. Each column is named with its unit, which is needed to add the parts up; see UNITS, or give a number to divide by. A row missing any part is marked missing entirely; non-positive parts are replaced by half the smallest positive value of their column, since a log-ratio transform cannot take a zero; and with “rest” a further part is added holding whatever is left of the whole, so that the composition sums to one. Without “rest” the parts are closed instead.vector (dict) – Groups of columns to convert to vector variables, as
{name: [columns]}.drop_missing (bool) – Whether to drop points whose values are all missing, which happens where a composite falls in a gap.
- Returns:
point (geoml.data.PointData)
- get_contacts(domain)[source]
The points where the category changes, as a rock type variable.
Each contact carries the category above it and the category below it, which is what an implicit model needs to place a boundary. The hole it came from is carried as the metadata column HOLEID; a contact has no length, so none is recorded.
- Parameters:
domain (str or tuple) – The categorical column, as in composite().
- Returns:
point (geoml.data.PointData)
- Return type:
- as_classification_input(domain, length=5.0, label_order=None)[source]
Converts a categorical column to point data for a classification model.
Unlike the compositing done for grades, this treats the category as known at a point rather than over an interval: points are dropped along each run of constant category, and the contacts between runs are added as points carrying both neighbouring categories. A boundary therefore enters the model with zero effective support, which is what lets an implicit model honour it exactly.
The hole and the length are carried as the metadata columns HOLEID and LENGTH, the latter being zero at the contacts.
- Parameters:
domain (str or tuple) – The categorical column, as in composite().
length (float) – Spacing of the points dropped along each run.
label_order (list) – The order of the categories, for an ordered rock type. The order found in the data by default.
- Returns:
point (geoml.data.PointData)
- Return type:
- class geoml.data.drillhole.IntervalTable(data, hole='HOLEID', fr='FROM', to='TO', grades=None, categorical=None, density=None, recovery=None, flags=None, ignore=None, name=None)[source]
Bases:
objectOne interval file, such as an assay or a lithology table.
The table holds depths only – coordinates come from the hole traces in the DrillholeData object that owns it, so re-compositing never accumulates positional error.
Each value column is given a role, which decides how it is composited:
gradeNumeric. Length-weighted mean, weighted also by the density column if one is declared. Missing values are skipped rather than propagated.
categoricalRock type, alteration, and the like. The category holding the greatest length within a composite wins.
densityNumeric, and also the weight applied to the grades. Composited as a length-weighted mean of its own.
recoveryNumeric: the share of each interval actually recovered. Composited as a length-weighted mean, like the density – a fraction of a length is exactly what length-weighting averages – and never applied as a weight to anything: how much a poorly recovered assay should count is a modelling decision, not a compositing one. Conversion carries it as metadata rather than as a variable, beside HOLEID and LENGTH: it describes the sample, and the models must not see it.
flagA categorical marker (drilling method, say) treated like a category.
ignoreCarried through untouched: a composite takes the value of its single longest contributing interval. Free-text columns land here.
Columns that are not declared explicitly are given the
graderole if they are numeric andignoreotherwise; set_role() corrects them afterwards. __str__ prints the roles in force.- data
The intervals, sorted by hole and depth, with the hole, from and to columns renamed to HOLEID, FROM and TO.
- Type:
DataFrame
- roles
Column name to role.
- Type:
dict
- name
A label for the table, used in messages.
- Type:
str
- __init__(data, hole='HOLEID', fr='FROM', to='TO', grades=None, categorical=None, density=None, recovery=None, flags=None, ignore=None, name=None)[source]
Initializer for IntervalTable.
- Parameters:
data (DataFrame) – The interval file.
hole (str) – Column with the hole name.
fr (str) – Columns with the start and end depths of each interval.
to (str) – Columns with the start and end depths of each interval.
grades (str or list) – Columns to assign to each role.
categorical (str or list) – Columns to assign to each role.
density (str or list) – Columns to assign to each role.
recovery (str or list) – Columns to assign to each role.
flags (str or list) – Columns to assign to each role.
ignore (str or list) – Columns to assign to each role.
name (str) – A label for the table.
- property value_columns
- property holes
- property length
- property density_column
- set_role(column, role)[source]
Declares (or redeclares) how a column is to be composited.
- Return type:
- rename(columns)[source]
Renames value columns, carrying their roles with them.
The roles are held beside the data, keyed by column name, so renaming the data frame’s columns directly leaves them behind: the column quietly stops being a grade, and printing or compositing the table raises. Rename here instead — or rename the data frame before it is added, which is the other place where the two cannot drift apart.
Column names become variable names in as_point_data(), so this is the last chance to tidy them before they reach a model.
- Parameters:
columns (dict) – Maps each current column name to its new one.
- Returns:
self, so that calls can be chained, as with set_role.
- Return type:
- validate(on_error='warn', collar=None)[source]
Checks the intervals for the problems that break compositing.
Overlapping intervals, non-positive lengths, missing depths and holes with no collar are errors: the aggregation assumes intervals within a hole are sorted and disjoint. Gaps and intervals running past the end of the hole are only reported, since assay tables are legitimately incomplete.
- Parameters:
on_error (str) – One of “warn”, “raise” or “ignore”.
collar (DataFrame) – Collar table indexed by hole, used to check hole names and lengths.
- Returns:
report (DataFrame) – One row per problem found, with its hole, depths and severity.
- category_legend(column)[source]
The distinct values of a column, and how much of the hole each holds.
This is the starting point for grouping categories without a GUI: write it out with to_csv(), edit the group column in a spreadsheet – it starts as a copy of the label – and read it back into group_categories(). The rows are sorted by length, so the codes that carry the deposit come first and a long legend can be worked down from the top.
- Parameters:
column (str) – The column to describe.
own (Intervals carrying no value get a row of their)
missing (with a)
label
the (so the legend accounts for every interval in the table and)
says (unlogged ground is visible while the grouping is being decided. It)
-- (nothing about the depths no interval covers at all)
intervals (DrillholeData.fill_unlogged() turns those into)
and
them. (validate() reports)
- Returns:
legend (DataFrame) – One row per value, with the number of intervals it appears in, the total length it accounts for, and the group column to edit.
- Return type:
DataFrame
- group_categories(column, groups, new_column=None, other=None)[source]
Lumps the values of a column into fewer categories.
Logging codes are usually far too many to model directly, and which of them behave alike is a judgement only the geologist can make.
- Parameters:
column (str) – The column to group.
groups (dict or DataFrame) – Either a mapping from each new category to the values it takes in, as
{"ore": ["MSST", "SLTST"], "waste": "SHALE"}, or a legend from category_legend() with its group column edited.new_column (str) – Where to put the result. The column is replaced by default; naming a new one keeps the original codes alongside the groups.
other (str) – What to call the values that no group claims. They keep their own label by default, with a warning naming them. Missing values stay missing either way.
- Returns:
table (IntervalTable) – A new table; this one is left alone.