Criteo数据集预处理

Criteo数据集介绍和下载

数据集包含各个特征取值和点击率,共39个特征,其中13个数字型特征,26个类别特征。Criteo是CTR模型的benchmark数据集,曾被用于kaggle竞赛。 (Kaggle链接),下载地址:(下载地址)

torchfm包中Criteo数据集预处理源码

import math
import shutil
import struct
from collections import defaultdict
from functools import lru_cache
from pathlib import Path

import lmdb
import numpy as np
import torch.utils.data
from tqdm import tqdm


class CriteoDataset(torch.utils.data.Dataset):
    """
    Criteo Display Advertising Challenge Dataset

    Data prepration:
        * Remove the infrequent features (appearing in less than threshold instances) and treat them as a single feature
        * Discretize numerical values by log2 transformation which is proposed by the winner of Criteo Competition

    :param dataset_path: criteo train.txt path.
    :param cache_path: lmdb cache path.
    :param rebuild_cache: If True, lmdb cache is refreshed.
    :param min_threshold: infrequent feature threshold.

    Reference:
        https://labs.criteo.com/2014/02/kaggle-display-advertising-challenge-dataset
        https://www.csie.ntu.edu.tw/~r01922136/kaggle-2014-criteo.pdf
    """

    def __init__(self, dataset_path=None, cache_path='.criteo', rebuild_cache=False, min_threshold=1):
        self.NUM_FEATS = 39
        self.NUM_INT_FEATS = 13
        self.min_threshold = min_threshold
        if rebuild_cache or not Path(cache_path).exists():
            shutil.rmtree(cache_path, ignore_errors=True)
            if dataset_path is None:
                raise ValueError('create cache: failed: dataset_path is None')
            self.__build_cache(dataset_path, cache_path)
        self.env = lmdb.open(cache_path, create=False, lock=False, readonly=True)
        with self.env.begin(write=False) as txn:
            self.length = txn.stat()['entries'] - 1
            self.field_dims = np.frombuffer(txn.get(b'field_dims'), dtype=np.uint32)

    def __getitem__(self, index):
        with self.env.begin(write=False) as txn:
            np_array = np.frombuffer(
                txn.get(struct.pack('>I', index)), dtype=np.uint32).astype(dtype=np.long)
        return np_array[1:], np_array[0]

    def __len__(self):
        return self.length

    def __build_cache(self, path, cache_path):
        feat_mapper, defaults = self.__get_feat_mapper(path)
        with lmdb.open(cache_path, map_size=int(1e11)) as env:
            field_dims = np.zeros(self.NUM_FEATS, dtype=np.uint32)
            for i, fm in feat_mapper.items():
                field_dims[i - 1] = len(fm) + 1
            with env.begin(write=True) as txn:
                txn.put(b'field_dims', field_dims.tobytes())
            for buffer in self.__yield_buffer(path, feat_mapper, defaults):
                with env.begin(write=True) as txn:
                    for key, value in buffer:
                        txn.put(key, value)

    def __get_feat_mapper(self, path):
        feat_cnts = defaultdict(lambda: defaultdict(int))
        with open(path) as f:
            pbar = tqdm(f, mininterval=1, smoothing=0.1)
            pbar.set_description('Create criteo dataset cache: counting features')
            for line in pbar:
                values = line.rstrip('\n').split('\t')
                if len(values) != self.NUM_FEATS + 1:
                    continue
                for i in range(1, self.NUM_INT_FEATS + 1):
                    feat_cnts[i][convert_numeric_feature(values[i])] += 1
                for i in range(self.NUM_INT_FEATS + 1, self.NUM_FEATS + 1):
                    feat_cnts[i][values[i]] += 1
        feat_mapper = {i: {feat for feat, c in cnt.items() if c >= self.min_threshold} for i, cnt in feat_cnts.items()}
        feat_mapper = {i: {feat: idx for idx, feat in enumerate(cnt)} for i, cnt in feat_mapper.items()}
        defaults = {i: len(cnt) for i, cnt in feat_mapper.items()}
        return feat_mapper, defaults

    def __yield_buffer(self, path, feat_mapper, defaults, buffer_size=int(1e5)):
        item_idx = 0
        buffer = list()
        with open(path) as f:
            pbar = tqdm(f, mininterval=1, smoothing=0.1)
            pbar.set_description('Create criteo dataset cache: setup lmdb')
            for line in pbar:
                values = line.rstrip('\n').split('\t')
                if len(values) != self.NUM_FEATS + 1:
                    continue
                np_array = np.zeros(self.NUM_FEATS + 1, dtype=np.uint32)
                np_array[0] = int(values[0])
                for i in range(1, self.NUM_INT_FEATS + 1):
                    np_array[i] = feat_mapper[i].get(convert_numeric_feature(values[i]), defaults[i])
                for i in range(self.NUM_INT_FEATS + 1, self.NUM_FEATS + 1):
                    np_array[i] = feat_mapper[i].get(values[i], defaults[i])
                buffer.append((struct.pack('>I', item_idx), np_array.tobytes()))
                item_idx += 1
                if item_idx % buffer_size == 0:
                    yield buffer
                    buffer.clear()
            yield buffer


