Python: Unearthing Data Trends - Local Maxima and Minima in NumPy

2024-05-19

Conceptual Approach

  1. Local maxima (peaks) are points where the data value is greater than both its neighbors on either side.

Implementation with NumPy

  1. Compare with neighbors: We can achieve this by calculating the difference between consecutive elements in the array using np.diff(data).
  2. Identify direction change: A local maximum (minimum) corresponds to a change in direction from positive (negative) difference to negative (positive) difference.
  3. Find extrema indices: We can use boolean indexing to find these transitions and then add 1 to account for the initial shift caused by np.diff.

Here's the code that implements this logic:

import numpy as np

def find_local_extrema(data):
  """
  Finds local maxima and minima in a 1D NumPy array.

  Args:
      data: A 1D NumPy array.

  Returns:
      A tuple containing two lists:
          - local_maxima: A list of indices of local maxima.
          - local_minima: A list of indices of local minima.
  """

  # Get boolean arrays for where the data is greater/less than its neighbors
  is_greater_than_neighbors = np.diff(data) > 0
  is_less_than_neighbors = np.diff(data) < 0

  # Find the indices where the direction changes (i.e., local extrema)
  local_maxima = np.where((is_greater_than_neighbors[:-1] & ~is_greater_than_neighbors[1:]) |
                          (is_less_than_neighbors[:-1] & ~is_less_than_neighbors[1:]))[0] + 1
  local_minima = np.where((~is_greater_than_neighbors[:-1] & is_greater_than_neighbors[1:]) |
                         (~is_less_than_neighbors[:-1] & is_less_than_neighbors[1:]))[0] + 1

  return local_maxima, local_minima

# Sample data
data = np.array([2, 3, 5, 7, 4, 2, 1, 6])

# Find local maxima and minima
local_maxima, local_minima = find_local_extrema(data)

# Print the results
print("Local maxima:", data[local_maxima])
print("Local minima:", data[local_minima])

This code effectively finds local maxima and minima in the data array.




Imports:

import numpy as np

This line imports the NumPy library and assigns it the alias np. NumPy is essential for working with arrays in Python.

Function Definition:

def find_local_extrema(data):
  """
  Finds local maxima and minima in a 1D NumPy array.

  Args:
      data: A 1D NumPy array.

  Returns:
      A tuple containing two lists:
          - local_maxima: A list of indices of local maxima.
          - local_minima: A list of indices of local minima.
  """

This defines a function called find_local_extrema that takes a 1D NumPy array (data) as input and returns two lists: local_maxima and local_minima containing the indices of local maxima and minima respectively.

Finding Differences:

  # Get boolean arrays for where the data is greater/less than its neighbors
  is_greater_than_neighbors = np.diff(data) > 0
  is_less_than_neighbors = np.diff(data) < 0
  • np.diff(data) calculates the difference between consecutive elements in the data array.
  • The results are stored in two boolean arrays:
    • is_greater_than_neighbors: True for elements greater than their neighbors.

Identifying Direction Changes:

  # Find the indices where the direction changes (i.e., local extrema)
  local_maxima = np.where((is_greater_than_neighbors[:-1] & ~is_greater_than_neighbors[1:]) |
                          (is_less_than_neighbors[:-1] & ~is_less_than_neighbors[1:]))[0] + 1
  local_minima = np.where((~is_greater_than_neighbors[:-1] & is_greater_than_neighbors[1:]) |
                         (~is_less_than_neighbors[:-1] & is_less_than_neighbors[1:]))[0] + 1

This part is the core logic for finding extrema:

  • [:-1] and [1:] slice the boolean arrays, excluding the last and first element respectively (to avoid out-of-bounds errors).
  • & (bitwise AND) and ~ (bitwise NOT) are used to find positions where the direction changes.
    • For maxima: A transition from positive difference to negative difference.
  • np.where finds the indices where these conditions are True.
  • + 1 accounts for the initial shift caused by np.diff.

