【发布时间】:2019-02-09 01:13:38
【问题描述】:
我有一个用户及其 ip 地址的 pandas 数据框:
users_df = pd.DataFrame({'id': [1,2,3],
'ip': ['96.255.18.236','105.49.228.135','104.236.210.234']})
id ip
0 1 96.255.18.236
1 2 105.49.228.135
2 3 104.236.210.234
还有一个单独的数据框,其中包含网络范围和相应的地理名称 ID:
geonames_df = pd.DataFrame({'network': ['96.255.18.0/24','105.49.224.0/19','104.236.128.0/17'],
'geoname': ['4360369.0','192950.0','5391959.0']})
geoname network
0 4360369.0 96.255.18.0/24
1 192950.0 105.49.224.0/19
2 5391959.0 104.236.128.0/17
对于每个用户,我需要针对所有网络检查他们的 ip,并提取相应的地理名称并将其添加到 users_df。我想要这个作为输出:
id ip geonames
0 1 96.255.18.236 4360369.0
1 2 105.49.228.135 192950.0
2 3 104.236.210.234 5391959.0
在此示例中很简单,因为它们的顺序正确且只有 3 个示例。实际上,users_df 有 4000 行,geonames_df 有超过 300 万行
我目前正在使用这个:
import ipaddress
networks = []
for n in geonames_df['network']:
networks.append(ipaddress.ip_network(n))
geonames = []
for idx, row in users_df.iterrows():
ip_address = ipaddress.IPv4Address(row['ip'])
for block in networks:
if ip_address in block:
geonames.append(str(geonames_df.loc[geonames_df['network'] == str(block), 'geoname'].item()))
break
users_df['geonames'] = geonames
由于数据帧/列表上的嵌套循环,这非常慢。有没有更快的方法来利用 numpy/pandas?或者至少某种方式比上面的方法更快?
对此有类似的问题 (How can I check if an ip is in a network in python 2.x?),但 1) 它不涉及 pandas/numpy,2) 我想针对 多个网络 检查多个 IP,以及 3) 投票最高答案无法避免嵌套循环,这就是我性能缓慢的原因
【问题讨论】:
-
我认为您将在这里遇到的问题是在内部 for 循环中使用 pandas 函数。如果您可以将其转换为更底层的形式,那么您可以使用 Numba、Cython 等。不过,我看不到加速外部 for 循环的方法,因为您正在调用第三方库。
-
105.49.228.135如何映射到105.49.224.0/19范围?
标签: python python-3.x pandas ip