@lru_cache(maxsize=None)
def convert_numeric_feature(val: str):
    if val == '':
        return 'NULL'
    v = int(val)
    if v > 2:
        return str(int(math.log(v) ** 2))
    else:
        return str(v - 2)

对其中部分代码的解读:

1.defaultdict函数区别于dict(),若输入不在该字典中的key,输出不会像普通dict一样报错,而是会得到一个默认值,这里使用这个函数便于进行普通特征和低频特征的读取和处理。 

2. get_feat_mapper部分:feat_cnts[i][j]代表第i个域特征值为j(原始表格里的值)出现的次数,第一个赋值的feat_mapper表示每个域中非低频特征有哪些,第二次赋值的则表示各个域中feat到idx的映射(原始表格值到新的id)

3.yield_buffer部分:feat_mapper.get()代表对特征值赋予默认值,这里注意若特征值本身有对应的idx,则还是return这个idx而不是赋予的默认值,所以这个函数实际上只对低频特征生效。其结果即将低频特征都赋予了一个相同的idx

基于统计信息(频率)预处理的修改

为了使用模型压缩方法,这里我需要将所有低频特征放置于table底部,但不归为一类id,于是将代码进行了如下修改

class CriteoDatasetOtherSplit(torch.utils.data.Dataset):
    """
    Criteo Display Advertising Challenge Dataset

    Data prepration:
        * Remove the infrequent features (appearing in less than threshold instances) and treat them as a single feature
        * Discretize numerical values by log2 transformation which is proposed by the winner of Criteo Competition

    :param dataset_path: criteo train.txt path.
    :param cache_path: lmdb cache path.
    :param rebuild_cache: If True, lmdb cache is refreshed.
    :param min_threshold: infrequent feature threshold.

    Reference:
        https://labs.criteo.com/2014/02/kaggle-display-advertising-challenge-dataset
        https://www.csie.ntu.edu.tw/~r01922136/kaggle-2014-criteo.pdf
    """

    def __init__(self, dataset_path=None, cache_path='.criteo', rebuild_cache=False, min_threshold=8):
        self.NUM_FEATS = 39
        self.NUM_INT_FEATS = 13
        self.min_threshold = min_threshold
        if rebuild_cache or not Path(cache_path).exists():
            shutil.rmtree(cache_path, ignore_errors=True)
            if dataset_path is None:
                raise ValueError('create cache: failed: dataset_path is None')
            self.__build_cache(dataset_path, cache_path)
        self.env = lmdb.open(cache_path, create=False, lock=False, readonly=True)
        with self.env.begin(write=False) as txn:
            self.length = txn.stat()['entries'] - 1
            self.field_dims = np.frombuffer(txn.get(b'field_dims'), dtype=np.uint32)
            self.other_dims = np.frombuffer(txn.get(b'other_dims'), dtype=np.uint32)

    def __getitem__(self, index):
        with self.env.begin(write=False) as txn:
            np_array = np.frombuffer(
                txn.get(struct.pack('>I', index)), dtype=np.uint32).astype(dtype=np.long)
        return np_array[1:], np_array[0]

    def __len__(self):
        return self.length - 1

    def __build_cache(self, path, cache_path):
        feat_mapper, other_feat_mapper, defaults = self.__get_feat_mapper(path)
        with lmdb.open(cache_path, map_size=int(1e11)) as env:
            field_dims = np.zeros(self.NUM_FEATS, dtype=np.uint32)
            other_dims = np.zeros(self.NUM_FEATS, dtype=np.uint32)
            for i, fm in other_feat_mapper.items():
                other_dims[i - 1] = len(fm)
            for i, fm in feat_mapper.items():
                field_dims[i - 1] = len(fm) + other_dims[i - 1]
            with env.begin(write=True) as txn:
                txn.put(b'field_dims', field_dims.tobytes())
                txn.put(b'other_dims', other_dims.tobytes())
            for buffer in self.__yield_buffer(path, feat_mapper, other_feat_mapper, defaults):
                with env.begin(write=True) as txn:
                    for key, value in buffer:
                        txn.put(key, value)

    def __get_feat_mapper(self, path):
        feat_cnts = defaultdict(lambda: defaultdict(int))
        with open(path) as f:
            pbar = tqdm(f, mininterval=1, smoothing=0.1)
            pbar.set_description('Create criteo dataset cache: counting features')
            for line in pbar:
                values = line.rstrip('\n').split('\t')
                if len(values) != self.NUM_FEATS + 1:
                    continue
                for i in range(1, self.NUM_INT_FEATS + 1):
                    feat_cnts[i][convert_numeric_feature(values[i])] += 1
                for i in range(self.NUM_INT_FEATS + 1, self.NUM_FEATS + 1):
                    feat_cnts[i][values[i]] += 1
        feat_mapper = {i: {feat for feat, c in cnt.items() if c >= self.min_threshold} for i, cnt in feat_cnts.items()}
        other_feat_mapper = {i: {feat for feat, c in cnt.items() if c < self.min_threshold} for i, cnt in feat_cnts.items()}
        feat_mapper = {i: {feat: idx for idx, feat in enumerate(cnt)} for i, cnt in feat_mapper.items()}
        other_feat_mapper = {i: {feat: idx for idx, feat in enumerate(cnt)} for i, cnt in other_feat_mapper.items()}
        defaults = {i: len(cnt) for i, cnt in feat_mapper.items()}
        return feat_mapper, other_feat_mapper, defaults

    def __yield_buffer(self, path, feat_mapper, other_feat_mapper, defaults, buffer_size=int(1e5)):
        item_idx = 0
        buffer = list()
        with open(path) as f:
            pbar = tqdm(f, mininterval=1, smoothing=0.1)
            pbar.set_description('Create criteo dataset cache: setup lmdb')
            for line in pbar:
                values = line.rstrip('\n').split('\t')
                if len(values) != self.NUM_FEATS + 1:
                    continue
                np_array = np.zeros(self.NUM_FEATS + 1, dtype=np.uint32)
                np_array[0] = int(values[0])
                for i in range(1, self.NUM_INT_FEATS + 1):
                    other_feat_mapper[i].setdefault(convert_numeric_feature(values[i]), 0)
                    np_array[i] = feat_mapper[i].get(convert_numeric_feature(values[i]),
                                                     other_feat_mapper[i][convert_numeric_feature(values[i])]+defaults[i])
                for i in range(self.NUM_INT_FEATS + 1, self.NUM_FEATS + 1):
                    other_feat_mapper[i].setdefault(values[i], 0)
                    np_array[i] = feat_mapper[i].get(values[i], other_feat_mapper[i][values[i]]+defaults[i])
                buffer.append((struct.pack('>I', item_idx), np_array.tobytes()))
                item_idx += 1
                if item_idx % buffer_size == 0:
                    yield buffer
                    buffer.clear()
            yield buffer


