{"cells":[{"metadata":{},"cell_type":"markdown","source":"# iBeacon Understanding and Feature Engineering\n\nThe aim of this notebook is to get a better understanding of the iBeacon technology. According to [Wikipedia](https://en.wikipedia.org/wiki/IBeacon) \"iBeacon is a protocol developed by Apple [...] in 2013. Various vendors have since made iBeacon-compatible hardware transmitters – typically called beacons – a class of **Bluetooth Low Energy (BLE) devices** that broadcast their identifier to nearby portable electronic devices.\"\n\nIn regards to using the iBeacon technology for precise indoor localization, the [Apple developers' guide ](https://developer.apple.com/ibeacon/Getting-Started-with-iBeacon.pdf) states: \"Due to the issues around signal strength and the variabilities in deployment environments, **iBeacon technology is not intended to be used for specific location identification. It should be capable of providing room-level accuracy**, but there are many factors that need to be considered to build a successful deployment.\"\n\nThe fact that iBeacon technology is not precise at meter-level is also reflected in this [discussion topic \"How much value is TYPE_BEACON adding?\"](https://www.kaggle.com/c/indoor-location-navigation/discussion/222488). Nonetheless, let's explore this topic a little bit."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\npd.set_option(\"display.max_colwidth\", 50)\n    \nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport glob\nimport os\nimport sys\nimport math\nimport gc\nimport json \nimport re\nfrom tqdm import tqdm\n\nimport warnings # Supress warnings \nwarnings.filterwarnings('ignore')\n\nPATH = '../input/indoor-location-navigation/'\n\nsubmission = pd.read_csv(f'{PATH}sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# iBeacon Features \nAs described on the [competitions GitHub page](https://github.com/location-competition/indoor-location-competition-20), the provided iBeacon data contains following features:\n* UUID: Identifier specific to the app and deployment use case [2]\n* MajorID: Further specification for iBeacon and use case [2]\n* MinorID: Further specification of region or use case [2]\n* TxPower\n* RSSI\n* Distance: The distance is calculated from TxPower and RSSI\n* MAC Address\n\n\"The UUID, major and minor values provide the identifying information for the iBeacon\" [2]\n\nThe following function is edited from [the repository's](https://github.com/location-competition/indoor-location-competition-20/blob/master/io_f.py) original function ` read_data_file(data_filename)` with a focus on iBeacon data. While the original function only exracted timestamp, identifier (joined from UUID, MajorID and MinorID) and RSSI, we will be **also extracting the distance**."},{"metadata":{"trusted":true},"cell_type":"code","source":"#  The following code is copied and edited https://github.com/location-competition/indoor-location-competition-20\nfrom dataclasses import dataclass\n\n@dataclass\nclass ReadData:\n    # Removed other signal info acquisition for simplicity reasons ...\n    ibeacon: np.ndarray\n    waypoint: np.ndarray\n\n\ndef read_data_file(data_filename):\n    # Removed other signal info acquisition for simplicity reasons ...\n    ibeacon = []\n    waypoint = []\n\n    with open(data_filename, 'r', encoding='utf-8') as file:\n        lines = file.readlines()\n\n    for line_data in lines:\n        line_data = line_data.strip()\n        if not line_data or line_data[0] == '#':\n            continue\n\n        line_data = line_data.split('\\t')\n\n        # Removed other signal info acquisition for simplicity reasons ...\n\n        if line_data[1] == 'TYPE_BEACON':\n            ts = line_data[0]\n            uuid = line_data[2]\n            major = line_data[3]\n            minor = line_data[4]\n            rssi = line_data[6]\n            distance = line_data[7] # Newly added\n            \n            ibeacon_data = [ts, '_'.join([uuid, major, minor]), rssi, distance]\n            \n            ibeacon.append(ibeacon_data)\n            continue\n\n        if line_data[1] == 'TYPE_WAYPOINT':\n            waypoint.append([int(line_data[0]), float(line_data[2]), float(line_data[3])])\n\n    # Removed other signal info acquisition for simplicity reasons ...\n\n    ibeacon = np.array(ibeacon)\n    waypoint = np.array(waypoint)\n\n    return ReadData(ibeacon, waypoint)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"\"\"\"\n### Help Functions ###\n\nHere we are setting up help functions that will be used in the following.\n\n## Git Repository ##\nhttps://github.com/location-competition/indoor-location-competition-20\n\nThe `read_data_file` function from the repository returns a class `ReadData` with the following attributes: `acce`, `acce_uncali`, `gyro`, `gyro_uncali`, `magn`, `magn_uncali`, `ahrs`, `wifi`, `ibeacon`, `waypoint`.\n\n## Further Utility Functions ##\nfrom https://www.kaggle.com/jiweiliu/wifi-label-encode\n\"\"\"\n\ndef encode_floor(floor):\n    \"\"\"\n    Encodes floor string to integer\n    \"\"\"\n    # Get floor number\n    encoded_floor = int(re.findall('[0-9]+', floor)[0])\n    \n    if floor.find('B') == 0:\n        # Multiply with -1 incase of B floor\n        encoded_floor = (-1)*encoded_floor\n    else: \n        # Subtract one floor to start at 0 for F1\n        encoded_floor = encoded_floor -1\n        \n    return encoded_floor\n\n# The following code is copied and edited from https://www.kaggle.com/jiweiliu/wifi-label-encode\nACOLS = ['timestamp','x','y','z']\n        \nFIELDS = {\n    'acce': ACOLS,\n    'acce_uncali': ACOLS,\n    'gyro': ACOLS,\n    'gyro_uncali': ACOLS,\n    'magn': ACOLS,\n    'magn_uncali': ACOLS,\n    'ahrs': ACOLS,\n    'wifi': ['timestamp','ssid','bssid','rssi','last_timestamp'],\n    'ibeacon': ['timestamp','id','rssi', 'distance'],\n    'waypoint': ['timestamp','x','y']\n}\n\ndef create_dummy_df(cols):\n    \"\"\"\n    Edited from https://www.kaggle.com/jiweiliu/wifi-label-encode\n    \"\"\"\n    df = pd.DataFrame()\n    for col in cols:\n        df[col] = [0]\n        if col in ['ssid','bssid']:\n            df[col] = df[col].map(str)\n    return df\n\ndef to_frame(data, col):    \n    \"\"\"\n    Edited from https://www.kaggle.com/jiweiliu/wifi-label-encode\n    \"\"\"\n    cols = FIELDS[col]\n    if data.shape[0]>0:\n        df = pd.DataFrame(data, columns=cols)\n    else:\n        df = create_dummy_df(cols)\n    for col in df.columns:\n        if 'timestamp' in col:\n            df[col] = df[col].astype('int64')\n    return df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Room Level Accuracy\nBased on the above information, I would like to find out if it is possible to **locate the iBeacon devices based on the training data**. Then we could use the information of the **iBeacon locations as additional features**."},{"metadata":{},"cell_type":"markdown","source":"## Data Preparation\n\nBefore we begin, we will prepare the data for easier handling afterwards. The test set only covers 24 buildings. Therefore, we will only consider this reduced number of buildings to create our new features. "},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# Edited from https://www.kaggle.com/devinanzelmo/wifi-features\nsubmission['building'] = submission[\"site_path_timestamp\"].apply(lambda x: x.split(\"_\")[0])\nprint(f\"The test set convers {submission['building'].nunique()} buildings with {len(submission)} pathes to predict.\")\nused_buildings = list(submission['building'].unique())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We collect each training path in the preselected 24 test buildings in a dataframe called `train_df`. It is also saved to the output if you would like to further use it."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"train_df = pd.DataFrame()\nbuilding_dict = {}\nfor building in used_buildings:\n    building_dict['building'] = building\n    for floor in os.listdir(f\"{PATH}/train/{building}\"):\n        building_dict['floor'] = floor\n        building_dict['floor_enc'] = encode_floor(floor)\n        for path in os.listdir(f\"{PATH}/train/{building}/{floor}\"):\n            building_dict['path'] = path\n            train_df = train_df.append(building_dict, ignore_index=True)\n\ndisplay(train_df.head().style.set_caption('Training Data'))\ntrain_df.to_csv(\"train_df.csv\", index=False)\n\n# Visualize\nbuilding_overview_df = train_df.groupby(['building', 'floor_enc']).path.nunique().to_frame().reset_index(drop=False)\nbuilding_overview_df = building_overview_df.pivot(index='building', columns='floor_enc')['path'].fillna(0)\nbuilding_overview_df.style.background_gradient(cmap='Blues', vmin=0, vmax=150).format(\"{:.0f}\").set_caption('Number Training Pathes per Floor for Buildings in Test Set')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Methodology\n\nThe **general idea** is as follows:  \n1. Assign each iBeacon distance to a waypoint position in building. \n2. Gather all iBeacon distance / position pairs for each beacon.\n3. Use lateration as shown below to determine the beacons position in the building\n![Trilateration.png](attachment:Trilateration.png)\n*Image from [Wikipedia: Lateration](https://de.wikipedia.org/wiki/Lateration)*\n4. Repeat previous steps for all known beacons in selected buildings\n\n### 1. Assign each iBeacon distance to a waypoint position in building.\nFor a sample path, we get the following **iBeacon and waypoint data**.","attachments":{"Trilateration.png":{"image/png":"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"}}},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"sample_building = '5a0546857ecc773753327266'\nsample_floor = 'B1'\nsample_path = f'{PATH}train/{sample_building}/{sample_floor}/5e15731fa280850006f3d013.txt'\nprint(f\"Sample path: {sample_path}\")\n\npath = read_data_file(sample_path)\n\nibeacon_df = to_frame(path.ibeacon,'ibeacon')\ndisplay(ibeacon_df.head().style.set_caption('DataFrame Head of iBecon Data'))\ndisplay(ibeacon_df.id.value_counts())\n\nwaypoint_df = to_frame(path.waypoint,'waypoint')\ndisplay(waypoint_df.head().style.set_caption('DataFrame Head of Waypoint Data'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can see that the waypoint data and the iBeacon data have different timestamps. Therefore, we cannot map a position to the iBeacon data directly.\nInstead, we will create a **lookup table to distinguish the position for each timestamp. Note that this method is NOT precise** but sufficient for the intended purpose.  \n\nThe lookup table is created by combining the iBeacon DataFrame with the waypoint DataFrame. Then the new combined dataframe is sorted by timestamps. Finally, the **waypoint data for the iBeacon timestamps is imputed by interpolation**."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Get iBeacon timestamps\nibeacon_df_grouped = ibeacon_df.groupby('timestamp')['id'].unique().to_frame().reset_index(drop=False)\ndisplay(ibeacon_df_grouped.head().style.set_caption(\"iBeacon Timestamps\"))\n\n# Combine with waypoint data\nwaypoint_ble_combined = pd.concat([ibeacon_df_grouped, waypoint_df])\nwaypoint_ble_combined = waypoint_ble_combined.sort_values(by='timestamp').reset_index(drop=True)\n\ndisplay(waypoint_ble_combined.head().style.set_caption('Combined Dataframe of Waypoint and iBeacon Timestamps Sorted by Time'))\n\nfig, ax = plt.subplots(nrows=2, ncols=1, figsize=(14, 6))\nsns.lineplot(x=waypoint_ble_combined.timestamp, y=waypoint_ble_combined.x, marker='o', ax=ax[0], label = 'before interpolation', color='orange')\nsns.lineplot(x=waypoint_ble_combined.timestamp, y=waypoint_ble_combined.y, marker='o', ax=ax[1], label = 'before interpolation', color='orange')\n\n# Interpolate waypoint\nwaypoint_ble_combined.x = waypoint_ble_combined.x.interpolate()\nwaypoint_ble_combined.y = waypoint_ble_combined.y.interpolate()\n\nsns.lineplot(x=waypoint_ble_combined.timestamp, y=waypoint_ble_combined.x, marker='o', ax=ax[0], label = 'after interpolation', color='blue')\nsns.lineplot(x=waypoint_ble_combined.timestamp, y=waypoint_ble_combined.y, marker='o', ax=ax[1], label = 'afte interpolationr', color='blue')\n\nplt.show()\n\ndisplay(waypoint_ble_combined.head().style.set_caption(\"Lookup Table with Interpolated Waypoint Data for iBeacon Timestamps\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Next we will map the waypoint data from the lookup table to the iBeacon dataframe to the corresponding timestamp."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"ble_df_with_waypoint = ibeacon_df.merge(waypoint_ble_combined[['timestamp', 'x', 'y']], on='timestamp', how='left')\ndisplay(ble_df_with_waypoint.head().style.set_caption(\"iBeacon Dataframe with added waypoint data\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 2. Gather all iBeacon distance / position pairs for each beacon.\nLet's repeat above step for all training files in the given building on the given floor."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"ble_list = pd.DataFrame()\ndf = train_df[train_df.building == sample_building]\n\nfiles = df[df.floor == sample_floor].path.unique()\n\nfor file in (files):\n\n    path = read_data_file(f\"{PATH}train/{sample_building}/{sample_floor}/{file}\")\n    \n    # Get path's wifi and waypoint data\n    ibeacon_df = to_frame(path.ibeacon,'ibeacon')\n    waypoint_df = to_frame(path.waypoint,'waypoint')\n\n    # Combine wifi and waypoint dataframe to one dataframe\n    ibeacon_df_grouped = ibeacon_df.groupby('timestamp')['id'].nunique().to_frame().reset_index(drop=False)\n    waypoint_ble_combined = pd.concat([ibeacon_df_grouped, waypoint_df])\n    waypoint_ble_combined = waypoint_ble_combined.sort_values(by='timestamp').reset_index(drop=True)\n\n    # Interpolate waypoint data for wifi timestamps\n    waypoint_ble_combined.x = waypoint_ble_combined.x.interpolate()\n    waypoint_ble_combined.y = waypoint_ble_combined.y.interpolate()\n\n    # Map wifi timestamps to wifi dataframe\n    ble_df_with_waypoint = ibeacon_df.merge(waypoint_ble_combined[['timestamp', 'x', 'y']], on='timestamp', how='left')\n\n\n    # Append to dataframe holding all wifi data for this floor\n    ble_list = ble_list.append(ble_df_with_waypoint)\n\ndisplay(ble_list.head().style.set_caption(f\"All iBeacon data for floor {sample_floor} in building {sample_building}\"))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Below you can see the frequency of each beacon. One beacon has over 26,000 datapoints, while there are two beacons with only 1 datapoint."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"display(ble_list.id.value_counts().to_frame().head(10))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### 3. Use lateration to determine the beacons position in the building\n\nBefore we begin, let's plot a few BLE signals to get a feeling for the data."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def plot_ibeacon_signal(path, building, floor, identifier):\n    \"\"\"\n    Copied and edited from https://www.kaggle.com/robikscube/indoor-navigation-snap-to-grid-post-processing\n     \n    For every available position the distance to a selected beacon is plotted as a circle.\n    The circles center is the corresponding x,y position.\n    The circles radius is the corresponding distance.\n    The x, y, and distance as scaled to match the maps dimensions for the visualization.\n    \n    Arg in:\n    * path: data directory for the floor images and floor info\n    * building: target building to be plotted\n    * floor: target floor in target building to be plotted\n    * identifier: selected beacon's ID to which the distances shall be plotted\n    \n    Output:\n    A visualization of the target building's target floor with circles representing the distances.\n    \"\"\"\n\n    # Prepare width_meter & height_meter (taken from the .json file)\n    floor_plan_filename = f\"{path}/metadata/{building}/{floor}/floor_image.png\"\n    json_plan_filename = f\"{path}/metadata/{building}/{floor}/floor_info.json\"\n\n    # Load and extract floor dimensions in meter\n    with open(json_plan_filename) as json_file:\n        json_data = json.load(json_file)\n\n    width_meter = json_data[\"map_info\"][\"width\"]\n    height_meter = json_data[\"map_info\"][\"height\"]\n\n    # Load floor map as image\n    floor_img = plt.imread(f\"{path}/metadata/{sample_building}/{sample_floor}/floor_image.png\")\n\n    # Get datapoints for single beacon\n    ble_df = ble_list[ble_list.id ==identifier]\n\n    # Scale x, y, and distance to match floor with sclaer = floor_img.shape[0] / height_meter = floor_img.shape[1] / width_meter)\n    ble_df[\"x_scaled\"] = ble_df[\"x\"] * floor_img.shape[0] / height_meter\n    ble_df[\"y_scaled\"] = (ble_df[\"y\"] * -1 * floor_img.shape[1] / width_meter) + floor_img.shape[0]\n    ble_df[\"distance_scaled\"] = ble_df[\"distance\"].astype(float) * floor_img.shape[0] / height_meter\n\n    # Plot distance to beacon from x,y position as circle \n    fig, ax = plt.subplots(figsize=(12, 12))\n    plt.imshow(floor_img)\n    for i in range(len(ble_df)):\n        circle=plt.Circle((ble_df[\"x_scaled\"].values[i], ble_df[\"y_scaled\"].values[i]), ble_df[\"distance_scaled\"].values[i], color='dodgerblue', fill=False)\n        ax.add_patch(circle)\n    ax.set_title(f\"Building {building}, Floor {floor} \\n Beacon ID {identifier}\")\n    plt.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"In the below example, there were 2340 datapoints available. However, we might wonder how it is even possible to have a BLE signal when at the top left corner and at the same time at middle."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"plot_ibeacon_signal(PATH, sample_building, sample_floor, \"89cb11b04122cef23388b0da06bd426c1f48a9b5_cfc84f0752adc96b489f71195d91a946c5f6d3e8_8159618423dfa22f1ca0b62543e2f18eef630ce8\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"One reason might be that the weaker the signal the less confident we can be in the signals accuracy. Therefore, let's look at the signals in close approximity only (< 3m). However, we can see that even with this stricter selection of iBeacon data, it still looks like there are **three (and a half) possible positions of the beacon**.\n\nAt this stage, it either looks like the identifier is not uniquely identifying a single beacon or the beacons are changing positions or the BLE RSSI is not realible."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"path = PATH\nbuilding = sample_building\nfloor = sample_floor\nidentifier = \"89cb11b04122cef23388b0da06bd426c1f48a9b5_cfc84f0752adc96b489f71195d91a946c5f6d3e8_8159618423dfa22f1ca0b62543e2f18eef630ce8\"\n\n\n# Prepare width_meter & height_meter (taken from the .json file)\nfloor_plan_filename = f\"{path}/metadata/{building}/{floor}/floor_image.png\"\njson_plan_filename = f\"{path}/metadata/{building}/{floor}/floor_info.json\"\n\nwith open(json_plan_filename) as json_file:\n    json_data = json.load(json_file)\n\nwidth_meter = json_data[\"map_info\"][\"width\"]\nheight_meter = json_data[\"map_info\"][\"height\"]\n\nfloor_img = plt.imread(f\"{PATH}/metadata/{sample_building}/{sample_floor}/floor_image.png\")\n\nble_df = ble_list[ble_list.id ==identifier]\nble_df.distance = ble_df.distance.astype(float)\nble_df[\"x_\"] = ble_df[\"x\"] * floor_img.shape[0] / height_meter\nble_df[\"y_\"] = (ble_df[\"y\"] * -1 * floor_img.shape[1] / width_meter) + floor_img.shape[0]\nble_df[\"distance_\"] = ble_df[\"distance\"].astype(float) * floor_img.shape[0] / height_meter\n\nble_df = ble_df[ble_df.distance < 3]\ndisplay(ble_df.head().style.set_caption(\"iBeacon datapoints in close approximity (< 3m)\"))\nfig, ax = plt.subplots(figsize=(12, 12))\nplt.imshow(floor_img)\nfor i in range(len(ble_df)):\n    circle=plt.Circle((ble_df[\"x_\"].values[i], ble_df[\"y_\"].values[i]), ble_df[\"distance_\"].values[i], color='dodgerblue', fill=False)\n    ax.add_patch(circle)\n    \ncircle=plt.Circle((480, 320), 60, color='red', fill=False)\nax.add_patch(circle)\n\ncircle=plt.Circle((140, 70), 50, color='red', fill=False)\nax.add_patch(circle)\n\ncircle=plt.Circle((340, 120), 75, color='red', fill=False)\nax.add_patch(circle)\n\nax.set_title(f\"Building {building}, Floor {floor} \\n Beacon ID {identifier}\")\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"For sanity reasons, let's check another beacon. For the below beacon, it looks like we could apply some form of lateration. If you search for where most of the circles are intersecting, you could guess that the beacons position could be roughly located at the position of the red dot. This one gives us a little bit of hope that our idea is feasible."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"#plot_ibeacon_signal(PATH, sample_building, sample_floor, \"4e9d3569a79dcbd102831d1bd587aa4e868ae797_2be4ebd5d986f25c1c84ff3d1536595914dab649_6b742085bcd69795bc6f371a635f62f3b2e3e2c5\")\npath = PATH\nbuilding = sample_building\nfloor = sample_floor\nidentifier = \"4e9d3569a79dcbd102831d1bd587aa4e868ae797_2be4ebd5d986f25c1c84ff3d1536595914dab649_6b742085bcd69795bc6f371a635f62f3b2e3e2c5\"\n\n\n# Prepare width_meter & height_meter (taken from the .json file)\nfloor_plan_filename = f\"{path}/metadata/{building}/{floor}/floor_image.png\"\njson_plan_filename = f\"{path}/metadata/{building}/{floor}/floor_info.json\"\n\nwith open(json_plan_filename) as json_file:\n    json_data = json.load(json_file)\n\nwidth_meter = json_data[\"map_info\"][\"width\"]\nheight_meter = json_data[\"map_info\"][\"height\"]\n\nfloor_img = plt.imread(f\"{PATH}/metadata/{sample_building}/{sample_floor}/floor_image.png\")\n\nble_df = ble_list[ble_list.id ==identifier]\n\nble_df[\"x_\"] = ble_df[\"x\"] * floor_img.shape[0] / height_meter\nble_df[\"y_\"] = (ble_df[\"y\"] * -1 * floor_img.shape[1] / width_meter) + floor_img.shape[0]\nble_df[\"distance_\"] = ble_df[\"distance\"].astype(float) * floor_img.shape[0] / height_meter\n\nfig, ax = plt.subplots(figsize=(12, 12))\nplt.imshow(floor_img)\nfor i in range(len(ble_df)):\n    circle=plt.Circle((ble_df[\"x_\"].values[i], ble_df[\"y_\"].values[i]), ble_df[\"distance_\"].values[i], color='dodgerblue', fill=False)\n    ax.add_patch(circle)\n    \ncircle=plt.Circle((335, 195), 5, color='red')\nax.add_patch(circle)\n\n\nax.set_title(f\"Building {building}, Floor {floor} \\n Beacon ID {identifier}\")\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's look at one more beacon. This time we only have 12 datapoints. In theory, this should be enough for trilateration. However, if you look at the below figure, it is difficult to visually estimate the position of the beacon."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"plot_ibeacon_signal(PATH, sample_building, sample_floor, \"7545e168924d7dd838162d5ba572786e2c47c7ff_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c_ef92237676503daee4b9f2c7f3ffce1a980fc403\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"At this stage, **it does not seem to be feasible to determine the position of the beacons in the training data as an additional feature**. \n\n# Floor Level Accuracy\nLet's see if the iBeacon data can at least support determining the floor in a building. For this purpose, we will follow the simple recipe demonstrated in the notebook [Simple 👌 99% Accurate Floor Model 💯](https://www.kaggle.com/nigelhenry/simple-99-accurate-floor-model). The notebook by [@nigelhenry](https://www.kaggle.com/nigelhenry) follows the following steps for the WiFi signal to determine floor.\n> 1. Construct a floor-bssid-max(RSSI) frequency table for each site\n2. Give each floor 1 point for every bssid-RSSI pair that falls within the max(RSSI) previously observed on that floor\n3. Take the highest-voted floor.\nLet's evaluate if the same steps can be applied to the iBeacon data.\n\n"},{"metadata":{},"cell_type":"markdown","source":"Below, I have gathered all iBeacon signals on each floor for the sample building."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"ble_list = pd.DataFrame()\ndf = train_df[train_df.building == sample_building]\n\nfor floor in tqdm(df.floor.unique()):\n    files = df[df.floor == floor].path.unique()\n\n    for file in (files):\n\n        path = read_data_file(f\"{PATH}train/{sample_building}/{floor}/{file}\")\n\n        # Get path's wifi and waypoint data\n        ibeacon_df = to_frame(path.ibeacon,'ibeacon')\n        waypoint_df = to_frame(path.waypoint,'waypoint')\n\n        # Combine wifi and waypoint dataframe to one dataframe\n        ibeacon_df_grouped = ibeacon_df.groupby('timestamp')['id'].nunique().to_frame().reset_index(drop=False)\n        waypoint_ble_combined = pd.concat([ibeacon_df_grouped, waypoint_df])\n        waypoint_ble_combined = waypoint_ble_combined.sort_values(by='timestamp').reset_index(drop=True)\n\n        # Interpolate waypoint data for wifi timestamps\n        waypoint_ble_combined.x = waypoint_ble_combined.x.interpolate()\n        waypoint_ble_combined.y = waypoint_ble_combined.y.interpolate()\n\n        # Map wifi timestamps to wifi dataframe\n        ble_df_with_waypoint = ibeacon_df.merge(waypoint_ble_combined[['timestamp', 'x', 'y']], on='timestamp', how='left')\n\n        ble_df_with_waypoint['floor'] = floor\n        # Append to dataframe holding all wifi data for this floor\n        ble_list = ble_list.append(ble_df_with_waypoint)\n\nble_list.distance = ble_list.distance.astype(float)\ndisplay(ble_list.head().style.set_caption(f\"All iBeacon data for building {sample_building}\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Below you can see on how many floors an identifier's signal is received. Although ideally, we would want an identifier's signal to be received only on one floor, we can expected a beacons signal to be received in th floor above or below as well. This means, that we would expected a maximum of three floors for a beacon's signal to be received. However, below we can see two beacons whose signals are received on five floors. This seems suspicious."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"ble_list.groupby('id').floor.nunique().to_frame().sort_values(by='floor', ascending=False).reset_index(drop=False).head(10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's see what happens if we only use strong signals from beacons in close approximity (< 3m). We still have the two entries with strong signals on all five floors. This seems implausible. However, we now have fewer beacons whose signals are received on multiple floors."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"ble_list[ble_list.distance < 3].groupby('id').floor.nunique().to_frame().sort_values(by='floor', ascending=False).reset_index(drop=False).head(10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"However, if we visualize the beacons' signals, we can at least roughly evaluate on which level the beacon must be located. Note, that the below shown lookup table does not include all beacons in the building."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"beacon_floor_mapping = ble_list[ble_list.distance < 3].groupby(['id', 'floor']).floor.count().to_frame()\nbeacon_floor_mapping.columns = ['num_signals']\nbeacon_floor_mapping = beacon_floor_mapping.reset_index(drop=False)\nbeacon_floor_mapping = beacon_floor_mapping.pivot(index = 'id', columns='floor').num_signals.fillna(0)\nbeacon_floor_mapping['located_on'] = beacon_floor_mapping.idxmax(axis=1)\nbeacon_floor_mapping.reset_index(drop=False, inplace=True)\nbeacon_floor_mapping.style.set_properties(subset=['id'], **{'width': '300px'}).background_gradient(subset=[\"B1\", \"F1\", \"F2\", \"F3\", \"F4\"], cmap='Blues', vmin=0, vmax=1500).format({\"B1\": \"{:.0f}\", \"F1\": \"{:.0f}\", \"F2\": \"{:.0f}\", \"F3\": \"{:.0f}\", \"F4\": \"{:.0f}\", \"F5\": \"{:.0f}\", }).set_caption('Number Strong iBeacon Signals in Sample Building')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's see if the above lookup table can be used as an additional feature. We will merge the `located_on` feature to the dataframe of your sample path."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"path = read_data_file(sample_path)\n\n# Get path's wifi and waypoint data\nibeacon_df = to_frame(path.ibeacon,'ibeacon')\nwaypoint_df = to_frame(path.waypoint,'waypoint')\n\n# Combine wifi and waypoint dataframe to one dataframe\nibeacon_df_grouped = ibeacon_df.groupby('timestamp')['id'].nunique().to_frame().reset_index(drop=False)\nwaypoint_ble_combined = pd.concat([ibeacon_df_grouped, waypoint_df])\nwaypoint_ble_combined = waypoint_ble_combined.sort_values(by='timestamp').reset_index(drop=True)\n\n# Interpolate waypoint data for wifi timestamps\nwaypoint_ble_combined.x = waypoint_ble_combined.x.interpolate()\nwaypoint_ble_combined.y = waypoint_ble_combined.y.interpolate()\n\n# Map wifi timestamps to wifi dataframe\nble_df_with_waypoint = ibeacon_df.merge(waypoint_ble_combined[['timestamp', 'x', 'y']], on='timestamp', how='left')\n\n# Merge with lookup table\nX = ble_df_with_waypoint.merge(beacon_floor_mapping[['id', 'located_on']], on='id', how='left')\nX.distance = X.distance.astype(float)\ndisplay(X.head())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now, if we use the `value_counts()` function, we can see that this path could either be located on B1 or F4. However, if we only look at the iBeacon signals in clsoe approximity (<3m), we can say with high confidence that the sample path is located on B1, which is in fact correct. One pitfall to note here, is that the lookup table contains information from the sample path as well. If you would want to evaluate the accuracy of this method, it would be better to create a lookup table excluding the validation data.\n\nSince the aim of this notebook is only to evaluate the feasibility of iBeacon data usage, I will not determine the accuracy of this method. However, I think it is save to say that the **iBeacon data could be used to support floor level classification. However, I would not recommend to use it on its own but instead combine it at least with WiFi**."},{"metadata":{"trusted":true},"cell_type":"code","source":"display(X.located_on.value_counts())\ndisplay(X[X.distance < 3].located_on.value_counts())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Summary\n* iBeacon technology is only be capable of providing room-level accuracy [2]\n* Kagglers have reported that adding iBeacon data seems to worsen the precision (see [discussion topic \"How much value is TYPE_BEACON adding?\"](https://www.kaggle.com/c/indoor-location-navigation/discussion/222488))\n* Analysis showed that it does not seem to be feasible to determine the position of the beacons in the training data as an additional feature.\n* iBeacon data could be used to support floor level classification. However, it is not recommended to use it on its own but instead combine it at least with WiFi data."},{"metadata":{},"cell_type":"markdown","source":"# References\n[1] https://en.wikipedia.org/wiki/IBeacon\n\n[2] https://developer.apple.com/ibeacon/Getting-Started-with-iBeacon.pdf\n\n[3] https://github.com/location-competition/indoor-location-competition-20\n\n[4] https://de.wikipedia.org/wiki/Lateration\n\n# Code References\nhttps://github.com/location-competition/indoor-location-competition-20\n\nhttps://www.kaggle.com/jiweiliu/wifi-label-encode\n\nhttps://www.kaggle.com/devinanzelmo/wifi-features\n\nhttps://www.kaggle.com/robikscube/indoor-navigation-snap-to-grid-post-processing\n\nhttps://www.kaggle.com/nigelhenry/simple-99-accurate-floor-model"}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}