大数据挑战赛-鼠标轨迹识别

2023-05-16

大数据挑战赛-鼠标轨迹识别,竞赛官网:http://bdc.saikr.com/c/cql/34541

1.我们看一下整个竞赛的详情

赛题描述

      鼠标轨迹识别当前广泛运用于多种人机验证产品中,不仅便于用户的理解记忆,而且极大增加了暴力破解难度。但攻击者可通过黑产工具产生类人轨迹批量操作以绕过检测,并在对抗过程中不断升级其伪造数据以持续绕过同样升级的检测技术。我们期望用机器学习算法来提高人机验证中各种机器行为的检出率,其中包括对抗过程中出现的新的攻击手段的检测。

比赛数据

     本题目数据来源于某人机验证产品采集的鼠标轨迹,经过脱敏处理,数据分为3部分(数据量分别为3000条,10万,200万)。

     赛事分为三个阶段(初赛、复赛、决赛答辩):5月26日初赛提供3000条数据作为训练样本,供参赛者下载进行建模和模型优化,同时提供10万条正式比赛数据供下载评测,识别结果为初赛得分;复赛提供200万条比赛数据(不可下载,数据不可见,仅供评测),识别结果为复赛得分;决赛将以现场答辩会的形式进行。

【训练数据】

训练数据表名称:dsjtzs_txfz_training

字段

类型

解释

a1

bigint

编号id

a2

string

鼠标移动轨迹(x,y,t)

a3

string

目标坐标(x,y)

label

string

类别标签:1-正常轨迹,0-机器轨迹

训练样例数据:见 dsjtzs_txfz_training_sample.txt

【测试数据】

初赛测试表名称:dsjtzs_txfz_test1

复赛测试表名称:dsjtzs_txfz_test2

字段

类型

解释

a1

bigint

编号id

a2

string

鼠标移动轨迹(x,y,t)

a3

string

目标坐标(x,y)

测试样例数据:见 dsjtzs_txfz_test_sample.txt

测评标准

选手请将识别为机器行为的编号id提交到计算平台,需要提交的结果表,只包含一个字段:编号id。

初赛提交表名:dsjtzs_txfzjh_preliminary

复赛提交表名:dsjtzs_txfzjh _semifinal

设定Precision为P,Recall为R,白样本为正常轨迹,黑样本为机器轨迹其中:

P = 判黑的数据中真正为黑的数量/判黑的数据总量,

R = 判黑的数据中真正为黑的数量/真实黑数据总量,

比如10w条数据,其中8w条为白样本,2w条为黑样本,参赛者一共将1w条判断为黑样本(其中真正的黑样本有8000条,错将2000条白样本判黑),那么,

P=8000/10000 = 80%,

R=8000/20000=40%,

参赛队伍最终得分F = 5PR/(2P+3R)*100。最终排名按照F值评判,F值越大,代表结果越优,排名越靠前。

2.竞赛的进程安排

初赛(5月26日—7月21日)

(1)参赛队伍可从大赛官方网站下载数据,在本地进行算法设计和调试,规定时间内在报名官网提交结果,每支队伍在一天内只能提交一次结果;

(2)5月26日起,系统向选手开放训练样本数据3000条(2600白样本,400条黑样本)供参赛者下载进行建模和模型优化,同时提供正式比赛数据10万条供参赛者下载评测;

复赛(7月25日-8月14日)

(1)所有比赛数据不可下载,选手需在腾讯数据平台部DIX平台上完成数据处理、建模、算法调试、产出结果等所有环节,可使用基于Spark、xgBoost及平台提供的机器学习相关基础算法。

(2)7月25日起系统提供200万条正式比赛数据(对参赛选手不可见,仅供平台对参赛作品进行评测);

决赛(8月20日)

1.  决赛将以现场答辩会的形式进行,具体安排另行通知;

2.  参赛队伍应提前准备现场答辩材料,包括PPT、算法代码;

综上所述:

每个竞赛的阶段数据集情况
比赛阶段训练集(条)测试集(条)
初赛(stage1)3000100000
初赛(stage2)3000100000
复赛30002000000

3.训练数据和测试数据如下所示:

训练数据

70 276,2555,1234;290,2555,1261;339,2555,1306;374,2555,1357;409,2555,1405;430,2555,1456;451,2555,1567;451,2555,1879;458,2555,2338;479,2555,2365;507,2555,2404;591,2555,2458;745,2568,2509;801,2568,2557;822,2568,2608;829,2568,2656; 643.5,553 1
75 262,2503,316;262,2516,376;297,2516,406;353,2516,439;416,2490,472;493,2490,502;605,2477,532;717,2425,565;794,2412,598;857,2412,628;934,2412,664;955,2412,691;990,2412,724;1018,2412,757;1025,2412,787;1039,2412,880;1060,2412,913;1067,2412,946;1095,2386,1006;1109,2386,1069;1123,2386,1129;1130,2386,1312;1123,2386,2035;1109,2386,2215;1095,2386,2395;1088,2386,2608;1074,2386,2638;1067,2386,2671;1060,2386,2704;1053,2386,2764;1046,2399,2797;1039,2399,3937; 843.0,358 1
249 612,2607,352;836,2607,724;871,2607,1165;885,2607,2341;899,2607,2797;913,2607,3328;927,2607,3706;934,2607,4162;941,2607,4621;948,2607,5053;969,2607,5629;969,2620,8749;962,2620,10234;920,2620,11749;913,2633,12625;920,2633,15493;934,2633,16405;948,2633,16717;976,2633,17821; 727.5,189 1
2983 325,2438,484;381,2464,1201;458,2555,1276;479,2555,1312;528,2451,1396;570,2555,1501;640,2555,1606;703,2555,1699;745,2451,1723;801,2542,3730;829,2555,3796;892,2555,3841;920,2555,3907;976,2516,5986;1004,2555,9784;1046,2555,14935;1074,2555,17041;1088,2529,17083;1137,2555,22609;1193,2555,22642;1207,2555,27553;1235,2555,27619;1256,2555,32953;1270,2412,33028;1319,2425,33052;1333,2464,38623;1333,2555,38704; 1123.0,195.5 0
2984 297,2529,193;311,2594,2251;346,2594,6838;381,2594,10930;437,2594,10951;486,2594,15874;528,2594,15895;556,2672,21235;591,2633,21283;612,2594,21337;633,2594,21367;647,2503,25906;682,2568,28411;689,2594,28480;731,2594,33868;745,2594,33931; 528.0,670 0
2985 269,2542,217;311,2555,2650;346,2555,7423;367,2555,7513;395,2555,7594;402,2555,7633;444,2555,7669;472,2555,7735;528,2555,7813;570,2555,7837;605,2555,7906;640,2685,8014;654,2594,8122;689,2555,8170;696,2698,8221;773,2594,8266;794,2555,8305;808,2555,8371; 601.5,358 0

