python - Pandas:将 IP 解析为国家/地区的最快方法

标签 python pandas dataframe geo

我有一个函数 find_country_from_connection_ip,它接受一个 ip,经过一些处理后返回一个国家。如下所示:

def find_country_from_connection_ip(ip):
    # Do some processing
    return county

我正在使用 apply 方法中的函数。如下所示:

df['Country'] = df.apply(lambda x: find_country_from_ip(x['IP']), axis=1)

因为它非常简单,我想要的是从 DataFrame 中具有 >400000 行的现有列评估新列。

它运行,但非常慢并抛出如下异常:

...........: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

if name == 'main': In [38]:

我理解这个问题,但不太明白如何将 locapplylambda 一起使用。

注意请建议您是否有更有效的替代解决方案,可以带来最终结果。

**** 编辑 ********

该函数主要是在mmdb 数据库中查找,如下所示:

def find_country_from_ip(ip):
    result = subprocess.Popen("mmdblookup --file GeoIP2-Country.mmdb --ip {} country names en".format(ip).split(" "), stdout=subprocess.PIPE).stdout.read()
    if result:
        return re.search(r'\"(.+?)\"', result).group(1) 
    else:
        final_output = subprocess.Popen("mmdblookup --file GeoIP2-Country.mmdb --ip {} registered_country names en".format(ip).split(" "), stdout=subprocess.PIPE).stdout.read()
        return re.search(r'\"(.+?)\"', final_output).group(1)

尽管如此,这是一项代价高昂的操作,当您有一个包含 >400000 行的 DataFrame 时,这应该需要一些时间。但是多少钱?就是那个问题。大约需要 2 小时,我认为差不多。

最佳答案

我会为此使用 maxminddb-geolite2 (GeoLite) 模块。

首先安装maxminddb-geolite2模块

pip install maxminddb-geolite2

Python 代码:

import pandas as pd
from geolite2 import geolite2

def get_country(ip):
    try:
        x = geo.get(ip)
    except ValueError:
        return pd.np.nan
    try:
        return x['country']['names']['en'] if x else pd.np.nan
    except KeyError:
        return pd.np.nan

geo = geolite2.reader()

# it took me quite some time to find a free and large enough list of IPs ;)
# IP's for testing: http://upd.emule-security.org/ipfilter.zip
x = pd.read_csv(r'D:\download\ipfilter.zip',
                usecols=[0], sep='\s*\-\s*',
                header=None, names=['ip'])

# get unique IPs
unique_ips = x['ip'].unique()
# make series out of it
unique_ips = pd.Series(unique_ips, index = unique_ips)
# map IP --> country
x['country'] = x['ip'].map(unique_ips.apply(get_country))

geolite2.close()

输出:

In [90]: x
Out[90]:
                     ip     country
0       000.000.000.000         NaN
1       001.002.004.000         NaN
2       001.002.008.000         NaN
3       001.009.096.105         NaN
4       001.009.102.251         NaN
5       001.009.106.186         NaN
6       001.016.000.000         NaN
7       001.055.241.140         NaN
8       001.093.021.147         NaN
9       001.179.136.040         NaN
10      001.179.138.224    Thailand
11      001.179.140.200    Thailand
12      001.179.146.052         NaN
13      001.179.147.002    Thailand
14      001.179.153.216    Thailand
15      001.179.164.124    Thailand
16      001.179.167.188    Thailand
17      001.186.188.000         NaN
18      001.202.096.052         NaN
19      001.204.179.141       China
20      002.051.000.165         NaN
21      002.056.000.000         NaN
22      002.095.041.202         NaN
23      002.135.237.106  Kazakhstan
24      002.135.237.250  Kazakhstan
...                 ...         ...

时间:对于 171.884 个唯一 IP:

In [85]: %timeit unique_ips.apply(get_country)
1 loop, best of 3: 14.8 s per loop

In [86]: unique_ips.shape
Out[86]: (171884,)

结论:大约需要35 秒,你在我的硬件上拥有 40 万个唯一 IP:

In [93]: 400000/171884*15
Out[93]: 34.90726303786274

关于python - Pandas:将 IP 解析为国家/地区的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40211314/

相关文章:

python - 为什么这个简单的 Python TK Gui 程序占用 100% CPU

python - Pandas:将 DataFrameGroupBy 对象转换为所需格式

python - 将两列 CSV 作为 dict 读取,第一列作为键

python - atom.io、hydrogen 和 ipython 远程 (ssh) 内核

python - 将唯一列转换为具有相应值的 SFrame 标题

arrays - Julia - 如何将数据帧转换为数组?

python - 如何使用 Python 中另一个 DataFrame 对象中的值更新 DataFrame 对象的一部分?

python - 将 Pandas DataFrame 作为 Pickle 写入 S3

python - Pandas - 将数据从一列计算到另一列

python - 保存时 Pandas 的身材正在被削减