Assuming you have the following 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
let's find all IPs falling between (but not including) 61.245.160.99
and 61.245.160.254
:
In [49]: ip_from = '61.245.160.99'
In [50]: ip_to = '61.245.160.254'
if we will compare IPs as strings - it will be compared lexicographically so it won't work properly as @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: []
We can use 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
Explanation:
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 here is a bit faster (vectorized) function which will return numerical IP representation:
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)
Demo:
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
check:
In [80]: (df.ip.apply(lambda x: int(IPAddress(x))) == ip_to_int(df.ip)).all()
Out[80]: True