Statistics

Statistical functions for well log data with depth-weighted calculations.

This module provides both weighted (by depth intervals) and arithmetic (unweighted) statistical functions for well log analysis.

logsuite.analysis.statistics.compute_intervals(depth)[source]

Compute depth intervals (thicknesses) for each sample point.

Uses midpoint method: each sample represents the interval from halfway to the previous sample to halfway to the next sample.

Parameters:

depth (np.ndarray) – Depth values (must be sorted ascending)

Returns:

Interval thickness for each depth point

Return type:

np.ndarray

Examples

>>> depth = np.array([1500, 1501, 1505])
>>> compute_intervals(depth)
array([0.5, 2.5, 2.0])

The intervals are: - 1500: from 1500 to 1500.5 = 0.5m (first point gets half interval to next) - 1501: from 1500.5 to 1503 = 2.5m (midpoint to midpoint) - 1505: from 1503 to 1505 = 2.0m (last point gets half interval from prev)

logsuite.analysis.statistics.compute_zone_intervals(depth, top, base)[source]

Compute depth intervals truncated to zone boundaries.

Uses the midpoint method but truncates intervals at zone boundaries to ensure thickness is correctly attributed to each zone.

Parameters:
  • depth (np.ndarray) – Depth values (must be sorted ascending)

  • top (float) – Zone top depth (inclusive)

  • base (float) – Zone base depth (exclusive)

Returns:

Interval thickness for each depth point, truncated to zone boundaries. Points outside the zone have zero interval.

Return type:

np.ndarray

Examples

>>> depth = np.array([2708.0, 2708.3, 2708.4, 2708.6])
>>> # Zone from 2708.0 to 2708.4
>>> compute_zone_intervals(depth, 2708.0, 2708.4)
array([0.15, 0.2, 0.05, 0.0])

The intervals are truncated at zone boundary 2708.4: - 2708.0: from 2708.0 to midpoint(2708.0, 2708.3)=2708.15 = 0.15m - 2708.3: from 2708.15 to midpoint(2708.3, 2708.4)=2708.35 = 0.2m - 2708.4: from 2708.35 to 2708.4 (zone boundary) = 0.05m (truncated) - 2708.6: outside zone = 0.0m

logsuite.analysis.statistics.mean(values, weights=None, method=None)[source]

Compute mean with optional method selection.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN)

  • weights (np.ndarray, optional) – Weights (depth intervals) for weighted calculation

  • method (str, optional) – ‘weighted’ for depth-weighted mean, ‘arithmetic’ for simple mean. If None, returns dict with both methods.

Returns:

If method specified: single float value If method is None: {‘weighted’: float, ‘arithmetic’: float}

Return type:

float or dict

Examples

>>> values = np.array([0.1, 0.2, 0.3])
>>> weights = np.array([1.0, 2.0, 1.0])
>>> mean(values, weights)
{'weighted': 0.2, 'arithmetic': 0.2}
>>> mean(values, weights, method='weighted')
0.2
>>> mean(values, weights, method='arithmetic')
0.2
logsuite.analysis.statistics.sum(values, weights=None, method=None)[source]

Compute sum with optional method selection.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN)

  • weights (np.ndarray, optional) – Weights (depth intervals) for weighted calculation

  • method (str, optional) – ‘weighted’ for depth-weighted sum, ‘arithmetic’ for simple sum. If None, returns dict with both methods.

Returns:

If method specified: single float value If method is None: {‘weighted’: float, ‘arithmetic’: float}

Return type:

float or dict

Examples

>>> values = np.array([0, 1, 0])  # NTG values
>>> weights = np.array([0.5, 2.5, 2.0])
>>> sum(values, weights, method='weighted')
2.5  # Net thickness
>>> sum(values, weights, method='arithmetic')
1.0  # Simple count of net samples
logsuite.analysis.statistics.std(values, weights=None, method=None)[source]

Compute standard deviation with optional method selection.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN)

  • weights (np.ndarray, optional) – Weights (depth intervals) for weighted calculation

  • method (str, optional) – ‘weighted’ for depth-weighted std, ‘arithmetic’ for simple std. If None, returns dict with both methods.

Returns:

If method specified: single float value If method is None: {‘weighted’: float, ‘arithmetic’: float}

Return type:

float or dict

Examples

>>> values = np.array([0.1, 0.2, 0.3, 0.2])
>>> weights = np.array([1.0, 1.0, 1.0, 1.0])
>>> std(values, weights)
{'weighted': 0.0707..., 'arithmetic': 0.0707...}
logsuite.analysis.statistics.percentile(values, p, weights=None, method=None)[source]

