>我在熊猫中有两个数据帧。
import pandas as pd
inp1 = [{'network':'1.0.0.0/24', 'A':1, 'B':2}, {'network':'5.46.8.0/23', 'A':3, 'B':4}, {'network':'78.212.13.0/24', 'A':5, 'B':6}]
df1 = pd.DataFrame(inp)
print("df1", df1)
inp2 = [{'ip':'1.0.0.10'}, {'ip':'blahblahblah'}, {'ip':'78.212.13.249'}]
df2 = pd.DataFrame(inp2)
print("df2", df2)
输出:
network A B
0 1.0.0.0/24 1 2
1 5.46.8.0/23 3 4
2 78.212.13.0/24 5 6
ip
0 1.0.0.10
1 blahblahblah
2 78.212.13.249
我想要的最终输出如下所示:
ip A B
0 1.0.0.10 1 2
1 blahblahblah NaN Nan
2 78.212.13.249 5 6
我想遍历df2['ip']
中的每个单元格,并检查它是否属于df1['network']
中的网络。如果它属于网络,它将返回特定 IP 地址的相应 A 和 B 列。我已经参考了这篇文章并考虑了netaddr, IPNetwork, IPAddress, ipaddress
但无法完全弄清楚。
感谢帮助!
您可以使用netaddr
+apply()
来做到这一点。下面是一个示例:
from netaddr import IPNetwork, IPAddress, AddrFormatError
network_df = pd.DataFrame([
{'network': '1.0.0.0/24', 'A': 1, 'B': 2},
{'network': '5.46.8.0/23', 'A': 3, 'B': 4},
{'network': '78.212.13.0/24', 'A': 5, 'B': 6}
])
ip_df = pd.DataFrame([{'ip': '1.0.0.10'}, {'ip': 'blahblahblah'}, {'ip': '78.212.13.249'}])
# create all networks using netaddr
networks = (IPNetwork(n) for n in network_df.network.to_list())
def find_network(ip):
# return empty string when bad/wrong IP
try:
ip_address = IPAddress(ip)
except AddrFormatError:
return ''
# return network name as string if we found network
for network in networks:
if ip_address in network:
return str(network.cidr)
return ''
# add network column. set network names by ip column
ip_df['network'] = ip_df['ip'].apply(find_network)
# just merge by network columns(str in both dataframes)
result = pd.merge(ip_df, network_df, how='left', on='network')
# you don't need network column in expected output...
result = result.drop(columns=['network'])
print(result)
# ip A B
# 0 1.0.0.10 1.0 2.0
# 1 blahblahblah NaN NaN
# 2 78.212.13.249 5.0 6.0
请参阅评论。希望这有帮助。
如果你愿意使用R而不是Python,我写了一个IP地址包可以解决这个问题。仍然有一个底层循环,但它是在C++中实现的(更快!
library(tibble)
library(ipaddress)
library(fuzzyjoin)
addr <- tibble(
address = ip_address(c("1.0.0.10", "blahblahblah", "78.212.13.249"))
)
#> Warning: Problem on row 2: blahblahblah
nets <- tibble(
network = ip_network(c("1.0.0.0/24", "5.46.8.0/23", "78.212.13.0/24")),
A = c(1, 3, 5),
B = c(2, 4, 6)
)
fuzzy_left_join(addr, nets, c("address" = "network"), is_within)
#> # A tibble: 3 x 4
#> address network A B
#> <ip_addr> <ip_netwk> <dbl> <dbl>
#> 1 1.0.0.10 1.0.0.0/24 1 2
#> 2 NA NA NA NA
#> 3 78.212.13.249 78.212.13.0/24 5 6
创建于 2020-09-02 由 reprex 软件包 (v0.3.0(