【问题标题】:Filter Pandas DataFrame by ip address range按 IP 地址范围过滤 Pandas DataFrame
【发布时间】:2023-03-27 19:26:01
【问题描述】:

我需要按 IP 地址范围过滤熊猫 Dataframe。没有正则表达式可以吗?

Ex. From 61.245.160.0   To 61.245.175.255

【问题讨论】:

  • @Andy Hayden :好的,正则表达式很好,我有很多要匹配的范围,这就是为什么我问没有正则表达式?

标签: python pandas dataframe ip-address


【解决方案1】:

我有一个使用ipaddress的方法。

例如,我想知道host0 = 10.2.23.5 是否属于以下任何网络NETS = ['10.2.48.0/25','10.2.23.0/25','10.2.154.0/24']

>>> host0 = ip.IPv4Address('10.2.23.5')
>>> NETS = ['10.2.48.0/25','10.2.23.0/25','10.2.154.0/24']
>>> nets  = [ip.IPv4Network(x) for x in NETS]
>>> [x for x in nets if (host2 >= x.network_address and host2 <= x.broadcast_address)]
[IPv4Network('10.2.23.0/25')]

现在,为了将这种方法与 Pandas 结合起来,需要执行以下操作:创建一个函数并将其应用于 DF 的每一行。

def fnc(row):
    host = ip.IPv4Address(row)
    vec = [x for x in netsPy if (host >= x.network_address and host <= x.broadcast_address)]

    if len(vec) == 0:
        return '1'
    else:
        return '-1'

您稍后将其应用于 DF。

df['newCol'] = df['IP'].apply(fnc)

这将创建一个新列 newCol ,其中每一行将是 1-1 ,具体取决于 IP 地址是否属于您感兴趣的任一网络。

【讨论】:

  • 导入ipaddress为ip
【解决方案2】:

假设你有以下 DF:

In [48]: df
Out[48]:
               ip
0    61.245.160.1
1  61.245.160.100
2  61.245.160.200
3  61.245.160.254

让我们找出介于(但不包括)61.245.160.9961.245.160.254 之间的所有 IP:

In [49]: ip_from = '61.245.160.99'

In [50]: ip_to = '61.245.160.254'

如果我们将 IP 作为字符串进行比较 - 它将按字典顺序进行比较,因此它不能像 @adele has pointed out 那样正常工作:

In [51]: df.query("'61.245.160.99' < ip < '61.245.160.254'")
Out[51]:
Empty DataFrame
Columns: [ip]
Index: []

In [52]: df.query('@ip_from < ip < @ip_to')
Out[52]:
Empty DataFrame
Columns: [ip]
Index: []

我们可以使用numerical IP representation:

In [53]: df[df.ip.apply(lambda x: int(IPAddress(x)))
   ....:      .to_frame('ip')
   ....:      .eval('{} < ip < {}'.format(int(IPAddress(ip_from)),
   ....:                                  int(IPAddress(ip_to)))
   ....:       )
   ....: ]
Out[53]:
               ip
1  61.245.160.100
2  61.245.160.200

解释:

In [66]: df.ip.apply(lambda x: int(IPAddress(x)))
Out[66]:
0    1039507457
1    1039507556
2    1039507656
3    1039507710
Name: ip, dtype: int64

In [67]: df.ip.apply(lambda x: int(IPAddress(x))).to_frame('ip')
Out[67]:
           ip
0  1039507457
1  1039507556
2  1039507656
3  1039507710

In [68]: (df.ip.apply(lambda x: int(IPAddress(x)))
   ....:    .to_frame('ip')
   ....:    .eval('{} < ip < {}'.format(int(IPAddress(ip_from)),
   ....:                               int(IPAddress(ip_to))))
   ....: )
Out[68]:
0    False
1     True
2     True
3    False
dtype: bool

这里的 PS 是一个更快(矢量化)的函数,它将返回数字 IP 表示:

def ip_to_int(ip_ser):
    ips = ip_ser.str.split('.', expand=True).astype(np.int16).values
    mults = np.tile(np.array([24, 16, 8, 0]), len(ip_ser)).reshape(ips.shape)
    return np.sum(np.left_shift(ips, mults), axis=1)

演示:

In [78]: df['int_ip'] = ip_to_int(df.ip)

In [79]: df
Out[79]:
               ip      int_ip
0    61.245.160.1  1039507457
1  61.245.160.100  1039507556
2  61.245.160.200  1039507656
3  61.245.160.254  1039507710

检查:

In [80]: (df.ip.apply(lambda x: int(IPAddress(x))) == ip_to_int(df.ip)).all()
Out[80]: True

【讨论】:

  • 只是想补充一下,当我的 IP 为例如时,我遇到了def ip_to_int(ip_ser) 的问题。 240.42.123.100,我会得到 int -265651356。这是由于np.left_shift(ips, mults) 的整数溢出引起的。在这种情况下,我找到了使用stackoverflow.com/a/27400252/6453903np.left_shift(ips.astype(object), mults) 的解决方法
【解决方案3】:

字符串在 python 中是可排序的,所以你应该能够摆脱它:

In [11]: '61.245.160.0' < '61.245.175.255'
Out[11]: True

布尔掩码:

In [12]: df[('61.245.160.0' < df.ip) & (df.ip < '61.245.175.255')]

或者取一个切片(如果 ip 是索引):

In [13]: df.loc['61.245.160.0':'61.245.175.255']

【讨论】:

  • 我爱蟒蛇!最简单的解决方案通常实际上可供程序员使用!
  • 小心这种方法,因为它不能正确排序。即'61.245.160.99' &lt; '61.245.160.102' Out[161]: False
  • @adele 好点,获得正确行为的一种快速方法是为 IP 地址创建大量代表,例如61 * 1000000000 + 245 * 1000000+ 160 * 1000 + 255 并以此为基础进行排序。
  • 我同意@ade1e。为什么不使用import ipaddress?效果很好:[x for x in nets if (host2 &gt;= x.network_address and host2 &lt;= x.broadcast_address)]。唯一的问题是我真的不知道如何在 Pandas 中使用这种方法。
猜你喜欢
  • 2019-03-25
  • 2017-01-04
  • 2019-08-30
  • 2022-07-22
  • 2014-02-11
  • 1970-01-01
  • 2020-10-07
  • 2017-11-27
  • 2010-09-10
相关资源
最近更新 更多