Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check for stuck data in a pandas data frame

This question has been edited for clarity based on the comments

Objective: Flag variable number of stuck/repetitive values in the columns of a data frame based on a group.

Desired Solution: The desired solution should meet the following criteria:

  1. Speed and Brevity are important
  2. Solution should accept as input variable number of thresholds for flagging stuck/repetitive values for each zone. For e.g. : {"Zone1": 4 , "Zone2":2} -> indicating that in Zone1, there need to be 4 consecutive repeated values for the logic to flag, while in Zone2, having atleast 2 or more repeated values should trigger the flag
  3. Please add comments wherever possible to make it easier to understand
  4. Preferably use Pandas and/or Numpy
  5. Time your solution on a test data frame with 87600 values (generate a data frame with 87,600 values to time)

Input Data/ Problem Formulation:

import pandas as pd
import numpy as np
from random import randint

# Generate some random data
ts_index = pd.date_range("1/1/2019", periods=24, freq="1H")
v1 = [randint(1, 100) for i in range(24)]
v2 = [2] * 24
v3 = [2, 2, 2, 2, 4, 4, 0, 2, 2, 1, 9, 2, 4, 1, 2, 2, 0, 2, 1, 8, 1, 7, 3, 5]
test_df = pd.DataFrame({"v1": v1, "v2": v2, "v3": v3}, index=ts_index)
print(test_df) 

Now, a sample output should look like this.

like image 993
UGuntupalli Avatar asked Feb 04 '26 16:02

UGuntupalli


1 Answers

First we get the absolute difference for the columns, followed by a cumsum().

Assuming that if a value does not change, the cumulative sum of the differences will remain constant, we can use pandas .shift().

We have to compare each value in zone1 with the one 4 rows above. Similar for zone2.

import pandas as pd
import numpy as np
import datetime


# Generate some random data
ts_index = pd.date_range("1/1/2019", periods=24, freq="1H")
v1 = [random.randint(1, 100) for i in range(24)]
v2 = [2] * 24
v3 = [2, 2, 2, 2, 4, 4, 0, 2, 2, 1, 9, 2, 4, 1, 2, 2, 0, 2, 1, 8, 1, 7, 3, 5]
df = pd.DataFrame({"v1": v1, "v2": v2, "v3": v3}, index=ts_index)
df1 = df.diff().fillna(0)

# Add hour and time of day to create flag
df['Hour'] = df.index.hour
df['Flag'] = np.where((df['Hour'] <= 8) | (df['Hour'] >= 18), 'Zone1', 'Zone2')
df1['Flag'] = np.where((df['Hour'] <= 8) | (df['Hour'] >= 18), 'Zone1', 'Zone2')

df1[["v1", "v2","v3"]] = np.abs(df1[["v1", "v2","v3"]])
df1[["v1", "v2","v3"]] = df1.groupby("Flag")["v1", "v2","v3"].cumsum()
columns = ["v1","v2","v3"]

z1_p = 3
z2_p = 1

for col in columns:
    df["Flag_"+col] = (np.array(df1[col].shift(z1_p) == df1[col]) & np.array(df1["Flag"] == "Zone1")) | \
(np.array(df1[col].shift(z2_p) == df1[col]) & np.array(df1["Flag"] == "Zone2"))
    for element in df[df["Flag_"+col] == True].index:
        if df.loc[element]["Flag"] == "Zone1":
            for i in range(1,4):
                a = a.append(pd.Index([element - datetime.timedelta(hours=i)]))
        else:
            a = a.append(pd.Index([element - datetime.timedelta(hours=1)]))
    df.at[a,"Flag_"+col] = True

df

Output:

                    v1  v2  v3  Hour    Flag    Flag_v1 Flag_v2 Flag_v3
2019-01-01 00:00:00 31  2   2   0       Zone1   False   True    True
2019-01-01 01:00:00 93  2   2   1       Zone1   False   True    True
2019-01-01 02:00:00 48  2   2   2       Zone1   False   True    True
2019-01-01 03:00:00 56  2   2   3       Zone1   False   True    True
2019-01-01 04:00:00 9   2   4   4       Zone1   False   True    False
2019-01-01 05:00:00 75  2   4   5       Zone1   False   True    False
2019-01-01 06:00:00 29  2   0   6       Zone1   False   True    False
2019-01-01 07:00:00 61  2   2   7       Zone1   False   True    False
2019-01-01 08:00:00 64  2   2   8       Zone1   False   True    False
2019-01-01 09:00:00 82  2   1   9       Zone2   False   True    False
2019-01-01 10:00:00 13  2   9   10      Zone2   False   True    False
2019-01-01 11:00:00 97  2   2   11      Zone2   False   True    False
2019-01-01 12:00:00 74  2   4   12      Zone2   False   True    False
2019-01-01 13:00:00 26  2   1   13      Zone2   False   True    False
2019-01-01 14:00:00 77  2   2   14      Zone2   False   True    True
2019-01-01 15:00:00 39  2   2   15      Zone2   False   True    True
2019-01-01 16:00:00 79  2   0   16      Zone2   False   True    False
2019-01-01 17:00:00 35  2   2   17      Zone2   False   True    False
2019-01-01 18:00:00 65  2   1   18      Zone1   False   True    False
2019-01-01 19:00:00 74  2   8   19      Zone1   False   True    False
2019-01-01 20:00:00 72  2   1   20      Zone1   False   True    False
2019-01-01 21:00:00 23  2   7   21      Zone1   False   True    False
2019-01-01 22:00:00 28  2   3   22      Zone1   False   True    False
2019-01-01 23:00:00 59  2   5   23      Zone1   False   True    False
like image 84
Let's try Avatar answered Feb 06 '26 05:02

Let's try



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!