我有一个IP地址的数据集(dat),其格式如下:
Person IP_Address
267 555.66.44.222
299 111.222.55.22
513 222.111.8.777
524 888.88.333.222
Run Code Online (Sandbox Code Playgroud)
我还有一个IP地址的数据库(db),其格式如下:
First_IP_Address_In_Netblock Last_IP_Address_In_Netblock Latitude Longitude
16777216 16777471 -27.48333 153.01667
16777472 16778239 26.06139 119.30611
16778240 16779263 -37.814 144.96332
16779264 16781311 23.11667 113.25
16781312 16785407 35.689506 139.6917
16785408 16793599 23.11667 113.25
16793600 16797695 34.38528 132.45528
16797696 16798719 35.689506 139.6917
16798720 16799743 34.38528 132.45528
16799744 16799999 35.689506 139.6917
Run Code Online (Sandbox Code Playgroud)
我的问题有两个:1)我如何转换IP地址(来自数据集或数据库),以便它们采用相同的格式?2)我怎样才能将每个人的纬度和经度相匹配?第二个问题是让我感到困惑,因为每个坐标都与一系列IP地址相关联(从网络块中的第一个IP地址到网络块中的最后一个IP地址),而不是单个地址.
在我的iptools包(https://gitlab.dds.ec/bob.rudis/iptools)中,我有一个ip2long函数可以将IPv4字符串转换为长整数.它是基于Rcpp的,需要Boost标头.以下是纯R实现:
ip2long <- function(ip) {
# convert string into vector of characters
parts <- unlist(strsplit(ip, '.', fixed=TRUE))
# set up a function to bit-shift, then "OR" the octets
octets <- function(x,y) bitOr(bitShiftL(x, 8), y)
# Reduce applys a funcution cumulatively left to right
Reduce(octets, as.integer(parts))
}
Run Code Online (Sandbox Code Playgroud)
注意:这需要bitops包.
然后,您可以将IP地址转换为长整数,并检查它是否在第一个和最后一个IP网络地址之间.即:像:
library(data.table)
library(bitops)
ip2long <- function(ip) {
# convert string into vector of characters
parts <- unlist(strsplit(ip, '.', fixed=TRUE))
# set up a function to bit-shift, then "OR" the octets
octets <- function(x,y) bitOr(bitShiftL(x, 8), y)
# Reduce applys a funcution cumulatively left to right
Reduce(octets, as.integer(parts))
}
# i added the 1.0.0.2 entry to show you the result
dat <- read.table(text="Person IP_Address
267 555.66.44.222
299 111.222.55.22
513 222.111.8.777
555 1.0.0.2
524 888.88.333.222", stringsAs=FALSE, header=TRUE)
lookup <- read.table(text="First_IP_Address_In_Netblock Last_IP_Address_In_Netblock Latitude Longitude
16777216 16777471 -27.48333 153.01667
16777472 16778239 26.06139 119.30611
16778240 16779263 -37.814 144.96332
16779264 16781311 23.11667 113.25
16781312 16785407 35.689506 139.6917
16785408 16793599 23.11667 113.25
16793600 16797695 34.38528 132.45528
16797696 16798719 35.689506 139.6917
16798720 16799743 34.38528 132.45528
16799744 16799999 35.689506 139.6917", stringsAs=FALSE, header=TRUE)
rbindlist(lapply(dat$IP_Address, function(ip) {
ip_long <- ip2long(ip)
res <- lookup[ip_long>=lookup$First_IP_Address_In_Netblock &
ip_long<=lookup$Last_IP_Address_In_Netblock, c(3,4)]
if (nrow(res) > 0) {
return(data.table(ip=ip, res))
} else {
return(data.table(ip=ip))
}
}), fill=TRUE)
## ip Latitude Longitude
## 1: 555.66.44.222 NA NA
## 2: 111.222.55.22 NA NA
## 3: 222.111.8.777 NA NA
## 4: 1.0.0.2 -27.48333 153.0167
## 5: 888.88.333.222 NA NA
Run Code Online (Sandbox Code Playgroud)
我使用data.table的rbindlist,因为它有一个很好的fill,在缺少列填充选项.
我有一个较旧的MaxMind纯R软件包:https://github.com/hrbrmstr/Rmaxmind:这可以提供帮助,iptools我上面提到的基于Rcpp的软件包也可以进行IPv4地址的地理定位.
如果您尝试使用此答案中的代码,我强烈建议您将查找表存储起来,data.table因为它会显着提高效率(并且还有加速查询的方法).您还可以将查找表存储在SQL数据库中,并使用智能索引和查询优化以这种方式执行查找.
| 归档时间: |
|
| 查看次数: |
2130 次 |
| 最近记录: |