其中包含三个正样本(label=1)和三个副样本(label=0),没一行代表一个样本。从数据中可以看到,第一列都是轨迹的标号,如70,75,249,2983等等,而没一行的最后一列,为0或1,表示样本轨迹的label。

测试集数据

1 234,2620,196;241,2620,226;248,2620,256; 647.0,189
5 374,2503,1174;402,2503,1204;430,2503,1252;479,2503,1267;514,2503,1297;563,2503,1330;619,2503,1363;654,2503,1399;682,2503,1423;724,2503,1456;745,2503,1492;766,2503,1522;773,2503,1549;780,2503,1762;794,2503,2800;808,2503,2830;822,2503,2863;843,2503,2893;857,2503,2956;864,2503,3016; 545.5,189
67 514,2347,46;591,2373,76;668,2399,103;745,2425,130;822,2451,157;899,2477,187;976,2503,214;1053,2529,241;1130,2555,265;1207,2581,292;1284,2607,319;1361,2568,346;1438,2529,373;1515,2490,400;1592,2451,424; 1424.0,1359
92 486,2334,40;535,2334,61;584,2334,82;633,2334,103;682,2334,121;731,2334,142;780,2347,163;829,2360,184;878,2373,202;927,2386,223;976,2386,241;1025,2399,262;1074,2412,280;1123,2425,301;1172,2438,319;1221,2412,340;1270,2386,358;1319,2360,379;1368,2334,397;1417,2308,418;1466,2282,436;1515,2256,457; 1312.0,189
93 234,2386,61;234,2438,160;234,2464,181;241,2477,229;255,2490,280;269,2490,316;318,2503,364;367,2516,421;416,2516,469;458,2516,511;493,2516,562;514,2503,613;535,2503,664;556,2490,715;563,2490,766;563,2477,808;570,2477,847;577,2477,1102;584,2477,1150;605,2477,1213;619,2477,1261;668,2477,1312;766,2477,1363;878,2477,1411;1053,2477,1462;1144,2477,1513;1235,2477,1561;1284,2477,1615;1312,2477,1660;1326,2477,1711;1333,2477,1762;1347,2477,1825;1361,2477,1861;1382,2477,1915;1403,2477,1963;1438,2477,2011;1452,2477,2062;1466,2477,2110;1473,2477,2161;1466,2477,2413;1459,2477,2437;1466,2477,3091;1473,2477,3181;1480,2477,3253;1487,2477,3355;1494,2477,3412;1501,2477,3463;1508,2477,3517;1515,2477,3589;1501,2477,4237; 1361.0,202

此处共给出5个样本,测试集除了最后一列没有label外,其他的跟训练集一样。

现在我们仔细解析一下数据样本的结构:

根据第一部分的竞赛题目,以及对数据集的解析。我们可以明白,所有的样本都由一个序列构成的,我们选择训练样本中的id=75的样本来分析一下:

75 262,2503,316;262,2516,376;297,2516,406;353,2516,439;416,2490,472;493,2490,502;605,2477,532;717,2425,565;794,2412,598;857,2412,628;934,2412,664;955,2412,691;990,2412,724;1018,2412,757;1025,2412,787;1039,2412,880;1060,2412,913;1067,2412,946;1095,2386,1006;1109,2386,1069;1123,2386,1129;1130,2386,1312;1123,2386,2035;1109,2386,2215;1095,2386,2395;1088,2386,2608;1074,2386,2638;1067,2386,2671;1060,2386,2704;1053,2386,2764;1046,2399,2797;1039,2399,3937; 843.0,358 1

第一列75为样本id,最后一列是label=1,表明是正样本,中间是一串由分号作为分隔符的序列,分隔的每一部分包含三个数值如一个部分为(262,2503,316),根据题目可知,这里面的三个值对应(x,y,t)。根据题目的背景,整个序列是一个鼠标轨迹,那么,轨迹在采样的过程中,就是通过一个个点构成,所以(x,y,t)就是一个点的位置和时间参数。

另外,需要格外指出的是,每条轨迹坐标后面紧接着有一个由逗号分隔开的坐标如 843.0,358,该坐标就构成了这条轨迹的目标点。根据题目的意思,也就是说,每条轨迹最终的目的都是想挪动到目标点位置的。

4.样本轨迹的特征提取

