推荐数据集处理(分桶) 重要(比较水)


1. 探索数据集

1.1 数据读入

1
2
3
# 上面是对于数据标签的导入
names = ['label', 'I1', 'I2', 'I3', 'I4', 'I5', 'I6', 'I7', 'I8', 'I9', 'I10', 'I11','I12', 'I13', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11','C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22','C23', 'C24', 'C25', 'C26']
criteo_data = pd.read_csv('./criteo-100k.txt',sep='\t',names=names)

1.2 查看数据

1
criteo_data.head()

qDRYeU.md.png

1
2
3
4
5
6
7
8
criteo_data.info()
# shape 内不需要传参
criteo_data.shape
# 数据集10w 缺的有点多
criteo_data.isnull().sum()
# 查看==数值型列==的汇总统计
# 这里的目的是查看是否有及其异常的值
criteo_data.describe()

1.3 数据分类

1
2
3
4
5
6
# 数据特征分为离散和连续类
sparse_features = ['C' + str(i) for i in range(1, 27)]
dense_features = ['I' + str(i) for i in range(1, 14)]
features = sparse_features + dense_features
# 检查 特征列是否添加完全
assert len(sparse_features) + len(dense_features) == criteo_data.shape[1] - 1

1.4 查看缺失值情况(标注)

1
2
3
4
5
6
7
8
# 查看离散变量目前的类别
criteo_data[sparse_features].dtypes
# 查看离散变量缺失值情况
criteo_data[sparse_features].isnull().sum()
# 离散缺失值标注
criteo_data[sparse_features] = criteo_data[sparse_features].fillna('-1')
# 查看离散变量缺失值情况
criteo_data[sparse_features].isnull().sum()
1
2
3
4
5
6
7
8
# 查看连续变量目前的类别
criteo_data[sparse_features].dtypes
# 查看连续变量缺失值情况
criteo_data[sparse_features].isnull().sum()
# 连续缺失值标注
criteo_data[sparse_features] = criteo_data[sparse_features].fillna(0)
# 查看连续变量缺失值情况
criteo_data[sparse_features].isnull().sum()

1.5 数据分箱

1
2
3
4
5
6
7
8
9
10
11
from sklearn.preprocessing import LabelEncoder, OrdinalEncoder, KBinsDiscretizer

# 连续型特征等间隔分箱
est = KBinsDiscretizer(n_bins=100, encode='ordinal', strategy='uniform')
criteo_data[dense_features] = est.fit_transform(criteo_data[dense_features])

# 离散型特征转换成连续数字,为了在与参数计算时使用索引的方式计算,而不是向量乘积
criteo_data[features] = OrdinalEncoder().fit_transform(criteo_data[features])

data = criteo_data[features + ['label']].values
data.shape

1.6 训练数据与标签分离

1
2
3
# 这里类似于 之前是 标签 + 数据
# 现在更换为 数据 + 标签
data = data_df[features + ['label']].values

2. 字段维度(field_dim) 与 数据划分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def train_valid_test_split(self, train_size=0.8, valid_size=0.1, test_size=0.1):
field_dims = (self.data.max(axis=0).astype(int) + 1).tolist()[:-1]

train, valid_test = train_test_split(self.data, train_size=train_size, random_state=2021)

valid_size = valid_size / (test_size + valid_size)
valid, test = train_test_split(valid_test, train_size=valid_size, random_state=2021)

device = self.device

train_X = torch.tensor(train[:, :-1], dtype=torch.long).to(device)
valid_X = torch.tensor(valid[:, :-1], dtype=torch.long).to(device)
test_X = torch.tensor(test[:, :-1], dtype=torch.long).to(device)
train_y = torch.tensor(train[:, -1], dtype=torch.float).unsqueeze(1).to(device)
valid_y = torch.tensor(valid[:, -1], dtype=torch.float).unsqueeze(1).to(device)
test_y = torch.tensor(test[:, -1], dtype=torch.float).unsqueeze(1).to(device)

return field_dims, (train_X, train_y), (valid_X, valid_y), (test_X, test_y)

2.1 字段维度获取(field_dim)

1
2
3
4
# 这一段太妙了
# 获得 前数据内 最大值 假如数据范围为0-540 则 一共有541个数
# 所以需要加1 后面[:-1] 剔除标签行
field_dims = (self.data.max(axis=0).astype(int) + 1).tolist()[:-1]

2.2 数据划分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
train, valid_test = train_test_split(self.data, train_size=train_size, random_state=2021)

valid_size = valid_size / (test_size + valid_size)
valid, test = train_test_split(valid_test, train_size=valid_size, random_state=2021)
# 上面划分 是简单的
device = self.device
# 这里 想 重点说一下两个[:, :-1] [:, -1]区分
# 举个例子 一个社会 有很多家庭 每个家庭 有很多人
# 前一个: 取 哪个家庭
# 后一个 : 取 那些人
# [:, :-1] 这个的意思是 取 所有家庭内 除了最后一个以外的所有人
# [:, -1] 意思是 取 所有家庭内 最后一个人
train_X = torch.tensor(train[:, :-1], dtype=torch.long).to(device)
valid_X = torch.tensor(valid[:, :-1], dtype=torch.long).to(device)
test_X = torch.tensor(test[:, :-1], dtype=torch.long).to(device)
train_y = torch.tensor(train[:, -1], dtype=torch.float).unsqueeze(1).to(device)
valid_y = torch.tensor(valid[:, -1], dtype=torch.float).unsqueeze(1).to(device)
test_y = torch.tensor(test[:, -1], dtype=torch.float).unsqueeze(1).to(device)