如何在DataFrame中对IPv4与IPv6地址进行混合排序?
混合IPv4/IPv6地址的DataFrame排序解决方案
原始数据与需求
给定以下包含混合IPv4和IPv6地址的DataFrame:
import pandas as pd df = pd.DataFrame( [ {"group": "a", "ip_address": "10.3.110.12"}, # IPv4 {"group": None, "ip_address": "10.3.110.127"}, # IPv4 {"group": "c", "ip_address": "2607:f140:d000:135::7e9c"}, # IPv6 {"group": "b", "ip_address": "10.3.110.90"}, # IPv4 ] )
需求:对ip_address列升序排序,要求IPv4在前,IPv6在后,且同类型IP内部按地址大小自然排序。
现有方法的问题
- 方法1(ipaddress对象排序):
IPv4Address和IPv6Address是不同类的对象,pandas无法跨类型比较,直接排序会触发TypeError。 - 方法2(socket.inet_aton转换):仅支持IPv4,IPv6需要使用
inet_pton,但两者返回的字节长度不同,无法统一排序。
可行解决方案
方案一:辅助列排序(兼容所有pandas版本)
通过添加类型标记和IP整数值两个辅助列,实现分层排序:
import ipaddress # 定义IP处理函数,返回(类型标记, IP整数值) def process_ip(ip_str): ip_obj = ipaddress.ip_address(ip_str) ip_type = 0 if isinstance(ip_obj, ipaddress.IPv4Address) else 1 return (ip_type, int(ip_obj)) # 生成辅助列 df[['ip_type', 'ip_int']] = df['ip_address'].apply(lambda x: pd.Series(process_ip(x))) # 按类型升序(IPv4在前)、IP整数值升序排序,最后删除辅助列 df_sorted = df.sort_values(by=['ip_type', 'ip_int'], ascending=True).drop(['ip_type', 'ip_int'], axis=1) print(df_sorted)
输出结果:
group ip_address 0 a 10.3.110.12 3 b 10.3.110.90 1 None 10.3.110.127 2 c 2607:f140:d000:135::7e9c
方案二:使用sort_values的key参数(pandas 1.1.0+)
利用sort_values的key参数直接生成排序键,无需辅助列,代码更简洁:
import ipaddress # 定义排序键生成函数 def sort_key(ip_str): ip_obj = ipaddress.ip_address(ip_str) # 元组排序优先比较第一个元素(类型标记),再比较第二个元素(IP整数) return (0 if isinstance(ip_obj, ipaddress.IPv4Address) else 1, int(ip_obj)) # 直接按生成的键排序 df_sorted = df.sort_values(by='ip_address', key=lambda x: x.apply(sort_key)) print(df_sorted)
输出结果与方案一完全一致。
原理说明
- 类型标记:用0标记IPv4,1标记IPv6,确保排序时IPv4始终排在IPv6前面。
- IP整数值:将IPv4/IPv6地址转换为对应的整数(IPv4是32位整数,IPv6是128位大整数),利用整数的大小比较实现IP地址的自然排序。
内容的提问来源于stack exchange,提问作者SAGY
相关产品推荐
相关产品推荐