看整个样本数据集,不同的轨迹长度是不一样的,或者说采样点的个数是不一样的。当我们最初接触到这个题目的时候,我们本想把整个轨迹点作为特征,直接用Xgboost训练,后来发现尴尬了,轨迹长度都不一样,还怎么训练。

思路一:

其实,既然有了不同的轨迹,也就是不同的序列,可以有一种很常见的做法,就是直接使用长短期记忆网络(LSTM)来进行训练并预测,基本上可以无脑训练了。但是,由于官方给出的建议是不推荐使用深度学来打比赛,因为最后决赛提供的腾de讯的机器学习平台不给开放深度学习资源。所以这种方法,只是从脑子里面过了一下,没有去执行。

思路二:

既然,给的是每条曲线的轨迹,我们完全可以把每条轨迹做图然后生成图片保存起来,然后通过深度学习,进行图像的分类。因为训练集本身比较少(才3000条),而测试集却相当大(初赛10万条、复赛200万条),所以可以想到使用迁移学习的方法,将已经在较大数据集如ImageNet、Ms COCO上预训练好的模型,如ResNet、Inception-V3等等来初始化自己的网络,然后在自己的数据集上进行fine-tuning。这确实不失为一种可以尝试的方法。但是,同样的原因,官方不提供深度学习资源。就我们自己的破笔记本,根本想都别想。

思路三:

前面的方法都行不通了,作为菜鸟级选手,我只能想到通过提取每条样本轨迹的统计特征了。如平均值,方差,极差,偏差,最大值,最小值,中值。然后,既然有了轨迹,就会有速度和加速度,所以可以继续求出速度的前述统计特征,当然还可以想到,如果当作一个时间序列的话,我们可以计算序列的一阶差分二阶差分,然后继续计算统计特征。这么一下来,每条轨迹的统计特征已经不少了,足够进行Xgboost训练了。

为了纪念一下整个竞赛的不容易,下面贴出我写的提取特征的baseline(简单看看就行,可直接略过): 

# -*- coding: utf-8 -*-
import pandas as pd
import fileinput
import numpy as np
import matplotlib.pyplot as plt
import sys
import os
sys.path.append(os.getcwd() + '/scr')
from subFunction import *

train_path = './data/dsjtzs_txfz_tranining.txt'
test_path = './data/dsjtzs_txfz_test1.txt'

mouseTrack_features_labels = ['numRecode', 'xmean', 'ymean', 'xEnt', 'yEnt', 'MaxTimeInterval', 'MinTimeInterval', 'tailXdiff', 'tailYdiff', 'tailTdiff', 'tailDis_xy',
'Vmean', 'Vmax', 'Vmin', 'Vvar', 'Vstd', 'Accmean', 'Accmax', 'Accmin', 'Accvar', 'Accstd', 'LastT20var', 'LastT20std', 'Vcov', 'VCorrelationCoefficient', 'XdiffVar', 'YdiffVar']

    
featureLabels = ['id']
featureLabels.extend(mouseTrack_features_labels)
featureLabels.extend(['YTarget', 'XTarget', 'label'])

#获取x, y的平均值,2个特征
def get_XYmean(df_MouseTrack):
    x = df_MouseTrack["x"]
    y = df_MouseTrack["y"]
    xEnt = calcShannonEnt(x)
    yEnt = calcShannonEnt(y)
    xyEnt = [xEnt, yEnt]
    return xyEnt

#获取间隔时间的最大值和最小值  2个特征
def get_MaxMinT(df_MouseTrack):
    if len(df_MouseTrack) < 2:
        maxT = df_MouseTrack['t'].max()
        minT = df_MouseTrack['t'].min()
    else:
        t = df_MouseTrack['t']
        
#获取最后一个时间段x,y,t的差分值,以及两个点之间的欧式距离 4个特征
def get_tailFeature(df_MouseTrack):
    if len(df_MouseTrack) < 2:
        xdiff = 0
        ydiff = 0
        tdiff = 0
        dis = 0
        diff_and_Dis = [xdiff, ydiff, tdiff, dis]
    else:
        xdiff = calDiffenceResult(df_MouseTrack['x'])
        ydiff = calDiffenceResult(df_MouseTrack['y'])
        tdiff = calDiffenceResult(df_MouseTrack['t'])
        dis = np.sqrt(xdiff[-1]**2 + ydiff[-1]**2)
        diff_and_Dis = [xdiff[-1], ydiff[-1], tdiff[-1], dis]
    return diff_and_Dis

#速度的平均值, 最大值, 最小值, 方差, 标准差 5个特征
def get_xv_var(df_MouseTrack):
    if len(df_MouseTrack) < 2:
        speedMean = 0
        speedMax = 0
        speedMin - 0
        speedVar = 0
        speedStd = 0
    else:
        speed = calSpeed(df_MouseTrack)
        speedMean = speed.mean()
        speedMax = speed.max()
        speedMin = speed.min()
        speedVar = speed.var()
        speedStd = speed.std()
    speedFeat = [speedMean, speedMax, speedMin, speedVar, speedStd]
    return speedFeat

#加速度的平均值,最大值,最小值,方差,标准差  5个特征
def get_Acc_feat(df_MouseTrack):
    if len(df_MouseTrack) < 3:
        meanAcc = 0
        maxAcc = 0
        minAcc = 0
        varAcc = 0
        stdAcc = 0
    else:
        t = df_MouseTrack['t']
        t1 = np.array(t[0:-1])
        t2 = np.array(t[1:])
        v_t = (t1 + t2) / 2
        v_tdiff = calDiffenceResult(v_t)
        speed = calSpeed(df_MouseTrack)
        SPdiff = calDiffenceResult(speed)
        Accelearation = SPdiff/v_tdiff
        if len(Accelearation) == 0:
            end = 1
        meanAcc = Accelearation.mean()
        maxAcc = Accelearation.max()
        minAcc = Accelearation.min()
        varAcc = Accelearation.var()
        stdAcc = Accelearation.std()
        # reciprocalAcc = 1/Accelearation
    AccFeat = [meanAcc, maxAcc, minAcc, varAcc, stdAcc]
    return AccFeat