Compute percentile with optional method selection.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN)

  • p (float) – Percentile to compute (0-100)

  • weights (np.ndarray, optional) – Weights (depth intervals) for weighted calculation

  • method (str, optional) – ‘weighted’ for depth-weighted percentile, ‘arithmetic’ for simple percentile. If None, returns dict with both methods.

Returns:

If method specified: single float value If method is None: {‘weighted’: float, ‘arithmetic’: float}

Return type:

float or dict

Examples

>>> values = np.array([0.1, 0.2, 0.3, 0.4, 0.5])
>>> weights = np.array([1.0, 1.0, 1.0, 1.0, 1.0])
>>> percentile(values, 50, weights)
{'weighted': 0.3, 'arithmetic': 0.3}
>>> percentile(values, 50, weights, method='arithmetic')
0.3
logsuite.analysis.statistics.mode(values, weights=None, method=None, bins=50, is_discrete=False)[source]

Compute mode (most frequent value) with optional method selection.

For continuous data, values are binned before finding the mode. For discrete data, bins parameter is ignored.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN)

  • weights (np.ndarray, optional) – Weights (depth intervals) for weighted calculation

  • method (str, optional) – ‘weighted’ for depth-weighted mode, ‘arithmetic’ for simple mode. If None, returns dict with both methods.

  • bins (int, default 50) – Number of bins for continuous data (ignored if is_discrete=True)

  • is_discrete (bool, default False) – If True, treat as discrete data (no binning)

Returns:

If method specified: single float value (mode) If method is None: {‘weighted’: float, ‘arithmetic’: float}

Return type:

float or dict

Examples

>>> values = np.array([0.1, 0.2, 0.2, 0.3, 0.2])
>>> mode(values, method='arithmetic')
0.2
>>> discrete_values = np.array([1, 1, 2, 1, 3])
>>> mode(discrete_values, method='arithmetic', is_discrete=True)
1.0
logsuite.analysis.statistics.geometric_mean(values, weights=None, method=None)[source]

Compute geometric mean with optional method selection.

Geometric mean is appropriate for permeability averaging and other log-normally distributed properties. Only positive values are used; if any valid value is non-positive, returns NaN.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN). Must be positive for valid result.

  • weights (np.ndarray, optional) – Weights (depth intervals) for weighted calculation.

  • method (str, optional) – ‘weighted’ for depth-weighted geometric mean, ‘arithmetic’ for simple. If None, returns dict with both methods.

Returns:

If method specified: single float value. If method is None: {‘weighted’: float, ‘arithmetic’: float}

Return type:

float or dict

See also

mean

Arithmetic mean.

harmonic_mean

Harmonic mean (parallel flow averaging).

Examples

>>> values = np.array([1.0, 10.0, 100.0])
>>> geometric_mean(values, method='arithmetic')
10.0
logsuite.analysis.statistics.harmonic_mean(values, weights=None, method=None)[source]

Compute harmonic mean with optional method selection.

Harmonic mean is appropriate for averaging rates and parallel flow properties (e.g., horizontal permeability in layered systems). Only positive values are used; if any valid value is non-positive, returns NaN.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN). Must be positive for valid result.

  • weights (np.ndarray, optional) – Weights (depth intervals) for weighted calculation.

  • method (str, optional) – ‘weighted’ for depth-weighted harmonic mean, ‘arithmetic’ for simple. If None, returns dict with both methods.

Returns:

If method specified: single float value. If method is None: {‘weighted’: float, ‘arithmetic’: float}

Return type:

float or dict

See also

mean

Arithmetic mean.

geometric_mean

Geometric mean (log-normal averaging).

Examples

>>> values = np.array([1.0, 2.0, 4.0])
>>> harmonic_mean(values, method='arithmetic')
1.714...
logsuite.analysis.statistics.compute_all_statistics(values, depth)[source]

Compute comprehensive statistics including both weighted and arithmetic measures.

Parameters:
  • values (np.ndarray) – Property values (may contain NaN)

  • depth (np.ndarray) – Depth values corresponding to values

Returns:

Dictionary containing: - weighted_mean: Depth-weighted mean - weighted_sum: Depth-weighted sum (useful for cumulative thickness) - weighted_std: Depth-weighted standard deviation - weighted_p10, weighted_p50, weighted_p90: Depth-weighted percentiles - arithmetic_mean: Simple arithmetic mean - arithmetic_sum: Simple sum - arithmetic_std: Simple standard deviation - count: Number of non-NaN values - depth_samples: Total number of samples - depth_thickness: Total thickness covered - min: Minimum value - max: Maximum value

Return type:

dict