I'll show a numpy solution and leave it to you to transform to pandas.
a = np.array([
[0, 0, 0],
[0, 0, 0],
[0, 5, 0],
[0, 0, 3],
[0, 5, 3]]).T
First, mask the array and pad the mask with zeros on each row:
z = np.zeros((a.shape[0], 1), dtype=bool)
mask = np.concatenate((z, a == 0, z), axis=1)
By finding the location where the mask changes value, you can find the length of each run. The padding in the previous step ensures that the first change will be "on" and the last will be "off":
locs = np.nonzero(np.diff(mask, axis=1))
Now is the slightly tricky part. Normally you would do this in 1D, but here is 2D. However, the padding ensures that your run lengths are still accurate:
run_lengths = locs[1][1::2] - locs[1][::2]
Now you want to turn off the elements of mask that represent runs of fewer than n=3 elements. With the information you have, it may be easier to just create a new mask directly.
First mask out the runs that are too short:
valid_runs = np.flatnonzero(run_lengths >= 3)
Then make the output as a int8, which we will later view as a bool:
result = np.zeros(a.shape, dtype=np.int8)
Set the first element of each valid run to 1, and one past the end to -1:
v = 2 * valid_runs
result[locs[0][v], locs[1][v]] = 1
v += 1
v = v[locs[1][v] < result.shape[1]]
result[locs[0][v], locs[1][v]] = -1
You can take the cumulative sum of the result in-place, and view it as a boolean mask (since int8 and bool_ have the same size):
result = np.cumsum(result, axis=1, out=result).view(bool)
The final result is:
array([[ True, True, True, True, True],
[False, False, False, False, False],
[ True, True, True, False, False]])
TL;DR
Here is a fully generalized solution that will work across any axis in a multi-dimensional array, with an arbitrary selection for minimum run length (n) and number (k):
def mask_consecutive(a, k=0, n=3, axis=-1):
shape = list(a.shape)
shape[axis] = 1;
z = np.zeros(shape, dtype=bool)
mask = np.concatenate((z, a == k, z), axis=axis)
locs = np.argwhere(np.diff(mask, axis=axis))
run_lengths = locs[1::2, axis] - locs[::2, axis]
valid_runs = np.flatnonzero(run_lengths >= n)
result = np.zeros(a.shape, dtype=np.int8)
v = 2 * valid_runs
result[tuple(locs[v, :].T)] = 1
v += 1
v = v[locs[v, axis] < result.shape[axis]]
result[tuple(locs[v, :].T)] = -1
return np.cumsum(result, axis=axis, out=result).view(bool)