#采样最后 20 段时间的方差和标准差 2个特征
def get_t_last20_var(df_MouseTrack):
    tdiff = calDiffenceResult(df_MouseTrack['t'])
    if len(tdiff) >= 20:
        useTdiff = tdiff[-20:]
    else:
        useTdiff = tdiff
    Tvar = useTdiff.var()
    Tstd = useTdiff.std()
    T20feat = [Tvar, Tstd]
    return T20feat

#记录速度的协方差,及相关系数  2个特征
def get_vx_cov_reverse(df_MouseTrack):
    if len(df_MouseTrack) < 4:
        CovXY = 0
        CorrelationCoefficient = 0
    else:
        v = calSpeed(df_MouseTrack)
        v1 = v[0:-1]
        v2 = v[1:]
        vCov = np.cov(v1, v2) #协方差矩阵
        CovXY = vCov[0, 1] #v1和v2的协方差
        CorrelationCoefficient = CovXY/(np.sqrt(vCov[0, 0])*np.sqrt(vCov[1, 1]))  #求解相关系数
    vFeat = [CovXY, CorrelationCoefficient]
    return vFeat

#水平和垂直位移的方差  2个特征
def get_XYvar(df_MouseTrack):
    xdiff = calDiffenceResult(df_MouseTrack['x'])
    ydiff = calDiffenceResult(df_MouseTrack['y'])
    XDiffvar = xdiff.var()
    YDiffvar = ydiff.var()
    disVar = [XDiffvar, YDiffvar]
    return disVar

#时间噪声
def get_t_noisiness(df_MouseTrack):
    end = 1

#获取鼠标轨迹特征
def getFeatures(df_MouseTrack):
    m = len(df_MouseTrack)
    features = []
    features.append(m)

    XYmean = get_XYmean(df_MouseTrack)
    features.extend(XYmean)

    XYEnt = get_XYentropy(df_MouseTrack)
    features.extend(XYEnt)
    MaxMinT = get_MaxMinT(df_MouseTrack)
    features.extend(MaxMinT)

    tailfeat = get_tailFeature(df_MouseTrack)
    features.extend(tailfeat)

    vfeat = get_xv_var(df_MouseTrack)
    features.extend(vfeat)

    accfeat = get_Acc_feat(df_MouseTrack)
    features.extend(accfeat)

    last20tVar = get_t_last20_var(df_MouseTrack)
    features.extend(last20tVar)

    diffVfeat = get_vc_cov_reverse(df_MouseTrack)
    features.extend(diffVfeat)

    xyVar = get_XYvar(df_MouseTrack)
    features.extend(xyVar)

    return features

def make_train_data():
    traindata = pd.DataFrame(np.random.randn(1, len(featureLabels)), columns=featureLabels)
    for i, line in enumerate(fileinput.input(train_path)):
        features = []
        line = line.split()
        a1 = int(line[0]) #获取编号id
        features.append(a1)

        a2 = line[1].split(";")
        temp = [x.split(',') for x in a2]
        temp.pop()
        a2 = np.mat(temp, dtype=float)
        a2 = pd.DataFrame(a2, columns=list('xyt'))
        a2 = a2.groupby('t', as_index=False).first()
        if len(a2) < 2:
            continue
        a2_feature = getFeatures(a2)
        features.extend(a2_feature)

        a3 = line[2].split(',') #目标点的坐标
        a3_x = float(a3[0])
        a3_y = float(a3[1])
        features.append(a3_x) #x坐标
        features.append(a3_y)  #y坐标
        
        label = int(line[3]) #标签
        features.append(label)

        traindata.ix[i] = pd.Series(np.array(features), index=traindata.columns)
    return traindata

def make_test_data():
    testFeatlabels = featureLabels
    testFeatLabels.pop()  #测试样本数据集比训练样本集少一个标签"label"
    testdata = pd.DataFrame(np.random.randn(1, len(testFeatlabels)), columns=testFeatlabels)
    for i, line in enumerate(fileinput.input(test_path)):
        features = []
        line = line.split()
        a1 = int(line[0]) #获取编号id
        features.append(a1)

        a2 = line[1].split(";")
        temp = [x.split(',') for x in a2]
        temp.pop()
        a2 = np.mat(temp, dtype=float)
        a2 = pd.DataFrame(a2, columns=list('xyt'))
        if len(a2) < 3:
            pause = 1
        a2 = a2.groupby('t', as_index=False).first()
        a2_feature = getFeatures(a2)
        features.extend(a2_feature)

        a3 = line[2].split(',') #目标点的坐标
        a3_x = float(a3[0])
        a3_y = float(a3[1])
        features.append(a3_x)  #x坐标
        features.append(a3_y)  #y坐标

        testdata.ix[i] = pd.Series(np.array(features), index=testdata.columns)

    return testdata