Returning Results:

  return local_maxima, local_minima

The function returns a tuple containing two lists: local_maxima and local_minima.

Sample Data and Usage:

# Sample data
data = np.array([2, 3, 5, 7, 4, 2, 1, 6])

# Find local maxima and minima
local_maxima, local_minima = find_local_extrema(data)

# Print the results
print("Local maxima:", data[local_maxima])
print("Local minima:", data[local_minima])

This section creates a sample array (data) and calls the find_local_extrema function to find local maxima and minima. Finally, it prints the values at the identified extrema indices.




Using derivative sign changes:

This approach leverages the fact that local extrema occur at points where the derivative changes sign.

import numpy as np

def find_extrema_with_derivative(data):
  """
  Finds local maxima and minima using derivative sign changes.

  Args:
      data: A 1D NumPy array.

  Returns:
      A tuple containing two lists:
          - local_maxima: A list of indices of local maxima.
          - local_minima: A list of indices of local minima.
  """

  # Calculate the derivative (difference)
  derivative = np.diff(data)

  # Find sign changes in the derivative
  sign_changes = np.diff(np.sign(derivative))  # sign(x) returns +1 for positive, -1 for negative

  # Identify local maxima and minima based on sign changes
  local_maxima = np.where(sign_changes > 0)[0] + 1  # +1 for initial shift
  local_minima = np.where(sign_changes < 0)[0] + 1

  return local_maxima, local_minima

This method calculates the derivative using np.diff and then finds the sign changes in the derivative with np.diff(np.sign(derivative)). Positive sign changes indicate local minima, and negative sign changes indicate local maxima. Finally, it finds the indices of these sign changes and adjusts for the initial shift.

Using SciPy's find_peaks function (if available):

If you have the SciPy library installed, you can leverage its find_peaks function specifically designed for this purpose.

from scipy.signal import find_peaks

def find_extrema_with_scipy(data, prominence=None):
  """
  Finds local maxima and minima using SciPy's find_peaks function.

  Args:
      data: A 1D NumPy array.
      prominence (optional): Minimum prominence of peaks (defaults to None).

  Returns:
      A tuple containing two lists:
          - peaks: A list of indices of both maxima and minima.
          - properties: A dictionary containing peak properties (if prominence is provided).
  """

  # Find all peaks (including both maxima and minima)
  peaks, _ = find_peaks(data, prominence=prominence)

  # You can further classify peaks as maxima/minima based on data values

  return peaks, None  # You can return properties from _ if needed

# Example usage with prominence (optional)
peaks, _ = find_extrema_with_scipy(data, prominence=2)

This method uses find_peaks from SciPy to find all peaks (both maxima and minima) based on a user-defined prominence threshold (optional). You can then analyze the data values at the peak indices to differentiate between maxima and minima.

Remember to install SciPy (pip install scipy) if you want to use the second method.


python numpy


Mastering XPath: Essential Axes, Operators, and Tips for Effective Data Extraction

Understanding XPath and its Benefits:XPath (XML Path Language): A query language specifically designed for navigating and extracting data from XML documents...


When Values Matter: Using "==" for Effective Object Comparison in Python

Equality Operator ("=="):Checks if the values of two objects are equal.Works for various data types like numbers, strings...


Resolving 'ValueError: The truth value of an array with more than one element is ambiguous' in Python NumPy

Understanding the Error:This error arises when you attempt to use a NumPy array with multiple elements directly in a conditional statement (like if) in Python...


Python Pandas: Multiple Ways to Remove Rows Based on Conditions

Boolean Indexing:This is a powerful approach that uses a boolean expression to create a mask. This mask highlights which rows meet your condition for deletion...


Preserving Your Data: The Importance of DataFrame Copying in pandas

Preserving Original Data:In Python's pandas library, DataFrames are powerful structures for storing and analyzing tabular data...


python numpy