Нижегородский Государственный Технический Университет им. Р.Е.Алексеева Кафедра «Вычислительные системы и технологии» Отчет по дисциплине: Основы предиктивной аналитики «Анализ данных мобильного оператора. Поиск пути. Поиск владельца устройств.» Выполнил: студент группы М14-ИВТ-3 Сидоренко О.О. Проверил: Крылов В.В. Нижний Новгород 2015 год Задание. По заданным исходным данным вывести на карты путь для каждого устройства и определить такие пары устройств, которые принадлежат одному человеку. Вывод пути для каждого устройства Для вывода путей для всех устройств на карту необходим следующий минимальный набор данных: Идентификатор устройства Географичческие координаты точек-отметок Показатель последовательности точек-отметок Учитывая исходные данные можно обозначить за идентификатор устройства поле с IMEI, за показатель последовательности поле tstamp. А географически координаты точек-отметок устройства представлены несколько иначе: в исходных данных нет точного местоположения устройства в каждый момент времени, однако есть географические координаты вышки связи, где зарегистрировалось устройство в определенный момент времени, а также радиус действия вышки и начальный и конечный углы окружности с центром – вышкой. Т.о. можно получить сектор, где точно находится абонент (устройство) и вычислив центр масс этого сектора получим более точное расположение устройства. Перед работой вывода исходные данные, представленные в таблице, сортируются по времени; в отдельный объект выносятся все имеющиеся идентификаторы устройств; рассчитываются географические координаты центров масс секторов, о которых сказано выше. Далее для каждого устройства идет обращения к сервису Google Maps для получения изображения карты местности и затем последовательно на карту наносятся географические координаты центров масс секторов и проводятся к ним стрелки. В итоге получается набор изображений, подобных рис.1 Рис.1 Путь устройства 2 Определение пар устройств. Из тех данных, что имеются по условию, для определения пары устройств (далее ПУ), принадлежащих одному владельцу, разумным видится использование путей, которые прошли эти устройства. Существует несколько способов найти ПУ, используя пути, но все они основываются на том, что пути каждого устройства должны более-менее совпадать. Таким образом, необходимо найти некий показатель для каждого пути, который будет критерием выбора при объединении путей в группу. Этот показатель может быть представлен не одним значением, а несколькими. Так, например, можно определить ПУ, находя пути, где вышки (т.е. и центры масс их секторов) расположены очень близко друг к другу или совпадают. Однако в данной работе используется несколько показателей, представленных каждый одним значением, это Среднее и Время. Рассмотрим их подробнее: Среднее – среднее арифметическое значение по одной из географических координат всех центров масс секторов вышек на пути. Этот показатель очень грубо отсеивает пути, т.к. возможно существуют пути с близкими средними, но один из путей либо расположен «вокруг» другого, либо направлен в обратную сторону, либо включает в себя другой путь. Пример на рис.2, 3 – оба пути имеют приблизительно одинаковое Среднее, но физически не могут совершаться одним и тем же абонентом в одно и то же время. Время – разница между временем регистрации на первой вышки пути и временем регистрации на последней вышке. Если устройства принадлежат одному абоненту, и он использует их параллельно, то время регистрации на крайних вышках, и, следовательно, время всего пути, будет приблизительно равным. Однако при использовании этого показателя резко отбрасываются такие варианты, где путь в одну сторону абонент прошел с одним устройством, а в обратную – с другим. Или где этот путь совершался одним и тем же абонентом с разными устройствами, но в два разных дня. Аналогично Среднему, этот показатель пропускает разнонаправленные пути. Рис.2 Рис.3 Для сравнения показателей между собой необходимо определить какую-либо погрешность позволяющую определить промежуток, в которую должен входить показатель. Для этого можно ввести т.н. «степень схожести» двух чисел – показатель, не имеющий под собой физического смысла, лишь численно определяющий насколько одно из чисел близко к другому. В дальнейшем достаточно будет сравнить «степень схожести» с каким либо порогом. Сам алгоритм достаточно прост: после определения показателей необходимо разделить пути на группы, используя сравнение с порогом, а после прохождения нескольких порогов можно будет дать результат. Сравним полученные результаты при использовании только одного показателя (Среднее) с результатами при использовании двух показателей подряд. Т.к. приблизительные ответы уже были предоставлены, то достаточно будет найти общие ПУ между полученными результатами и ответами. Результаты сравнения приведены в таблице 1. 3 Таблица 1. Решение задачи Использованные Порог показатели Среднее 0.99999 Среднее; Время 0.99999 Среднее 0.9999 Среднее; Время 0.9999 Найдено ПУ 34 1 1049 2 Совпало с ответом 1 0 18 Часть ответа 158530782111 158520030347 158515687371 158515687709 158500730487 158500730293 158524011029 158515590685 158526303217 158526252825 158537942677 158522930839 158506092285 158501557263 158530782111 158520030347 0 Как видно, такой алгоритм показал не лучшие результаты, но сработал – можно говорить о том, что одна ПУ точно была найдена. Однако, заменив сравнение «степени схожести» на классическое определение попадания в промежуток можно изменить результат. Таблица 2. Решение задачи альтернативным способом: без «степени схожести» Использованные Порог Найдено ПУ Совпало с Часть ответа показатели ответом 158515687371 Среднее 0.01 4707 30 158515687709 158514437601 158507135235 158529952561 158529633307 158500730487 158500730293 158524011029 158515590685 158526303217 158526252825 158516497707 158500941403 158537942677 158522930839 158506092285 158501557263 158598060279 158533714541 158507689477 158526742489 158520675947 158536558521 158530782111 158520030347 158529027621 158500411793 Среднее; Время 0.01;1000000 111 1 В данном случае увеличилось количество ответов в обоих случаях, однако увеличилось и количество найденных ПУ. Это говорит о том, что необходимо более точно выставлять пороги. 4 Вывод Из двух заданий было успешно выполнено только первое – вывод пути на карту. Второе задание вызвало затруднения из-за нехватки данных и, как следствие, из-за отсутствия грамотно поставленных условий отсева результатов. Однако на заданных данных алгоритм сработал достаточно верно. 5 Приложение library(ggmap) library(mapproj) library(RgoogleMaps) library(maptools) library(rgdal) library(sp) data_mobile<-read.csv(file = "02_Data_mobile.csv",sep = ";", header = TRUE) na.omit(data_mobile)# проверили на NA data_sort<-data_mobile[order(data_mobile$tstamp),] #отсортировали по таймштампу #plot(data_sort$long ~ data_sort$lat,pch=19,type="o",col=data_sort$imei, xlab="Lat",ylab="Long") all_imei<-data.frame(imei = data_sort$imei) #вытащили все имеи #убрали одинаковые имеи, null и пустые строки. Тут null как текст будет, поэтому и убираем all_imei<-subset(all_imei,!duplicated(all_imei$imei) & all_imei$imei!="null" & all_imei$imei!="") attach(data_sort)#чтобы не использовать длинное обращение к элементу #Определили нулевые координаты startY <- long[1] startX <- lat[1] #Рассчитали ГЕОМЕТРИЧЕСКИЕ координаты вышек. в км data_sort$oldY <- 6371*sin(long-startY) data_sort$oldX <- 6371*sin(lat-startX) #рассчитали геометрические координаты центров секторов около вышек data_sort$Y <- data_sort$oldY + (2/3)*0.001*max_dist*2*sin(0.5*abs(end_angle-start_angle))*cos(start_angle+0.5*abs(end_anglestart_angle))/(abs(end_angle-start_angle)*pi/180) data_sort$X <- data_sort$oldX + (2/3)*0.001*max_dist*2*sin(0.5*abs(end_angle-start_angle))*sin(start_angle+0.5*abs(end_anglestart_angle))/(abs(end_angle-start_angle)*pi/180) #рассчитали ГЕОГРАФИЧЕСКИЕ координаты центров секторов около вышек data_sort$longMID <- asin(data_sort$Y/6371)+startY data_sort$latMID <- asin(data_sort$X/6371)+startX data_sort<-subset(data_sort,longMID > 0 & latMID > 0 ) na.omit(data_sort) #Рисуем пути for(j in 1:20) #nrow(all_imei)) { data_imei<-data_sort[data_sort$imei==all_imei$imei[j],] na.omit(data_imei) lonlat<-data.frame(lon = data_imei$longMID,lat = data_imei$latMID) data_imei_uniq<-lonlat[!duplicated(lonlat),]#unique(lonlat) data_imei_uniq<-subset(data_imei_uniq,lon > 0 & lat > 0) mymap = MapBackground(lat=data_imei_uniq$lat, lon=data_imei_uniq$lon, zoom = 13, NEWMAP = TRUE, GRAYSCALE = FALSE, ) PlotOnStaticMap(mymap, data_imei_uniq$lat[1], data_imei_uniq$lon[1], cex=1.5, pch=19, col=c('red'), add=FALSE ) PlotOnStaticMap(mymap, data_imei_uniq$lat[1], data_imei_uniq$lon[1], FUN=text, labels = "First", col=c('blue'), add=TRUE ) if(nrow(data_imei_uniq)>1) { 6 for(i in 2:nrow(data_imei_uniq)) { PlotOnStaticMap(mymap, data_imei_uniq$lat[i], data_imei_uniq$lon[i], cex=1.5, pch=19, col=c('red'), add=TRUE ) PlotArrowsOnStaticMap(mymap, lat0=data_imei_uniq$lat[i-1], lon0=data_imei_uniq$lon[i-1], lat1=data_imei_uniq$lat[i], lon1=data_imei_uniq$lon[i], col=c('blue'), add=TRUE ) } } setwd("D:/MyFiles/work/maps") filename<-paste0("map",all_imei$imei[j],".png") dev.print(png, width = 640, file = filename) setwd("D:/MyFiles/work") } #Попробуем найти пары девайсов #Функция выводит степень похожести двух чисел. Вообще не имеет физического смысла Similarities = function (x, y) { if((x-y)==0) {result<-1} else { result<-(x-y)/((x+y)/2) result<-1-abs(result) } return(result) } #создадим фрейм со средними значениями путей для каждого IMEI и разницей таймштампов пути all_imei_info<-data.frame() for(i in 1:length(all_imei$imei)) { lat_info<- data_sort$latMID[data_sort$imei == all_imei$imei[i]] lon_info<- data_sort$longMID[data_sort$imei == all_imei$imei[i]] tstamp <- max(data_sort$tstamp[data_sort$imei == all_imei$imei[i] & data_sort$tstamp>0])- min(data_sort$tstamp[data_sort$imei == all_imei$imei[i] & data_sort$tstamp>0]) all_imei_info<-rbind(all_imei_info, data.frame(imei = all_imei$imei[i], latMean = mean(lat_info), lonMean = mean(lon_info), time = tstamp )) } #попробуем выдрать пути epsylon <- 0.01#точность приближения epsylonTstamp <- 10000 relatePath<-data.frame() for(i in 1:length(all_imei$imei)) { #среднее значение пути для основного IMEI latM_1<-all_imei_info$latMean[i] #[all_imei_info$imei == all_imei$imei[i]] lonM_1<-all_imei_info$lonMean[i] #[all_imei_info$imei == all_imei$imei[i]] for(j in i:length(all_imei)) { if (j==i){ next } #среднее значение пути для меняющегося IMEI latM_2<-all_imei_info$latMean[j] #[all_imei_info$imei == all_imei$imei[j]] lonM_2<-all_imei_info$lonMean[j] #[all_imei_info$imei == all_imei$imei[j]] 7 #Вычислим степень похожести средних значений путей. measureSimil_lat<-Similarities(latM_1,latM_2) measureSimil_lon<-Similarities(lonM_1,lonM_2) if(measureSimil_lat<0.9999) {next} if(measureSimil_lon<0.9999) {next} #Альтернатива: если средния значения выходят за рамки, то выход на след итерацию #if ((latM_2<latM_1-epsylon)||(latM_2>latM_1+epsylon)) { next } #if ((lonM_2<lonM_1-epsylon)||(lonM_2>lonM_1+epsylon)) { next } #Проверка на схожесть показателей дельта времени firstTstamp_1 <- all_imei_info$time[i] firstTstamp_2 <- all_imei_info$time[j] compare<-Similarities(firstTstamp_1,firstTstamp_2) if(compare<0.9999) {next} #Альтернатива: если значения выходят за рамки, то выход на след итерацию #if ((firstTstamp_2<firstTstamp_1-epsylonTstamp) # ||(firstTstamp_2>firstTstamp_1+epsylonTstamp)) { next } relatePath<-rbind(relatePath,data.frame(imei_1 = all_imei$imei[i], imei_2 = all_imei$imei[j] )) } } #выведем вместо imei msisdn relatePath_msisdn<-data.frame() for(i in 1:length(relatePath$imei_1)) { msisdn_first <- data_sort$msisdn[data_sort$imei == relatePath$imei_1[i]][1] msisdn_second <- data_sort$msisdn[data_sort$imei == relatePath$imei_2[i]][1] relatePath_msisdn<-rbind(relatePath_msisdn, data.frame(msisdn_1 = msisdn_first, msisdn_2 = msisdn_second)) } #Запишем результаты в таблицу write.table(relatePath_msisdn, file = "Result.csv", row.names = FALSE, sep=";") #Выведем результаты данных ответов в подобный фрейм RightAnswer_msisdn<-read.csv(file = "Answer.csv",sep = ";", header = FALSE) #Выведем одинаковые значения между полученным и данным результами result<-data.frame() for(i in 1:length(relatePath_msisdn$msisdn_1)) { for(j in 1:length(RightAnswer_msisdn$V1)) { if(relatePath_msisdn$msisdn_1[i] == RightAnswer_msisdn$V1[j]) { if(relatePath_msisdn$msisdn_2[i]!=RightAnswer_msisdn$V2[j]) {next} } else if(relatePath_msisdn$msisdn_1[i] == RightAnswer_msisdn$V2[j]) { if(relatePath_msisdn$msisdn_2[i]!=RightAnswer_msisdn$V1[j]) {next} } else {next} result<-rbind(result,data.frame(msisdn_1 = relatePath_msisdn$msisdn_1[i], msisdn_2 = relatePath_msisdn$msisdn_2[i] )) } } 8