if __name__ == '__main__':
    traindata = make_train_data()
    testData = make_test_data(0

    end = 1

说实话,就上面提取特征的方法,如果提取训练集的样本3000条,速度还可以,不是很慢,但是提取测试集的10万条就得花个半个小时,那就更别说最后复赛的200万条了,就是要命了。

 

5.特征提取实践

上一部分分析了,我们提取特征的思路,这一部分就来重点实现这个操作。就是要明白一点,我们的特征大多是统计特征,少部分是分析样本数据集之后,得出的特征,还有就是通过阅读文献得到的特征。最终提取的特征及说明如下:

特征及说明

特征表示说明
轨迹点个数count因为不同轨迹长短不一样,所以考虑使用,count来表示轨迹的长度
x的最小值x_min整个轨迹中,x坐标的最小值
轨迹x方向走一般花的时间比x_ratio

因为鼠标轨迹在x方向上移动时,速度可能不太均匀,所以行走到x方向一半所花的时间占整体时间比较大,但是如果人拖动的话,开始速度很快,后面快接近目标点的时候,会变慢,所以走一半的路花的时间会少一些。

y坐标的最小值y_min 
y坐标的最大值y_max 
x坐标一阶差分后标准差x_diff_std 
x坐标一阶差分后的最大值x_diff_max 
x坐标一阶差分后的最小值x_diff_min 
x坐标一阶差分后的偏度x_diff_skew 
y坐标一阶差分后的平均值y_diff_std 
x坐标回退标记x_back_num因为有的轨迹在往x正方向移动的时候,是有一个目标点的,但是如果x移动越过了目标点,就会往回走。所以,通过该特征来表征轨迹是否有回退的情况
 DisPoint 
 Disx_forlat 
时间轴t差分后的标准差t_diff_mean 
t进行一阶差分后的标准差t_diff_std 
总时间比上x周总路程duration_mean 
走一半路花的时间timehalf 
所有相邻样本点距离最大值xy_diff_std 
相邻样本点速度的标准差vxy_std 
相邻样本点速度的平均值vxy_mean 
轨迹最后两个样本点的速度vxylast 
轨迹最开始两个样本点的速度vxyfirst 
速度序列一阶差分的中值vxy_diff_median 
速度序列一阶差分的平均值vxy_diff_mean 
速度序列一阶差分的最大值vxy_diff_max 
相邻点构成的角度序列的标准差angle_std 
相邻轨迹点的角度序列的峰度angle_kurt 
角度序列一阶差分的均值angle_diff_mean 
角度序列一阶差分的标准差angle_diff_std 
 Dis_pt2dst_diff_max 
 Dis_pt2st_diff_std 
 angle_upTriangle_num样本轨迹中,相邻三个点构成的上三角形的数量
 angle_downTriangle_num赝本轨迹中,相邻三个点构成的下三角形的数量

 

特征提取代码如下(采用pyspark提取特征,速度非常快):

#coding=utf-8

import matplotlib.pyplot as plt
import numpy as np
from pyspark import SparkContext
import sys

output_file = sys.argv[1]
input_file = sys.argv[2]

def get_TES_feat(element):
    feat = []
    data = element.split(" ")
    id = int(data[0])
    trace = data[1][:-1]
    trace = trace.split(';')
    trace = [[int(record.split(',')[0]), int(record.split(',')[1]), int(record.split(',')[2])] for record in trace]
    trace = np.array(trace)
    aim_x = float(data[2].split(',')[0])
    aim_y = float(data[2].split(',')[1])

    x = trace[:, 0]
    y = trace[:, 1]
    t = trace[:, 2]

    count = len(x)

    if len(x) == 1:
        x = np.array([x[0]]*3)
        y = np.array([y[0]]*3)
        t = np.array([t[0]]*3)
    elif len(x) == 2:
        x = np.array([x[0]]+[x[1]] * 2)
        y = np.array([y[0]]+[y[1]] * 2)
        t = np.array([t[0]]+[t[1]] * 2)

    x_min = x.min()
    x_ratio = 1.0*(x[len(x)-1] - x[0]) / len(x)
    y_min = y.min()
    y_max = y.max()

    x_diff = x[1:] - x[0:-1]
    y_diff = y[1:] - y[0:-1]
    t_diff = t[1:] - t[0:-1]
    
    x_diff_std = x_diff.std()
    x_diff_max = x_diff.max()
    x_diff_min = x_diff.min()
    x_diff_skew = ((x_diff**3).mean() - 3*x_diff.mean()*x_diff.var() - x_diff.mean()**3) / (x_diff.var() ** 1.5 + 0.000000001)
    
    y_diff_mean = np.fabs(y_diff[y_diff != 0]).mean()
    y_diff_std = y_diff[y_diff != 0].std()

    x_back_num = (x_diff < 0).sum()

    DisPoint = 1.0 * sum((x_diff ** 2 + y_diff ** 2) ** 0.5) / len(x)
    Disx_forlat = sum(x_diff[0:len(x_diff) / 2]) / (sum(x_diff[len(x_diff) / 2:len(x_diff)]) + 0.000000001)
    
    t_diff_mean = t_diff.mean()
    t_diff_num = t_diff.min()
    t_diff_std = t_diff.std()
    duration_mean = 1.0 * (t[len(t) - 1] - t[0]) / len(x)
    timehalf = np.log1p((t[len(t) / 2] - t[0])) - np.log10(t[len(t) - 1] - t[len(t) / 2])
    
    xy_diff = (x_diff ** 2 + y_diff ** 2) ** 0.5
    xy_diff_max = xy_diff.max()

    Vxy = np.log1p(xy_diff) - np.log1p(t_diff)
    Vxy_diff = Vxy[1:] - Vxy[0:-1]
    Vxy = Vxy[(Vxy > 0) | (Vxy < 1)]
    Vxy_diff = Vxy_diff[(Vxy_diff > 0) | (Vxy_diff < 1)]
    if len(Vxy) < 1:
        vxy_std = 0
        vxy_mean = 0
        vxyfirst = 0
        vxylast = 0
    else:
        vxy_std = Vxy.std()
        vxy_mean = Vxy.mean()
        vxyfirst = Vxy[0]
        vxylast = Vxy[len(Vxy) - 1]

    if len(Vxy_diff) < 1:
        vxy_diff_median = 0
        vxy_diff_mean = 0
        vxy_diff_std = 0
        vxy_diff_max = 0
    else:
        Vxy_diff.sort()
        vxy_diff_median = (Vxy_diff[len(Vxy_diff) / 2] + Vxy_diff[~len(Vxy_diff) / 2]) * 1.0 / 2
        vxy_diff_mean = Vxy_diff.mean()
        vxy_diff_std = Vxy_diff.std()
        vxy_diff_max = Vxy_diff.max()

    angles = np.log1p(y_diff) - np.log1p(x_diff)
    angle_diff = angles[1:] - angles[0:-1]
    angle_diff = angle_diff[(angle_diff > 0) | (angle_diff < 1)]
    angles = angles[(angles > 0) | (angles < 1)]
    if len(angles) < 1:
        angle_std = 0
        angle_kurt = 0
    else:
        angle_std = angles.std()
        angle_kurt = (angles ** 4).mean() / (angles.var() + 0.000000001)

    if len(angle_diff) == 0:
        angle_diff_mean = 0
        angle_diff_std = 0
    else:
        angle_diff_mean = angle_diff.mean()
        angle_diff_std = angle_diff.std()

    Dis_pt2dst = ((x - np.array([aim_x] * len(x))) ** 2 +
                (y - np.array([aim_y] * len(y))) ** 2) ** 0.5
    Dis_pt2dst_diff = Dis_pt2dst[1:] - Dis_pt2dst(0:-1]
    Dis_pt2dst_diff_max = Dis_pt2dst_diff.max()
    Dis_pt2dst_diff_std = Dis_pt2dst_diff.std()

    #方向角
    DirectAngle = np.sign(x_diff).astype(int).astype(str).astype(object) + np.sign(y_diff).astype(int).astype(str).astype(object)
    ConnectDirectAngle = DirectAngle[1:] + DirectAngle[0:-1]
    angle_upTriangle_num = len(ConnectionDirectAngle[ConnectDirectAngle == '111-1'])
    angle_downTriangle_num = len(ConnectionDirectAngle[ConnectDirectAngle == '1-111'])
    
    feat = [count, x_min, x_ratio, y_min, y_max, x_diff_std, x_diff_max, x_diff_min,         x_diff_skew, y_diff_mean,
            y_diff_std, x_back_num, DisPoint, Disx_forlat, t_diff_mean, t_diff_min, t_diff_std, duration_mean, timehalf,
            xy_diff_max, vxy_std, vxy_mean, vxyfirst, vxylast, vxy_diff_median, vxy_diff_mean, vxy_diff_max,
            vxy_diff_std, angle_std, angle_kurt, angle_diff_mean, angle_diff_std, Dis_pt2dst_diff_max,
            Dis_pt2dst_diff_std, angle_upTriangle_num, angle_downTriangle_num]
    feat = list(np.nan_to_num(feat))

    feat_str_list = [str(item) for item in feat]
    feat_str = ' '.join(feat_str_list)

    return feat_str

sc = SparkContext(appName='Test')
rdd = sc.textFile(input_file)
result = rdd.map(get_TES_feat)
result.saveAsTextFile(output_file)
end = 1

6.特征筛选

步骤5已经给出了提取特征的方法以及代码,但是事实上,如果按照统计特征的思维去提取特征的话,少说也得上百维特征了,但是最终我们,只是选取除了其中的36维特征,是因为我们在特征筛选的过程中去除掉了一些表现不好的特征。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

大数据挑战赛-鼠标轨迹识别 的相关文章

  • 几种电平转换电路

    在电路设计时 xff0c 有时会遇到电压域不匹配的问题 xff0c 如芯片为1 8V供电 xff0c 而MCU为3 3V供电 这时候就需要进行电平转换才能通讯 今天就来介绍几种常用的电平转换电路 二 三极管单向电平转换 一些通讯模块 xff
  • STM32的串口硬件流控(RS232/RS485)

    流控的概念源于 RS232 这个标准 xff0c 在 RS232 标准里面包含了串口 流控的定义 RS232 中的 RS 是Recommend Standard 的缩写 xff0c 即 推荐标准 之意 xff0c 它并不像 IEEE 128
  • 头文件中写类的实现出现函数重复定义的问题

    先来做一个实验 xff0c 你在一个头文件中定义一个类 xff0c 然后把内中的一个函数的实现写在这个头文件当中 A test h ifndefine A TEST define A TEST class A void test void
  • 步进电机驱动代码

    步进电机简而言之就是能够通过输入脉冲的个数 xff0c 确定旋转的角位移 xff0c 一般用他来控制小车轮子的偏移角度等 步进电机由驱动芯片ULN2003驱动 xff0c 利用ULN2003与MCU引脚相连 xff0c 可以驱动步进电机 主
  • 全速下载百度云

    用CMD命令下载百度云的资源 听起来类似Linux或者我们在电影里常见的黑客下载数据 需要准备工具 xff1a Windows系统 xff08 我用的是Windows10 xff09 xff0c CMD命令行 xff0c BaiduPCS
  • 几种常用电流互感器采样电路

    我们知道 xff0c 采样电流信号最简单的方法就是通过采样电阻将电流信号转换为电压信号 xff0c 然后再进行放大 采样即可 直流信号一般都可以这样处理 xff0c 但是对于电流互感器出来的交流信号 xff0c 不能直接输入到单极性的AD进
  • 调试程序时怎样查看变量波形?看这里

    我们在调试单片机程序时 xff0c 经常会需要查看某个变量或数组的值 xff0c 一般情况下 xff0c 可以通过 Add xxx to Watch 来查看 xff0c 或直接查看内存 但有时候 xff0c 比如ADC采样时 xff0c 单
  • 几种常用的产生负电源的方法

    电源电路是电路设计的重要环节 xff0c 一般情况下 xff0c 单电源能实现功能的用单电源就行 xff0c 可选的方案很多 xff0c DC DC LDO等芯片很多 有时候 xff0c 单电源无法满足需求时 xff0c 就必须用到负电源
  • 盘点一些国产“有特点”的单片机

    自从芯片涨价潮以来 xff0c 国产芯片 xff0c 尤其是单片机类芯片犹如雨后春笋般发展起来 xff0c 其中也不乏一些优秀的产品 今天来盘点一下一些有特点的单片机 这里所说的单片机 xff0c 是指通用型的MCU xff0c 像ESP3
  • 不会写Bootloader?看这里,现成的

    前段时间要写一个BootLoader程序 xff0c 想起来好像在STM32的HAL库里面看到过相关的Demo xff0c 打算参考一下 打开相关的目录看了一下 xff0c 确实是有相关文件 xff1a 但是没找到工程文件 没办法 xff0
  • 一个IO挂多个按键怎么实现?

    有时候做设计时 xff0c 我们会遇到外部按键比较多 xff0c IO口不够用的情况 这时大部分人会考虑通过其它芯片扩展IO xff0c 或者直接换一个IO口足够的MCU 其实 xff0c 还有个方法可以实现一个IO上挂多个按键 即采用AD
  • SWM32系列教程8--SPI及其应用

    SPI接口是非常常用的一种数字外设 xff0c SWM32S单片机有2个SPI接口 xff0c 其特点如下 xff1a 全双工串行同步收发可编程时钟极性和相位支持 MASTER 模式和 SLAVE 模式MASTER 模式下最高传输速度支持主
  • STM32使用HAL库驱动W5500

    W5500 芯片是一款集成全硬件 TCP IP 协议栈的嵌入式以太网控制器 xff0c 为单片机提供了更加简单 快速 稳定 安全的以太网接入方案 采用标准4线SPI接口 xff0c 理论速率上可以达到 80MHz 硬件设计 原理图如下 xf
  • SWM32系列教程9-SDIO及FatFs文件系统

    SWM32S单片机有1个SDIO接口 xff0c 支持多媒体卡 xff08 MMC xff09 SD 存储卡 SDIO 卡等设备 xff0c 可以使用软件方法或者 DMA 方法 xff08 SDIO 模块内部 DMA xff0c 与芯片 D
  • SWM32系列教程10--SDRAM和LCD

    SWM32S单片机内部集成了8MB的SDRAM以及LCD控制器 xff0c 非常适合用于屏幕驱动 其中LCD控制器支持RGB565格式的接口 xff0c 最大支持1024 768分辨率 今天来介绍一下这两个外设的用法 SDRAM SWM32
  • VSCode的REST Client指南,超好用的HTTP客户端工具

    我最新最全的文章都在 南瓜慢说 www pkslow com xff0c 欢迎大家来喝茶 xff01 1 简介 在做Web应用开发的时候 xff0c 经常需要测试Web接口 xff0c 就需要一些客户端来发送HTTP请求到服务端 常用的客户
  • 开源自己做的4.3寸触摸屏,SWM32单片机+LVGL

    十一假期抽时间把SWM32S做的触摸屏板的综合程序弄了一下 xff0c 板子硬件资源如下 xff1a SWM32S单片机 xff0c LQFP 64封装 xff0c 内置8MB的SDRAM 4 3寸16位RBG接口电容触摸屏 xff0c 8
  • 盘点国产RISC-V内核的单片机

    RISC V就不必多说了 xff0c 它是一个基于精简指令集的开源指令集架构 与主流的主流的架构为x86与ARM架构不同 xff0c 其特点就是完全开源 今天跟大家一起盘点一下国产RISC V内核的单片机 1 GD32VF103系列 兆易创
  • 单片机通过WIFI模块(ESP8266)获取网络时间与天气预报

    前几天发布了开源4 3寸触摸屏的文章 开源4 3寸触摸屏 xff0c 里面有WIFI获取时间和天气预报相关的功能 xff0c 今天就来介绍一下这个功能是怎样实现的 1 底层驱动 首先 xff0c 硬件上 xff0c 单片机通过串口AT指令访
  • 开源贴片机OpenPnp使用体验

    平时做板子比较多 xff0c 一直想整一个贴片机 xff0c 但是据说国产的桌面贴片机用起来都不咋地 xff0c 而且价格也不菲 xff0c 带视觉的将近2W 思来想去选择了OpenPnP xff0c 一方面价格便宜 xff0c 另一方面开

随机推荐

  • 【干货】STM32通过ADC模拟看门狗实现掉电保存

    1 前言 很多时候我们需要将程序中的一些参数 数据等存储在EEPROM或者Flash中 xff0c 达到掉电保存的目的 但有些情况下 xff0c 程序需要频繁的修改这些参数 xff0c 如果每次修改参数都进行一次保存 xff0c 那将大大降
  • 【开源项目】SFUD--通用串口Flash驱动库的移植和使用

    1 简介 SFUD 是一款开源的串行 SPI Flash 通用驱动库 由于现有市面的串行 Flash 种类居多 xff0c 各个 Flash 的规格及命令存在差异 xff0c SFUD 就是为了解决这些 Flash 的差异现状而设计 xff
  • STM32F0系列中断向量映射问题

    最近用Cortex M0内核的STM32F030K6T6做个东西 xff0c 需要做IAP升级 xff0c 发现它的中断向量与M3 M4等内核的单片机不太一样 xff0c 这里分享给大家 IAP升级需要一个BootLoader程序 xff0
  • STM32定时器实现红外接收与解码

    1 NEC协议 红外遥控是一种比较常用的通讯方式 xff0c 目前红外遥控的编码方式中 xff0c 应用比较广泛的是NEC协议 NEC协议的特点如下 xff1a 载波频率为 38KHz 8 位地址和 8位指令长度 地址和命令2次传输 xff
  • SPI读写SD卡速度有多快?

    SD卡是一个嵌入式中非常常用的外设 xff0c 可以用于存储一些大容量的数据 但用单片机读写SD卡速度一般都有限 xff08 对于高速SD卡 xff0c 主要是受限于单片机本身的接口速度 xff09 xff0c 在高速 实时数据存储时可能会
  • SPI方式读写SD卡速度有多快?

    很久没有写公众号了 xff0c 一方面忙 xff0c 另一方面也不知道写些什么内容 xff0c 大家如果有想了解的 xff08 前提是我也懂 xff09 xff0c 可以后台发送给我 今天主要来测试一下SPI读写SD卡的速度 SD卡是一个嵌
  • 火狐浏览器添加脚本(可代替手动做一些操作)

    首先打开火狐浏览器的更多组件 xff0c 在扩展中搜索Greasemonkey 然后点击安装 安装成功后点立即重启 重新打开浏览器后浏览器右上角会有一个猴子的图标 点击下标按钮 xff0c 新建用户脚本 xff0c 新建用户脚本可以随意命名
  • SDIO读写SD卡速度有多快?

    前两天测试了SPI方式读写SD卡的速度 SPI方式读写SD卡速度测试 xff0c 今天来测试一下SDIO方式的读写速度 测试条件 xff1a 单片机 xff1a STM32F407VET6 编译环境 xff1a MDK 5 30 43 HA
  • STM32CubeMx+HAL库实现USB CDC+MSC复合设备

    之前的文章中介绍过STM32的USB应用 xff0c 包括虚拟串口 xff08 CDC xff09 和大容量存储设备 xff08 MSC xff09 今天来介绍USB实现CDC和MSC复合设备的方法 硬件 xff1a STM32F407VE
  • 基于STM32CubeMx的USB CDC+MSC复合设备

    之前的文章中介绍过STM32的USB应用 xff0c 包括虚拟串口 xff08 CDC xff09 和大容量存储设备 xff08 MSC xff09 今天来介绍USB实现CDC和MSC复合设备的方法 硬件 xff1a STM32F407VE
  • go标准库httputil.ReverseProxy简单介绍和使用避坑

    很久没水博客了 xff0c 今天就来水一篇 xff0c 说说go标准库的httputil ReverseProxy httputil ReverseProxy顾名思义 xff0c http的反向代理 xff0c 可以类比nginx的反向代理
  • (二)Ardupilot软件分析及代码架构

    先要搞明白ardupilot是怎么实现飞行控制的 xff1f 然后再看文件 1 建立两个基本坐标系 xff1a 地理坐标系和载体坐标系 xff0c 保证两个基本坐标系的正确转化 一般使用旋转矩阵实现坐标系转换 xff1a 四元数运算 q01
  • STM32F103 实例应用——实现透传转发串口

    一 预期准备 实现机制 xff1a 空闲中断 43 DMA中断接收不定长串口数据 开发工具 xff1a STM32F103芯片 xff0c keil5 xff0c usb转ttl工具 预计实现效果 xff1a 串口1接收数据然后透传给串口2
  • 解决:ORA-06550 字符串长度限制在范围 (1...32767)

    错误信息 ORA 06550 第 1 行 第 782 列 PLS 00215 字符串长度限制在范围 1 32767 解决 本例是配置存储过程job的job action 61 gt 39 Declare FLAG Number 20 FAI
  • gcc、make、makefile、cmake、cmakelists区别

    转自 xff1a http www zhihu com question 36609459 辉常哥 1 gcc是GNU Compiler Collection xff08 就是GNU编译器套件 xff09 xff0c 也可以简单认为是编译器
  • FIFO和DMA

    FIFO SPI端口增加了FIFO xff0c 使得传输数据有了缓冲区间 FIFO存储器是一个先入先出的双口缓冲器 xff0c 即第一个进入其内的数据第一个被移出 xff0c 其中一个存储器的输入口 xff0c 另一个口是存储器的输出口 主
  • 蓝桥杯C语言基础练习 十进制转十六进制

    代码 xff08 解法类似十进制转二 八进制 xff09 include lt stdio h gt char getnum int z switch z case 0 return 39 0 39 break case 1 return
  • Linux和Windows下使用printf的差别

    1 Linux系统下 一般而言 xff0c 大家都知道printf是带有行缓冲的函数 xff0c printf把打印的消息先输出到行缓冲区 xff0c 在以下几种情况下 xff1a 1 程序结束时调用exit 0 return xff1b
  • Could not connect ot Redis No route to host问题解决

    局域网内访问另外一台服务器上的redis 报错 Could not connect to Redis No route to host 问题解决 发现是防火墙问题 于是设置 iptables N REDIS iptables A REDIS
  • 大数据挑战赛-鼠标轨迹识别

    大数据挑战赛 鼠标轨迹识别 xff0c 竞赛官网 xff1a http bdc saikr com c cql 34541 1 我们看一下整个竞赛的详情 赛题描述 鼠标轨迹识别当前广泛运用于多种人机验证产品中 xff0c 不仅便于用户的理解