python - Python / pandas:创建数据框的列并根据在另一个数据框范围内找到列值来设置它的值
问题描述
我有两个熊猫数据框,第一帧 ip2CountryDF 有 2M+ 记录:
startIP, endIP, countryISO
16777216,16777471,US
16777472,16778239,CN
16778240,16779263,AU
出于效率和匹配目的,此数据帧中的 IP 地址表示为整数
第二帧 inputDF 有 60K+ 记录:
sourceIP, eventTime, integerIP
114.119.157.43,01/Mar/2021,1920441643
193.205.128.7,01/Mar/2021,3251470343
193.205.128.7,01/Mar/2021,3251470343
193.205.128.7,01/Mar/2021,3251470343
我拥有的数据都来自公开可用的数据集
我要做的是根据 ip2CountryDF 中的值识别 inputDF 中每一行的源国家/地区。
理想情况下,我将选择 inputDF['integerIP'] 并获取 ip2CountryDF['countryISO'] 其中 inputDF 的 integerIP 在 ip2CountryDF['startIP'] 和 ip2CountryDF['endIP'] 之间的范围内
到目前为止,我使用 for 循环完成了数据,它适用于测试集(在 inputDF 中搜索 5 个条目的数据),但是当我遇到更大的数据集时,我的机器粉丝会拿起,几分钟后我没有得到任何结果并且我取消了工作(这告诉我我的代码效率如何),这是我使用的代码(效率低但有效):
countryList = []
for index, row in inputDF.iterrows():
integerIP = row['integerIP']
countryISO = ip2CountryDF.loc[(integerIP >= ip2CountryDF['startIP']) & (integerIP <= ip2CountryDF['endIP']),'countryISO'].iloc[0]
countryList.append(countryISO)
inputDF['countryISO'] = countryList
我需要什么帮助,能否以更有效和更(类似熊猫)的方式更好地处理,我试图使用类似的东西:
inputDF['countryISO'] = ip2CountryDF.loc[(inputDF['integerIP'] >= ip2CountryDF['startIP']) & (inputDF['integerIP'] <= ip2CountryDF['endIP']),'countryISO'].iloc[0]
非常感谢您花时间帮助我解决这个问题
解决方案
你是如此接近。您只是缺少对“地图”功能的调用。
加载 IpToCountry.csv(用于文档目的):
IP2COUNTRY = "https://github.com/urbanadventurer/WhatWeb/raw/master/plugins/IpToCountry.csv"
db = pd.read_csv(IP2COUNTRY, header=None, usecols=[0, 1, 4],
names=["startIP", "endIP", "countryISO"], comment="#")
>>> db
startIP endIP countryISO
0 0 16777215 ZZ
1 16777216 16777471 AU
2 16777472 16777727 CN
3 16777728 16778239 CN
4 16778240 16779263 AU
... ... ... ...
211757 4211081216 4227858431 ZZ
211758 4227858432 4244635647 ZZ
211759 4244635648 4261412863 ZZ
211760 4261412864 4278190079 ZZ
211761 4278190080 4294967295 ZZ
[211762 rows x 3 columns]
创建一个函数ip2country
,为十进制 ip 返回相应的 iso 国家代码:
def ip2country(ip: int):
return db.loc[(db["startIP"] <= ip) & (ip <= db["endIP"]), "countryISO"].squeeze()
df["countryISO"] = df["integerIP"].map(ip2country)
>>> df
sourceIP eventTime integerIP countryISO
0 114.119.157.43 2021-03-01 1920441643 SG
1 193.205.128.7 2021-03-01 3251470343 IT
2 193.205.128.7 2021-03-01 3251470343 IT
3 193.205.128.7 2021-03-01 3251470343 IT
表现
对于 10k ip 地址,在2.5 GHz 四核 Intel Core i7上平均在 11.7 秒内返回结果。
df1 = pd.DataFrame({"integerIP": np.random.randint(db["startIP"].min(),
db["endIP"].max()+1,
size=10000)})
%timeit df1["integerIP"].map(ip2country)
11.7 s ± 489 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
推荐阅读
- matlab - polyshape对象的顶部,底部,左侧,右侧x,y坐标 - Matlab
- javascript - 如何在曲线框html和css中添加垂直线分割和图例?
- css - 有没有办法混合深色阴影滤镜以不显示在浅色(白色)背景上?
- c++ - 关于 C++ 删除和内存泄漏的说明
- javascript - 循环遍历数组并用JS中的字符串替换某些数字
- html - 绝对定位的锚在移动设备上太高了
- java - Java 类型由多个托管类型生成
- r - 在 ggplot 中使用分面图标题进行标签解析
- python - 在 Python 中按行或列构建新 df 的最佳方法?
- html - python烧瓶 - 我怎样才能在身体元素之间腾出更多空间