# Clustering on the Chicago Array of Things: Spotting Anomalies in the Internet of Things Records
## 3 Methodology
### Experimental Evaluation
```
0:\(sensor\_data\)  minimum(nD,SD): min(\(nD,key=\lambda(d:abs(d-sD))\)) for\(datum\) in\(sensor\_data\)do \(closestDate=minimum(noaaData[^{\prime}date^{\prime}],sensorData[^{\prime}date^{ \prime}][0])\) \(idx=\)where(\(noaaData[^{\prime}date^{\prime}]==closestDate\)) \(noaaData[^{\prime}date^{\prime}]=noaaData[^{\prime}date^{\prime}][idx:]\) \(closestDate=minimum(noaaData[^{\prime}date^{\prime}],sensorData[^{\prime}date^{ \prime}][-1])\) \(idx=\)where(\(noaaData[^{\prime}date^{\prime}]==closestDate\)) \(noaaData[^{\prime}date^{\prime}]=noaaData[^{\prime}date^{\prime}][0:idx+1]\) endfor
```  
**Algorithm 1** Stripping unnecessary NOAA data  
The closest date is determined by measuring the difference in date between the first sensor reading and all NOAA readings until the minimum is found. The index is saved, and all proceeding data are stripped. The same thing occurs using the final sensor reading. To find a comparison between a given sensor's data and the ground-truth NOAA data, we calculate the mean difference between the sensor's readings and the NOAA data, using the closest value to each sensor reading with code similar to the algorithm in Algorithm 1. Here, instead of stripping data as seen in the algorithm, we track the index of the NOAA data and start the comparison against the next sensor reading from that index, reducing the computational complexity of a two-array comparison. We generate a difference between the NOAA and sensor reading and store that value to be calculated as part of the mean later. We determined some obvious anomalies after a cursory visual inspection of the data. These anomalies include incredibly large discrepancies between a sensor reading and a NOAA reading over the actual temperatures that are possible in the region. For an example of this phenomenon, please see Figure 3, specifically the anomalies labeled 1 and 2. Each number represents a different observed anomaly: (1) an out-of-bounds anomaly due to sensor error, (2) missing NOAA data, (3) potential sensor startup jitters, and (4) random sensor fluctuation. To avoid the erroneous readings represented by the value of 1 affecting the mean calculation, we chose a large boundary condition for the difference between sensor data and NOAA data of 50C. This value was chosen as it is just over regularly occurring high temperatures in the hottest area on earth [42]. The result is a heuristic that pulls unnaturally large sensor readings for temperature (and likely anomalies) out of the mean calculation. The value of 50 degrees Celsius (C) represents a bounding \(\alpha\) for a threshold anomaly, as discussed in Section 1.2. In addition, a small section of NOAA data is missing during the given time frame. This is represented in the data by a value of \(-99\) (represented by anomaly label 2 in Figure 3. As such, when determining the closest value to a given sensor reading, we ignore these values. The scikit-learn Python library provided access to the DB index metric. Other metrics for cluster analysis were considered, such as the Dunn Index and the Silhouette Score; however, the available library for the Dunn Index required considerable memory unavailable on any machines used for this work, and the Silhouette Score (also available through scikit-learn) took considerable computational time for the size of the dataset and was disqualified due to time constraints. This mean difference can be compared against the number of records in each cluster. This and the DB Index can be used for results analysis.