1

i have a pandas df that includes columns of sensor measurements were each row contains the sensor measurements of one unique sensor node. The order of these rows from the sensor nodes looks like this:

{{0: 'sensornode0009', 1: 'sensornode0015', 2: 'sensornode0011', 3: 'sensornode0012', 4: 'sensornode0016', 5: 'sensornode0014', 6: 'sensornode0013', 7: 'sensornode0008', 8: 'sensornode0010', 9: 'sensornode0009', 10: 'sensornode0015', 11: 'sensornode0011', 12: 'sensornode0012', 13: 'sensornode0016', 14: 'sensornode0014', 15: 'sensornode0013', 16: 'sensornode0008', 17: 'sensornode0010', 18: 'sensornode0009', 19: 'sensornode0015', 20: 'sensornode0011', 21: 'sensornode0012', 22: 'sensornode0016', 23: 'sensornode0014', 24: 'sensornode0013', 25: 'sensornode0008', 26: 'sensornode0010', 27: 'sensornode0009', 28: 'sensornode0015', 29: 'sensornode0011'}}

So there are 8 unique sensor nodes each sending the same measurements but from a different location. As can be seen in the data, sensornode0009 sent it´s values first, followed by the rest of the sensor nodes. After all unique sensor nodes occoured, sensornode0009 occours again. I call this a "chunk" of 10 seconds interval length within all sensor nodes sendet their data for one time. Due to small technically issues, some of the sensor nodes didn´t send their data within a 10 s - chunk.

I want to identify the rows where one or more sensor nodes are missing within one chunk and want to add a copy of the latest row were they sent the data correctly. As a result, i want to have a row of measurements from all unique sensor nodes within every 10s chunk.

I´ve tryed the following code to achieve this:

# Find the indices where the series starts (when 'sensornode_0009' occurs)
start_indices = df[df['Sensor_ID'] == 'sensornode0009'].index.tolist()

# Iterate through the series
for i in range(len(start_indices) - 1):
   start_idx = start_indices[i]  # Start index of the series
   end_idx = start_indices[i + 1]  # End index of the series

   # Get the unique names within the actual series
   names = df.loc[start_idx:end_idx, 'Sensor_ID'].unique()

   # Generate a list of expected names
   expected_names = df['Sensor_ID'].unique()

   # Check for missing names within the series
   missing_names = set(expected_names) - set(names)

   if missing_names:
      for missing_name in missing_names:
          # Find the latest row before the missing sensor node occurred
          last_row_idx = df[df['Sensor_ID'] == missing_name].index.max()
          last_row = df.loc[last_row_idx]

          # Copy the last row to the series where the sensor node is missing
          df.loc[end_idx, :] = last_row.values

Thsi code finds the indices of rows where sensornodes are missing but the filling of missing values doesnt work as expected.

For now I´ve used the information that the chunk always starts with "sensornode0009". Is there a simpler way to achieve the desired output?

pascal_
  • 61
  • 5

1 Answers1

0

With the following toy dataframe, representing four 10-seconds chunks in which 6 measures are missing:

import random

import pandas as pd

df = pd.DataFrame(
    {
        "Sensor_ID": [
            "sensornode0009",
            "sensornode0015",
            "sensornode0011",
            "sensornode0012",
            "sensornode0016",
            "sensornode0014",
            "sensornode0013",
            "sensornode0008",
            "sensornode0010",
            "sensornode0009",
            "sensornode0015",
            "sensornode0016",
            "sensornode0014",
            "sensornode0008",
            "sensornode0010",
            "sensornode0009",
            "sensornode0011",
            "sensornode0012",
            "sensornode0016",
            "sensornode0014",
            "sensornode0010",
            "sensornode0009",
            "sensornode0015",
            "sensornode0011",
            "sensornode0012",
            "sensornode0016",
            "sensornode0014",
            "sensornode0013",
            "sensornode0008",
            "sensornode0010",
        ],
        "Value": [random.uniform(1, 999) for _ in range(30)],
    }
)
print(df)
# Output

         Sensor_ID       Value
0   sensornode0009  538.221779
1   sensornode0015  565.538797
2   sensornode0011  575.390831
3   sensornode0012  445.036874
4   sensornode0016  819.592709
5   sensornode0014    2.283454
6   sensornode0013  523.824550
7   sensornode0008  832.071553
8   sensornode0010  190.525313
9   sensornode0009  271.313079
10  sensornode0015  616.734360
11  sensornode0016  995.404568
12  sensornode0014  537.618218
13  sensornode0008  507.406473
14  sensornode0010  985.809547
15  sensornode0009  474.056616
16  sensornode0011  736.087727
17  sensornode0012  448.838115
18  sensornode0016  402.096690
19  sensornode0014   70.338666
20  sensornode0010  310.830106
21  sensornode0009  777.731938
22  sensornode0015  841.878386
23  sensornode0011  549.194954
24  sensornode0012  949.023260
25  sensornode0016  867.558987
26  sensornode0014  330.417007
27  sensornode0013  459.010973
28  sensornode0008   38.897285
29  sensornode0010  578.124134

Here is one way to do it with pairwise from Python standard library itertools module and Pandas reindex, assuming sensornode0009 always exists:

from itertools import pairwise

complete_chunk = [
    "sensornode0009",
    "sensornode0015",
    "sensornode0011",
    "sensornode0012",
    "sensornode0016",
    "sensornode0014",
    "sensornode0013",
    "sensornode0008",
    "sensornode0010",
]
dfs = []

for i, j in pairwise(df[df["Sensor_ID"] == "sensornode0009"].index):
    dfs.append(
        df.loc[i : j - 1, :]
        .set_index("Sensor_ID")
        .reindex(complete_chunk)
        .fillna(method="ffill")
        .reset_index()
    )
dfs.append(
    df.loc[j:, :]
    .set_index("Sensor_ID")
    .reindex(complete_chunk)
    .fillna(method="ffill")
    .reset_index()
)  # last chunk

new_df = pd.concat(dfs, ignore_index=True)

Then:

print(new_df)
# Output

         Sensor_ID       Value
0   sensornode0009  538.221779
1   sensornode0015  565.538797
2   sensornode0011  575.390831
3   sensornode0012  445.036874
4   sensornode0016  819.592709
5   sensornode0014    2.283454
6   sensornode0013  523.824550
7   sensornode0008  832.071553
8   sensornode0010  190.525313
9   sensornode0009  271.313079
10  sensornode0015  616.734360
11  sensornode0011  616.734360
12  sensornode0012  616.734360
13  sensornode0016  995.404568
14  sensornode0014  537.618218
15  sensornode0013  537.618218
16  sensornode0008  507.406473
17  sensornode0010  985.809547
18  sensornode0009  474.056616
19  sensornode0015  474.056616
20  sensornode0011  736.087727
21  sensornode0012  448.838115
22  sensornode0016  402.096690
23  sensornode0014   70.338666
24  sensornode0013   70.338666
25  sensornode0008   70.338666
26  sensornode0010  310.830106
27  sensornode0009  777.731938
28  sensornode0015  841.878386
29  sensornode0011  549.194954
30  sensornode0012  949.023260
31  sensornode0016  867.558987
32  sensornode0014  330.417007
33  sensornode0013  459.010973
34  sensornode0008   38.897285
35  sensornode0010  578.124134
Laurent
  • 12,287
  • 7
  • 21
  • 37