转换R中的IP地址

时间:2014-10-22 16:30:05

标签: r ip 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

我还有一个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

我的问题有两个: 1)如何转换IP地址(来自数据集或数据库),以便它们采用相同的格式? 2)我怎样才能将每个人的纬度和经度相匹配?第二个问题让我感到困惑,因为每个坐标都与一系列IP地址相关联(从网络块中的第一个IP地址到网络块中的最后一个IP地址),而不是一个地址。

1 个答案:

答案 0 :(得分: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))
}

注意:这需要bitops包。

然后,您可以将IP地址转换为长整数,并检查它是否在First&amp;最后的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

我正在使用data.table的{​​{1}},因为它有一个很好的rbindlist选项,可以填充缺少的列。

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

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