You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从两列DataFrame构建DNS查询出现情况的0-1稀疏矩阵

问题:从两列结构DataFrame构建DNS查询出现情况稀疏矩阵

请问如何从仅包含两列的DataFrame中构建记录值出现情况的矩阵?我目前正在处理DNS数据集,共包含100个JSON文件,每个文件对应单日的DNS流量数据。我需要提取自身关注的IP地址子集,构建记录其出现情况的0-1稀疏矩阵,数据集中共有8个待分析的真实IP地址。

由于我仅关注s_ip(源IP地址)和dns_query(发起的DNS查询请求)两列字段,我已基于这两个字段以及目标IP列表['10.0.0.31','10.0.0.60','10.0.0.33','10.0.0.32','10.0.0.42','10.0.0.44','10.0.0.34','10.0.0.29']完成数据集过滤,也得到了列表中第一个IP对应的过滤后数据子集。

我尝试使用CountVectorizer和HashVectorizer实现需求但未成功。我目标构建的稀疏矩阵中,行对应单日的单个关注IP地址,列对应当日JSON文件中出现的所有dns_query取值,矩阵元素代表对应DNS查询的出现情况,效果类似如下sklearn官方示例中以文本为语料构建的词频矩阵:

In [7]: from sklearn.feature_extraction.text import CountVectorizer

In [8]: corpus = [
   ...:     'This is the first document.',
   ...:     'This document is the second document.',
   ...:     'And this is the third one.',
   ...:     'Is this the first document?',]

In [9]: vectorizer = CountVectorizer()

In [10]: X = vectorizer.fit_transform(corpus)

In [11]: vectorizer.get_feature_names_out()
Out[11]:
array(['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third',
       'this'], dtype=object)

In [12]: print(X.toarray())
[[0 1 1 1 0 0 1 0 1]
 [0 2 0 1 0 1 1 0 1]
 [1 0 0 1 1 0 1 1 1]
 [0 1 1 1 0 0 1 0 1]]

In [13]:

我已在Colab平台提供了该问题的最小可运行示例(MWE),恳请提供相关实现思路与指导。


实现方案

CountVectorizer适配失败的核心原因是:它默认处理空格分隔的自由文本,会自动执行分词逻辑,而你手里已经是结构化的两列DataFrame,不需要走文本分词流程,直接用结构化方法实现即可,两种可直接运行的方案如下:

方案1:pandas原生交叉表实现(逻辑最直观,无额外依赖)

直接通过交叉表生成行、列、值完全匹配需求的矩阵,支持一键转稀疏格式:

import pandas as pd

# 假设已加载合并所有单日数据为总DataFrame,包含date(日期标识)、s_ip、dns_query三列
target_ips = ['10.0.0.31','10.0.0.60','10.0.0.33','10.0.0.32','10.0.0.42','10.0.0.44','10.0.0.34','10.0.0.29']
df_filtered = df[df['s_ip'].isin(target_ips)].copy()

# 生成0-1矩阵前先对「单日+单IP+单查询」去重,避免重复计数
df_dedup = df_filtered.drop_duplicates(subset=['date', 's_ip', 'dns_query'])

# 生成交叉表
occur_matrix = pd.crosstab(
    index=[df_dedup['date'], df_dedup['s_ip']],  # 行维度:单日+单个关注IP
    columns=df_dedup['dns_query'],               # 列维度:所有出现过的DNS查询
    values=1,
    aggfunc='count',
    fill_value=0
)

# 转scipy稀疏矩阵供后续建模/计算使用
sparse_matrix = occur_matrix.sparse.to_coo().tocsr()
# 获取列标签(所有dns_query取值)
query_cols = occur_matrix.columns.to_numpy()
# 获取行标签(日期+IP的组合)
row_labels = occur_matrix.index.to_list()

如果仅需处理单日单个JSON文件,去掉index里的date字段即可,行直接对应单个关注IP。

方案2:sklearn生态MultiLabelBinarizer实现(适合大样本稀疏场景)

如果数据量较大,希望直接输出sklearn兼容的稀疏矩阵,可以用多标签二值化编码器实现:

from sklearn.preprocessing import MultiLabelBinarizer

# 按行维度分组,将每个组对应的dns_query聚合为列表
grouped = df_dedup.groupby(['date', 's_ip'])['dns_query'].apply(list).reset_index()

# 初始化二值化编码器,直接输出稀疏矩阵
mlb = MultiLabelBinarizer(sparse_output=True)
sparse_matrix = mlb.fit_transform(grouped['dns_query'])
# 获取列标签
query_cols = mlb.classes_
# 获取行标签
row_labels = grouped[['date', 's_ip']].to_numpy()

注意:如果你需要统计查询出现频次而非是否出现的0-1值,跳过drop_duplicates去重步骤即可,交叉表会自动完成计数,输出效果和你贴的CountVectorizer词频矩阵完全一致。

常见踩坑提醒:不要试图把单个IP对应的所有dns_query拼接成空格分隔的字符串喂给CountVectorizer——如果dns_query(比如域名)包含特殊字符、点号甚至空格,默认分词器会把完整域名拆成碎块,最终得到的列不是完整的查询值,结果完全不可用。


内容的提问来源于stack exchange,提问作者Geovani Benita

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:33:10