Press "Enter" to skip to content

基于Wi-Fi指纹和深度神经网络的室内定位系统设计代码详解(一)

本文讲解的代码可在GitHub上获取

 

https://github.com/kyeongsoo/can405_indoor_localization

 

首先我们需要知道为什幺要通过WIFI指纹实现室内定位,这是因为卫星定位系统在室内环境或高层建筑密集地区无法检测到卫星信号,无法满足人们对定位精度的要求。而良好的网络稳定性、高速高质量的数据传输,以及Wi-Fi通信模块在智能移动终端上的广泛应用,使得室内使用WIFI无线定位转变成一种低成本和易于实现技术。

 

话不多说,下面直接开始讲解代码。本文主要讲解如何预处理数据,数据集采用的UJIIndoorLoc dataset http://archive.ics.uci.edu/ml/datasets/UJIIndoorLoc

 

先定义训练与验证集的路径变量

 

path_train = '../data/UJIIndoorLoc/trainingData2.csv' 
path_validation = '../data/UJIIndoorLoc/validationData2.csv'

 

用函数pd.read_csv读取数据,其中header=0代表第一行是标题行

 

    train_df = pd.read_csv(path_train, header=0) 
    test_df = pd.read_csv(path_validation, header=0)

 

下面是读取数据集的结果。我们可以看到,该数据库包括19937条训练数据和1111条测试数据,实验中将原来的验证集作为测试集。一共有520个不同的无线接入点(WAP),每个无线接入点对应的接收信号强度(RSSI)范围从-104dBm(极差信号)到0dBm。在本实验中,为了便于后续归一化,使用负值-110表示未检测到WAP。除了520个WiFi指纹,529个属性还包含其他指纹采集坐标和其他有用信息。

 

在本实验中,除了使用520个WiFi指纹外,还需要使用6个属性,即Longitude (-7695.9388~ -7299.7865),Latitude (4864745.7450~4865017.3647),Floor (建筑物内楼层的高度,整数(0 ~ 4)),BuildingID(三栋楼(0~2)),SpaceID(用于识别位置空间(办公室、走廊、教室)的内部ID号,整数),RelativePosition(相对于位置空间的相对位置(1-门内,2-门外))。

 

    train_df
    WAP001  WAP002  WAP003  ...  USERID  PHONEID   TIMESTAMP
0        -110    -110    -110  ...       2       23  1371713733
1        -110    -110    -110  ...       2       23  1371713691
   ...     ...     ...  ...     ...      ...         ...
19935    -110    -110    -110  ...      18       10  1371711049
19936    -110    -110    -110  ...      18       10  1371711025
[19937 rows x 529 columns]
test_df
      WAP001  WAP002  WAP003  ...  USERID  PHONEID   TIMESTAMP
0       -110    -110    -110  ...       0        0  1380872703
1       -110    -110    -110  ...       0       13  1381155054
     ...     ...     ...  ...     ...      ...         ...
1109    -110    -110    -110  ...       0       13  1381247807
1110    -110    -110    -110  ...       0       13  1381247836
[1111 rows x 529 columns]

 

然后取出所有样本的520个WiFi指纹(train_AP_features),转换为float类型数组,使用函数对数据进行预处理。需要注意的是,这里是对每一行的数据进行标准化处理。

 

在此之后,添加一个新的列,它是和的组合,也就是字符串内容相加。进行这一步是因为我们后面要对楼层的参考点进行编号。将和结合,也就是说训练集数据中,在一个楼层里,我们将出现的不同参考点(,)分别进行编号。

 

    train_AP_features = scale(np.asarray(train_df.iloc[:,0:520]).astype(float), axis=1) # convert integer to float and scale jointly (axis=1)
    train_df['REFPOINT'] = train_df.apply(lambda row: str(int(row['SPACEID'])) + str(int(row['RELATIVEPOSITION'])), axis=1) # add a new column
    train_AP_features.shape
    (19937, 520)
    train_df['REFPOINT']
0        1062
1        1062
              ...
19935    1132
19936    1122
    Name: REFPOINT, Length: 19937, dtype: object

 

对于数据集中一共有几栋楼,每一栋楼有几个楼层,虽然我们可以直接在数据集的介绍中找到,但是我们一般还是选择自己从数据集中获取。np.unique函数是可以查找数组的唯一元素,因此我们可以通过该函数得到数据集中一共有三栋楼,五个楼层。

 

    blds = np.unique(train_df[['BUILDINGID']])
    flrs = np.unique(train_df[['FLOOR']])
    blds
    array([0, 1, 2], dtype=int64)
    flrs
    array([0, 1, 2, 3, 4], dtype=int64)

 

下面的代码是将参考点映射到每个楼层,这里用到了前面的REFPOINT,即每个楼层的不同参考点用不同的id标记。然后计算各楼层的平均坐标,留着后面使用。cond代表当前选择的楼层,是选取当前楼层的所有参考点的值,此时得到的idx代表的就是该楼层每一个参考点编号后的id值。

 

    x_avg = {}
    y_avg = {}
for bld in blds:
for flr in flrs:
# map reference points to sequential IDs per building-floor before building labels
            cond = (train_df['BUILDINGID']==bld) & (train_df['FLOOR']==flr)
            _, idx = np.unique(train_df.loc[cond, 'REFPOINT'], return_inverse=True) # refer to numpy.unique manual
            train_df.loc[cond, 'REFPOINT'] = idx
