转换R中的IP地址

wax*_*tax 1 ip r ip-address

我有一个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地址),而不是单个地址.

hrb*_*str 5

在我的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.tablerbindlist,因为它有一个很好的fill,在缺少列填充选项.

我有一个较旧的MaxMind纯R软件包:https://github.com/hrbrmstr/Rmaxmind:这可以提供帮助,iptools我上面提到的基于Rcpp的软件包也可以进行IPv4地址的地理定位.

如果您尝试使用此答案中的代码,我强烈建议您将查找表存储起来,data.table因为它会显着提高效率(并且还有加速查询的方法).您还可以将查找表存储在SQL数据库中,并使用智能索引和查询优化以这种方式执行查找.