@lru_cache(maxsize=None)
def convert_numeric_feature(val: str):
    if val == '':
        return 'NULL'
    v = int(val)
    if v > 2:
        return str(int(math.log(v) ** 2))
    else:
        return str(v - 2)

这里有个意料之外的错误,最后一行记录会报错'NoneType'修改dataset.length可以避免报错,但没有找到错误原因

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Criteo是一家数字营销公司,其CTR(点击率)数据集是一个公开提供的数据集,用于广告点击率预测的研究和开发。CTR是指广告展示次数与点击次数之间的比例,是衡量广告效果的重要指标。 Criteo的CTR数据集Criteo Labs提供,它包含了数百万条匿名化的在线广告展示和点击数据。该数据集包含了13个特征字段,以及一个二进制的目标字段,用于表示用户是否点击了广告。 这个数据集被广泛应用于点击率预测相关的研究和算法开发。通过分析CTR数据集,我们可以研究不同特征与广告点击率之间的关系,进而提取特征、构建模型,预测用户的点击行为。这对于推荐系统、广告投放优化等领域都有很大的应用价值。 由于数据集的规模庞大,处理CTR数据集需要一定的计算资源和技术。因此,许多研究者和数据科学家会选择使用CTR数据集进行模型训练和评估。同时,由于CTR数据集的开放性,也方便了各界人士对广告点击率预测算法的研究和比较。 总之,Criteo CTR数据集是一个为广告点击率预测而设计的数据集,广泛应用于研究和开发领域。通过分析CTR数据集,我们可以研究广告展示与点击之间的关系,进而提高广告的投放效果,提升用户体验。 ### 回答2: Criteo CTR数据集是由Criteo公司发布的一个广告点击率预测数据集。该数据集主要用于机器学习和数据挖掘领域的研究,旨在帮助研究人员开发和改进点击率预测算法。 该数据集包含一个特定时间范围内的真实广告点击记录,记录了用户与广告的各种信息。这些信息包括广告的特征(如广告ID、广告主ID、广告类别等)、用户的特征(如用户ID、用户所在国家、用户使用的设备类型等)以及广告点击的时间和点击后的结果(即用户是否点击了广告)。 Criteo CTR数据集的规模相当大,包含了数十亿次实际的广告点击记录。这个数据集被广泛用于进行点击率预测算法的研究和性能评估。研究人员可以利用这个数据集来训练机器学习模型,通过分析用户和广告的特征,预测用户是否会点击广告。这对于广告投放商和广告主来说非常重要,可以准确预测广告点击率,从而选择合适的广告投放策略,提高广告投放效果。 Criteo CTR数据集的发布对于学术界和业界都具有重要意义。它提供了一个真实的大规模数据集,可以用于验证各种点击率预测算法的鲁棒性和性能。同时,该数据集可以帮助研究人员发现用户和广告之间的隐藏模式和关联规则,从而提高广告投放的精度和效果。 ### 回答3: Criteo是一家专注于数字广告技术的公司,在CTR(点击率)数据集方面有很大的贡献。CTR数据集是一个经典的机器学习数据集,用于预测用户在互联网广告中是否会点击某个广告。CTR是指广告展示次数中发生的广告点击次数与广告展示次数之比。 Criteo的CTR数据集是一个非常大型的数据集,包含数十亿个展示、点击和购买事件。数据集中包含了许多特征,如广告的ID、用户的ID、广告的类别、广告的价格、广告在页面中的位置等等。每个事件都有一个标签,表示用户是否点击了广告。 CTR数据集的用途非常广泛。首先,它可用于学术研究领域,研究人员可以利用这个数据集进行机器学习算法和模型的研究。其次,CTR数据集对于互联网广告行业来说也非常有价值,可以用于训练和优化广告推荐算法。通过分析CTR数据集,可以了解用户的喜好和行为,从而更好地展示相关广告,提高广告点击率。 然而,CTR数据集也存在一些挑战。首先,数据集规模庞大,对于处理和存储都提出了很高的要求。其次,数据集中的数据非常稀疏,这意味着大部分事件都是未点击的,这对于模型的训练和预测也提出了一定的挑战。此外,CTR数据集还涉及到用户隐私的问题,因此在使用数据集时需要注意保护用户隐私。 总之,Criteo的CTR数据集是一个重要的机器学习数据集,对于广告领域的研究和实践有着重要的意义。通过对CTR数据集的分析,我们可以了解和预测用户的点击行为,从而优化广告投放策略,提高广告的点击率和效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值