获取numpy布尔数组中首个至少n个连续False块的起始索引
Great question! The issue with using np.cumsum(~w) is that it accumulates all False values across the entire array, not resetting the count when it hits a True. That's why it can't track consecutive runs—instead, it just gives a running total of False elements up to each index.
Simple Convolution-Based Approach
A clean and efficient way to solve this is using convolution. Here's how it works:
- Convert your boolean array to an integer array where
Falsebecomes1andTruebecomes0(since we want to count consecutiveFalses). - Use a convolution kernel of size
n_at_leastfilled with1s. When we convolve this kernel with our integer array, each result represents the sum ofn_at_leastconsecutive elements. If the sum equalsn_at_least, that means all those elements are1(so the original array hasn_at_leastconsecutiveFalses). - The first index where this sum occurs is exactly the starting index of the consecutive
Falserun.
Here's the code:
import numpy as np def find_first_consecutive_false_start(w, n_at_least): # Convert False to 1, True to 0 int_arr = (~w).astype(int) # Create convolution kernel of n_at_least 1s kernel = np.ones(n_at_least, dtype=int) # Compute valid convolution (only positions where kernel fits fully) conv_results = np.convolve(int_arr, kernel, mode='valid') # Find all indices where the sum equals n_at_least (all consecutive False) matching_indices = np.where(conv_results == n_at_least)[0] if len(matching_indices) == 0: return -1 # No such consecutive run exists return matching_indices[0]
Testing with Your Example
Let's verify this with your input:
w = np.array([True, False, True, True, False, False, False]) # For n_at_least=1 print(find_first_consecutive_false_start(w, 1)) # Output: 1 (correct) # For n_at_least=3 print(find_first_consecutive_false_start(w, 3)) # Output:4 (correct)
Alternative: Vectorized Running Count Method
If you prefer a method that tracks the length of each consecutive run directly (without convolution), here's a vectorized approach that computes the running length of consecutive Falses:
def find_first_consecutive_false_start(w, n_at_least): arr = ~w ones = np.where(arr, 1, 0) # Mark positions where we need to reset the count (when arr is False) reset = np.where(arr == False, 1, 0) reset_cumsum = np.cumsum(reset) # Calculate cumulative sum of ones, then subtract cumulative sum of ones at reset points cumulative_ones = np.cumsum(ones) run_lengths = ones * (cumulative_ones - np.cumsum(ones * reset)) # Find the first end index of a run that reaches n_at_least end_indices = np.where(run_lengths == n_at_least)[0] if len(end_indices) ==0: return -1 # Start index is end index minus (n_at_least -1) return end_indices[0] - (n_at_least -1)
This method computes the length of each consecutive False run as it goes, then finds the first run that meets your threshold.
Edge Cases
- If there are no consecutive
Falses of lengthn_at_least, the function returns-1. - If
n_at_least=0, you might want to handle that separately (e.g., return0depending on your use case).
内容的提问来源于stack exchange,提问作者00__00__00