# calculate the average coordinates of each building/floor
            x_avg[str(bld) + '-' + str(flr)] = np.mean(train_df.loc[cond, 'LONGITUDE'])
            y_avg[str(bld) + '-' + str(flr)] = np.mean(train_df.loc[cond, 'LATITUDE'])

 

    train_df['REFPOINT']
0        13
1        13
             ..
19935    15
19936    13
    Name: REFPOINT, Length: 19937, dtype: object
    x_avg
    {'0-0': -7640.376350991143, '0-1': -7637.829042353956, '0-2': -7639.023285886209, '0-3': -7640.245117900643, '0-4': nan, '1-0': -7463.825569651152, '1-1': -7511.07230214694, '1-2': -7486.581783868335, '1-3': -7492.579508808194, '1-4': nan, '2-0': -7352.32452951861, '2-1': -7351.31601971969, '2-2': -7347.406288310243, '2-3': -7360.208989855721, '2-4': -7357.458888837215}
    y_avg
    {'0-0': 4864957.721957975, '0-1': 4864957.706202937, '0-2': 4864958.364463876, '0-3': 4864956.533051689, '0-4': nan, '1-0': 4864874.372386921, '1-1': 4864893.299521635, '1-2': 4864878.546449652, '1-3': 4864892.971830967, '1-4': nan, '2-0': 4864818.793817714, '2-1': 4864816.715084595, '2-2': 4864820.8762252545, '2-3': 4864806.658757386, '2-4': 4864822.315012857}

 

通过上述的操作,对于每一组数据,我们得到了520个WiFi指纹,标签就是对应的建筑,楼层,参考点的三个id,我们可以看出这是一个多标签的分类问题。对于建筑,楼层,参考点,我们可以分别采用pd.get_dummies得到对应的独热编码,然后将其合并为118位的label,其中前三位是代表建筑,接着的五位代表楼层,后面的110位是参考点。所以对于所有训练数据的label就是19937 x 118大小。

 

    # build labels for multi-label classification
    len_train = len(train_df)
    blds_all = np.asarray(pd.get_dummies(pd.concat([train_df['BUILDINGID'], test_df['BUILDINGID']]))) # for consistency in one-hot encoding for both dataframes
    flrs_all = np.asarray(pd.get_dummies(pd.concat([train_df['FLOOR'], test_df['FLOOR']]))) # ditto
    blds = blds_all[:len_train]
    flrs = flrs_all[:len_train]
    rfps = np.asarray(pd.get_dummies(train_df['REFPOINT']))
    train_labels = np.concatenate((blds, flrs, rfps), axis=1)
# labels is an array of 19937 x 118
# - 3 for BUILDINGID
# - 5 for FLOOR,
# - 110 for REFPOINT
    OUTPUT_DIM = train_labels.shape[1]

 

    train_labels
    array([[0, 1, 0, ..., 0, 0, 0],
           [0, 1, 0, ..., 0, 0, 0],
           [0, 1, 0, ..., 0, 0, 0],
           ...,
           [0, 1, 0, ..., 0, 0, 0],
           [0, 1, 0, ..., 0, 0, 0],
           [0, 1, 0, ..., 0, 0, 0]], dtype=uint8)
    train_labels.shape
    (19937, 118)

 

然后我们将训练集分为训练集和验证集,其中表示训练数据与整体数据的比率,默认值为0.9。

 

    # split the training set into training and validation sets
    train_val_split = np.random.rand(len(train_AP_features)) < training_ratio # mask index array
    x_train = train_AP_features[train_val_split]
    y_train = train_labels[train_val_split]
    x_val = train_AP_features[~train_val_split]
    y_val = train_labels[~train_val_split]

 

    x_train.shape
    (17955, 520)
    y_train.shape
    (17955, 118)
    x_val.shape
    (1982, 520)
    y_val.shape
    (1982, 118)

 

对于从文件中读取的验证集,本次实验是将其作为测试集,对WiFi指纹数据也需要进行相应的标准化。

 

然后得到测试集中建筑和楼层的标签,纬度和经度。

 

    # turn the given validation set into a testing set
    test_AP_features = scale(np.asarray(test_df.iloc[:,0:520]).astype(float), axis=1)  # convert integer to float and scale jointly (axis=1)
    x_test_utm = np.asarray(test_df['LONGITUDE'])
    y_test_utm = np.asarray(test_df['LATITUDE'])
    blds = blds_all[len_train:]
    flrs = flrs_all[len_train:]

 

至此我们已经将数据处理完毕,得到了训练集,验证集,测试集。其中训练集的WiFi指纹大小为(17955, 520),标签大小为(17955, 118)。验证集的WiFi指纹大小为(1982, 520),标签大小为(1982, 118)。测试集的WiFi指纹大小为(1111, 520),因为要评估模型的性能,因此当测试时,我们对于预测得到的标签通过训练集转换标签的对应关系得到对应预测的建筑,楼层,参考点(可以对应到经纬度坐标)与真实的相比较,评估模型的性能。

 

ref

 

D. Dua and C. Graff, “UCI machine learning repository,” 2017. [Online]. Available:http://archive.ics.uci.edu/ml

 

K. S. Kim, S. Lee, and K. Huang, “A scalable deep neural network architecture for multi-building and multi-floor indoor localization based on wi-fi fingerprinting,” Big Data Analytics, vol. 3, no. 1, p. 4, 2018.

 

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注