Объединить / объединить два кадра данных, один с IP-адресами, один с IP-сетями - PullRequest
2 голосов
/ 15 октября 2019

У меня есть два кадра данных, один из которых содержит IP-адреса (df_ip), другой содержит IP-сети (df_network).
IP-адреса и сети относятся к типу ipaddress.ip_address и ipaddress.ip_network, что позволяет проверятьесли IP лежит в сети (ip in network).

Кадры данных выглядят следующим образом:

df_ip:
    IP
0   10.10.10.10
1   10.10.20.10
2   10.10.20.20

df_network:
    NETWORK         NETWORK_NAME
0   10.10.10.0/28   Subnet1
1   10.10.20.0/27   Subnet2

Я хочу объединить / объединить df_ip с df_network, добавив имя сети, в которой находится IP-адрес. строка.
Для этого небольшого экземпляра он должен вернуть следующее:

df_merged:
    IP            NETWORK_NAME
0   10.10.10.10   Subnet1
1   10.10.20.10   Subnet2
2   10.10.20.20   Subnet2

Мои фактические кадры данных намного больше, поэтому id предпочитают не использовать циклы for для поддержания эффективности.
Как я могу лучше всего достичь этого? Если для этого требуется изменить типы данных, это нормально.

Примечание: Я добавил код ниже, чтобы создать данные для удобства.

import pandas as pd
import ipaddress

# Create small IP DataFrame
values_ip = [ipaddress.ip_address('10.10.10.10'),
             ipaddress.ip_address('10.10.20.10'),
             ipaddress.ip_address('10.10.20.20')]

df_ip = pd.DataFrame()
df_ip['IP'] = values_ip

# Create small Network DataFrame
values_network = [ipaddress.ip_network('10.10.10.0/28'),
                  ipaddress.ip_network('10.10.20.0/27')]
names_network = ['Subnet1',
                 'Subnet2']

df_network = pd.DataFrame()
df_network['NETWORK'] = values_network
df_network['NETWORK_NAME'] = names_network

1 Ответ

2 голосов
/ 15 октября 2019

Эффективный способ избежать любых петель - использовать пустые массивы для проверки, где ip & netmask == network_address, то есть как проверить, находится ли ip в сети.

Обратите внимание, что это возвращает только первую соответствующую сетьимя

import numpy as np
net_masks = df_network.NETWORK.apply(lambda x: int(x.netmask)).to_numpy()
network_addresses = df_network.NETWORK.apply(lambda x: int(x.network_address)).to_numpy()

def get_first_network(ip):
    is_in_network = int(ip) & net_masks == network_addresses
    indices = np.argwhere(is_in_network)
    if indices.size>0:
        return df_network.loc[int(indices[0]), 'NETWORK_NAME' ]
    else:
        None

df_ip['network_name'] = df_ip.IP.apply(get_first_network)

, что приводит к:

            IP network_name
0  10.10.10.10      Subnet1
1  10.10.20.10      Subnet2
2  10.10.20.20      Subnet2
...