多兴趣推荐模型代码集合

参考地址

数据集地址

comi_rec_sr

import paddle
from paddle import nn
from paddle.io import DataLoader, Dataset
import paddle.nn.functional as F
import pandas as pd
import numpy as np
import copy
import os
import math
import random
from sklearn.metrics import roc_auc_score, log_loss
from sklearn.preprocessing import normalize
from tqdm import tqdm
from collections import defaultdict
from sklearn.manifold import TSNE
import seaborn as sns
from matplotlib import pyplot as plt
import faiss
import warnings

warnings.filterwarnings("ignore")


class SeqnenceDataset(Dataset):
    def __init__(self, config, df, phase='train'):
        self.config = config
        self.df = df
        self.max_length = self.config['max_length']
        self.df = self.df.sort_values(by=['user_id', 'timestamp'])
        self.user2item = self.df.groupby('user_id')['item_id'].apply(list).to_dict()
        self.user_list = self.df['user_id'].unique()
        self.phase = phase

    def __len__(self, ):
        return len(self.user2item)

    def __getitem__(self, index):
        if self.phase == 'train':
            user_id = self.user_list[index]
            item_list = self.user2item[user_id]
            hist_item_list = []
            hist_mask_list = []

            k = random.choice(range(4, len(item_list)))  # 从[8,len(item_list))中随机选择一个index
            # k = np.random.randint(2,len(item_list))
            item_id = item_list[k]  # 该index对应的item加入item_id_list

            if k >= self.max_length:  # 选取seq_len个物品
                hist_item_list.append(item_list[k - self.max_length: k])
                hist_mask_list.append([1.0] * self.max_length)
            else:
                hist_item_list.append(item_list[:k] + [0] * (self.max_length - k))
                hist_mask_list.append([1.0] * k + [0.0] * (self.max_length - k))

            return paddle.to_tensor(hist_item_list).squeeze(0), paddle.to_tensor(hist_mask_list).squeeze(
                0), paddle.to_tensor([item_id])
        else:
            user_id = self.user_list[index]
            item_list = self.user2item[user_id]
            hist_item_list = []
            hist_mask_list = []

            k = int(0.8 * len(item_list))
            # k = len(item_list)-1

            if k >= self.max_length:  # 选取seq_len个物品
                hist_item_list.append(item_list[k - self.max_length: k])
                hist_mask_list.append([1.0] * self.max_length)
            else:
                hist_item_list.append(item_list[:k] + [0] * (self.max_length - k))
                hist_mask_list.append([1.0] * k + [0.0] * (self.max_length - k))

            return paddle.to_tensor(hist_item_list).squeeze(0), paddle.to_tensor(hist_mask_list).squeeze(
                0), item_list[k:]

    def get_test_gd(self):
        self.test_gd = {}
        for user in self.user2item:
            item_list = self.user2item[user]
            test_item_index = int(0.8 * len(item_list))
            self.test_gd[user] = item_list[test_item_index:]
        return self.test_gd


class MultiInterest_SA(nn.Layer):
    def __init__(self, embedding_dim, interest_num, d=None):
        super(MultiInterest_SA, self).__init__()
        self.embedding_dim = embedding_dim
        self.interest_num = interest_num
        if d == None:
            self.d = self.embedding_dim * 4

        self.W1 = self.create_parameter(shape=[self.embedding_dim, self.d])
        self.W2 = self.create_parameter(shape=[self.d, self.interest_num])

    def forward(self, seq_emb, mask=None):
        '''
        seq_emb : batch,seq,emb
        mask : batch,seq,1
        '''
        H = paddle.einsum('bse, ed -> bsd', seq_emb, self.W1).tanh()
        mask = mask.unsqueeze(-1)
        A = paddle.einsum('bsd, dk -> bsk', H, self.W2) + -1.e9 * (1 - mask)
        A = F.softmax(A, axis=1)
        A = paddle.transpose(A, perm=[0, 2, 1])
        multi_interest_emb = paddle.matmul(A, seq_emb)
        return multi_interest_emb


class ComirecSA(nn.Layer):
    def __init__(self, config):
        super(ComirecSA, self).__init__()

        self.config = config
        self.embedding_dim = self.config['embedding_dim']
        self.max_length = self.config['max_length']
        self.n_items = self.config['n_items']

        self.item_emb = nn.Embedding(self.n_items, self.embedding_dim, padding_idx=0)
        self.multi_interest_layer = MultiInterest_SA(self.embedding_dim, interest_num=self.config['K'])
        self.loss_fun = nn.CrossEntropyLoss()
        self.reset_parameters()

    def calculate_loss(self, user_emb, pos_item):
        all_items = self.item_emb.weight
        scores = paddle.matmul(user_emb, all_items.transpose([1, 0]))
        return self.loss_fun(scores, pos_item)

    def output_items(self):
        return self.item_emb.weight

    def reset_parameters(self, initializer=None):
        for weight in self.parameters():
            paddle.nn.initializer.KaimingNormal(weight)

    def forward(self, item_seq, mask, item, train=True):

        if train:
            seq_emb = self.item_emb(item_seq)  # Batch,Seq,Emb
            item_e = self.item_emb(item).squeeze(1)

            multi_interest_emb = self.multi_interest_layer(seq_emb, mask)  # Batch,K,Emb

            cos_res = paddle.bmm(multi_interest_emb, item_e.squeeze(1).unsqueeze(-1))
            k_index = paddle.argmax(cos_res, axis=1)

            best_interest_emb = paddle.rand((multi_interest_emb.shape[0], multi_interest_emb.shape[2]))
            for k in range(multi_interest_emb.shape[0]):
                best_interest_emb[k, :] = multi_interest_emb[k, k_index[k], :]

            loss = self.calculate_loss(best_interest_emb, item)
            output_dict = {
                'user_emb': multi_interest_emb,
                'loss': loss,
            }
        else:
            seq_emb = self.item_emb(item_seq)  # Batch,Seq,Emb
            multi_interest_emb = self.multi_interest_layer(seq_emb, mask)  # Batch,K,Emb
            output_dict = {
                'user_emb': multi_interest_emb,
            }
        return output_dict


def my_collate(batch):
    hist_item, hist_mask, item_list = list(zip(*batch))

    hist_item = [x.unsqueeze(0) for x in hist_item]
    hist_mask = [x.unsqueeze(0) for x in hist_mask]

    hist_item = paddle.concat(hist_item, axis=0)
    hist_mask = paddle.concat(hist_mask, axis=0)
    return hist_item, hist_mask, item_list


def save_model(model, path):
    if not os.path.exists(path):
        os.makedirs(path)
    paddle.save(model.state_dict(), path + 'model.pdparams')


def load_model(model, path):
    state_dict = paddle.load(path + 'model.pdparams')
    model.set_state_dict(state_dict)
    print('model loaded from %s' % path)
    return model


def get_predict(model, test_data, hidden_size, topN=20):
    item_embs = model.output_items().cpu().detach().numpy()
    item_embs = normalize(item_embs, norm='l2')
    gpu_index = faiss.IndexFlatIP(hidden_size)
    gpu_index.add(item_embs)

    test_gd = dict()
    preds = dict()

    user_id = 0

    for (item_seq, mask, targets) in tqdm(test_data):

        # 获取用户嵌入
        # 多兴趣模型,shape=(batch_size, num_interest, embedding_dim)
        # 其他模型,shape=(batch_size, embedding_dim)
        user_embs = model(item_seq, mask, None, train=False)['user_emb']
        user_embs = user_embs.cpu().detach().numpy()

        # 用内积来近邻搜索,实际是内积的值越大,向量越近(越相似)
        if len(user_embs.shape) == 2:  # 非多兴趣模型评估
            user_embs = normalize(user_embs, norm='l2').astype('float32')
            D, I = gpu_index.search(user_embs, topN)  # Inner Product近邻搜索,D为distance,I是index
            #             D,I = faiss.knn(user_embs, item_embs, topN,metric=faiss.METRIC_INNER_PRODUCT)
            for i, iid_list in enumerate(targets):  # 每个用户的label列表,此处item_id为一个二维list,验证和测试是多label的
                test_gd[user_id] = iid_list
                preds[user_id] = I[i, :]
                user_id += 1
        else:  # 多兴趣模型评估
            ni = user_embs.shape[1]  # num_interest
            user_embs = np.reshape(user_embs,
                                   [-1, user_embs.shape[-1]])  # shape=(batch_size*num_interest, embedding_dim)
            user_embs = normalize(user_embs, norm='l2').astype('float32')
            D, I = gpu_index.search(user_embs, topN)  # Inner Product近邻搜索,D为distance,I是index
            #             D,I = faiss.knn(user_embs, item_embs, topN,metric=faiss.METRIC_INNER_PRODUCT)
            for i, iid_list in enumerate(targets):  # 每个用户的label列表,此处item_id为一个二维list,验证和测试是多label的
                recall = 0
                dcg = 0.0
                item_list_set = []

                # 将num_interest个兴趣向量的所有topN近邻物品(num_interest*topN个物品)集合起来按照距离重新排序
                item_list = list(
                    zip(np.reshape(I[i * ni:(i + 1) * ni], -1), np.reshape(D[i * ni:(i + 1) * ni], -1)))
                item_list.sort(key=lambda x: x[1], reverse=True)  # 降序排序,内积越大,向量越近
                for j in range(len(item_list)):  # 按距离由近到远遍历推荐物品列表,最后选出最近的topN个物品作为最终的推荐物品
                    if item_list[j][0] not in item_list_set and item_list[j][0] != 0:
                        item_list_set.append(item_list[j][0])
                        if len(item_list_set) >= topN:
                            break
                test_gd[user_id] = iid_list
                preds[user_id] = item_list_set
                user_id += 1
    return test_gd, preds


def evaluate(preds, test_gd, topN=50):
    total_recall = 0.0
    total_ndcg = 0.0
    total_hitrate = 0
    for user in test_gd.keys():
        recall = 0
        dcg = 0.0
        item_list = test_gd[user]
        for no, item_id in enumerate(item_list):
            if item_id in preds[user][:topN]:
                recall += 1
                dcg += 1.0 / math.log(no + 2, 2)
            idcg = 0.0
            for no in range(recall):
                idcg += 1.0 / math.log(no + 2, 2)
        total_recall += recall * 1.0 / len(item_list)
        if recall > 0:
            total_ndcg += dcg / idcg
            total_hitrate += 1
    total = len(test_gd)
    recall = total_recall / total
    ndcg = total_ndcg / total
    hitrate = total_hitrate * 1.0 / total
    return {f'recall@{topN}': recall, f'ndcg@{topN}': ndcg, f'hitrate@{topN}': hitrate}


# 指标计算
def evaluate_model(model, test_loader, embedding_dim, topN=20):
    test_gd, preds = get_predict(model, test_loader, embedding_dim, topN=topN)
    return evaluate(preds, test_gd, topN=topN)


def plot_embedding(data, title):
    x_min, x_max = np.min(data, 0), np.max(data, 0)
    data = (data - x_min) / (x_max - x_min)

    fig = plt.figure(dpi=120)
    plt.scatter(data[:, 0], data[:, 1], marker='.')

    plt.xticks([])
    plt.yticks([])
    plt.title(title)
    plt.show()


def Fr_train():
    config = {
        'train_path': 'E:/DeepMath/kuai_shou/train.csv',
        'valid_path': 'E:/DeepMath/kuai_shou/val.csv',
        'test_path': 'E:/DeepMath/kuai_shou/test.csv',
        'lr': 1e-4,
        'Epoch': 30,
        'batch_size': 512,
        'embedding_dim': 64,
        'max_length': 40,
        'n_items': 27077,
        'K': 4
    }
    # 读取数据
    train_df = pd.read_csv(config['train_path'])
    valid_df = pd.read_csv(config['valid_path'])
    test_df = pd.read_csv(config['test_path'])
    train_dataset = SeqnenceDataset(config, train_df, phase='train')
    valid_dataset = SeqnenceDataset(config, valid_df, phase='test')
    test_dataset = SeqnenceDataset(config, test_df, phase='test')
    train_loader = DataLoader(dataset=train_dataset, batch_size=config['batch_size'], shuffle=True, num_workers=8)
    valid_loader = DataLoader(dataset=valid_dataset, batch_size=config['batch_size'], shuffle=False,
                              collate_fn=my_collate)
    test_loader = DataLoader(dataset=test_dataset, batch_size=config['batch_size'], shuffle=False,
                             collate_fn=my_collate)

    model = ComirecSA(config)
    optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=config['lr'])
    log_df = pd.DataFrame()
    best_reacall = -1

    exp_path = './exp/ml-20m_softmax/ComirecSA_{}_{}_{}/'.format(config['lr'], config['batch_size'],
                                                                 config['embedding_dim'])
    os.makedirs(exp_path, exist_ok=True, mode=0o777)
    patience = 5
    last_improve_epoch = 1
    log_csv = exp_path + 'log.csv'
    # *****************************************************train*********************************************
    for epoch in range(1, 1 + config['Epoch']):
        # try :
        pbar = tqdm(train_loader)
        model.train()
        loss_list = []
        acc_50_list = []
        print()
        print('Training:')
        print()
        for batch_data in pbar:
            (item_seq, mask, item) = batch_data

            output_dict = model(item_seq, mask, item)
            loss = output_dict['loss']

            loss.backward()
            optimizer.step()
            optimizer.clear_grad()

            loss_list.append(loss.item())

            pbar.set_description('Epoch [{}/{}]'.format(epoch, config['Epoch']))
            pbar.set_postfix(loss=np.mean(loss_list))
        # *****************************************************valid*********************************************

        print('Valid')
        recall_metric = evaluate_model(model, valid_loader, config['embedding_dim'], topN=50)
        print(recall_metric)
        recall_metric['phase'] = 'valid'
        if log_df.empty:
            log_df = pd.DataFrame({k: [v] for k, v in recall_metric.items()})
        else:

            log_df = pd.concat([pd.DataFrame({k: [v] for k, v in recall_metric.items()}), log_df])
        log_df.to_csv(log_csv)

        if recall_metric['recall@50'] > best_reacall:
            save_model(model, exp_path)
            best_reacall = recall_metric['recall@50']
            last_improve_epoch = epoch

        if epoch - last_improve_epoch > patience:
            break

    print('Testing')
    model = load_model(model, exp_path)
    recall_metric = evaluate_model(model, test_loader, config['embedding_dim'], topN=50)
    print(recall_metric)
    recall_metric['phase'] = 'test'
    log_df = pd.concat([pd.DataFrame({k: [v] for k, v in recall_metric.items()}), log_df])
    log_df.to_csv(log_csv)
    item_emb = model.output_items().numpy()
    tsne_emb = TSNE(n_components=2).fit_transform(item_emb)
    plot_embedding(tsne_emb, 'ComirecSA Item Embedding')

if __name__ == '__main__':

    Fr_train()
    

gru_rec


import paddle
from paddle import nn
from paddle.io import DataLoader, Dataset
import paddle.nn.functional as F
import pandas as pd
import numpy as np
import copy
import os
import math
import random
from sklearn.metrics import roc_auc_score,log_loss
from sklearn.preprocessing import normalize
from tqdm import tqdm
from collections import defaultdict
from sklearn.manifold import TSNE
from matplotlib import pyplot as plt
import faiss
# paddle.device.set_device('gpu:0')
import warnings
warnings.filterwarnings("ignore")

class SeqnenceDataset(Dataset):
    def __init__(self, config, df, phase='train'):
        self.config = config
        self.df = df
        self.max_length = self.config['max_length']
        self.df = self.df.sort_values(by=['user_id', 'timestamp'])
        self.user2item = self.df.groupby('user_id')['item_id'].apply(list).to_dict()
        self.user_list = self.df['user_id'].unique()
        self.phase = phase

    def __len__(self, ):
        return len(self.user2item)

    def __getitem__(self, index):
        if self.phase == 'train':
            user_id = self.user_list[index]
            item_list = self.user2item[user_id]
            hist_item_list = []
            hist_mask_list = []

            k = random.choice(range(4, len(item_list)))  # 从[8,len(item_list))中随机选择一个index
            # k = np.random.randint(2,len(item_list))
            item_id = item_list[k]  # 该index对应的item加入item_id_list

            if k >= self.max_length:  # 选取seq_len个物品
                hist_item_list.append(item_list[k - self.max_length: k])
                hist_mask_list.append([1.0] * self.max_length)
            else:
                hist_item_list.append(item_list[:k] + [0] * (self.max_length - k))
                hist_mask_list.append([1.0] * k + [0.0] * (self.max_length - k))

            return paddle.to_tensor(hist_item_list).squeeze(0), paddle.to_tensor(hist_mask_list).squeeze(
                0), paddle.to_tensor([item_id])
        else:
            user_id = self.user_list[index]
            item_list = self.user2item[user_id]
            hist_item_list = []
            hist_mask_list = []

            k = int(0.8 * len(item_list))
            # k = len(item_list)-1

            if k >= self.max_length:  # 选取seq_len个物品
                hist_item_list.append(item_list[k - self.max_length: k])
                hist_mask_list.append([1.0] * self.max_length)
            else:
                hist_item_list.append(item_list[:k] + [0] * (self.max_length - k))
                hist_mask_list.append([1.0] * k + [0.0] * (self.max_length - k))

            return paddle.to_tensor(hist_item_list).squeeze(0), paddle.to_tensor(hist_mask_list).squeeze(
                0), item_list[k:]

    def get_test_gd(self):
        self.test_gd = {}
        for user in self.user2item:
            item_list = self.user2item[user]
            test_item_index = int(0.8 * len(item_list))
            self.test_gd[user] = item_list[test_item_index:]
        return self.test_gd
class GRU4Rec(nn.Layer):
    def __init__(self, config):
        super(GRU4Rec, self).__init__()

        self.config = config
        self.embedding_dim = self.config['embedding_dim']
        self.max_length = self.config['max_length']
        self.n_items = self.config['n_items']
        self.num_layers = self.config['num_layers']

        self.item_emb = nn.Embedding(self.n_items, self.embedding_dim, padding_idx=0)
        self.gru = nn.GRU(
            input_size=self.embedding_dim,
            hidden_size=self.embedding_dim,
            num_layers=self.num_layers,
            time_major=False,
        )
        self.loss_fun = nn.CrossEntropyLoss()
        self.reset_parameters()

    def calculate_loss(self,user_emb,pos_item):
        all_items = self.item_emb.weight
        scores = paddle.matmul(user_emb, all_items.transpose([1, 0]))
        return self.loss_fun(scores,pos_item)

    def output_items(self):
        return self.item_emb.weight

    def reset_parameters(self, initializer=None):
        for weight in self.parameters():
            paddle.nn.initializer.KaimingNormal(weight)

    def forward(self, item_seq, mask, item, train=True):
        seq_emb = self.item_emb(item_seq)
        seq_emb,_ = self.gru(seq_emb)
        user_emb = seq_emb[:,-1,:] #取GRU输出的最后一个Hidden作为User的Embedding
        if train:
            loss = self.calculate_loss(user_emb,item)
            output_dict = {
                'user_emb':user_emb,
                'loss':loss
            }
        else:
            output_dict = {
                'user_emb':user_emb
            }
        return output_dict

def my_collate(batch):
    hist_item, hist_mask, item_list = list(zip(*batch))

    hist_item = [x.unsqueeze(0) for x in hist_item]
    hist_mask = [x.unsqueeze(0) for x in hist_mask]

    hist_item = paddle.concat(hist_item, axis=0)
    hist_mask = paddle.concat(hist_mask, axis=0)
    return hist_item, hist_mask, item_list


def save_model(model, path):
    if not os.path.exists(path):
        os.makedirs(path)
    paddle.save(model.state_dict(), path + 'model.pdparams')


def load_model(model, path):
    state_dict = paddle.load(path + 'model.pdparams')
    model.set_state_dict(state_dict)
    print('model loaded from %s' % path)
    return model


def get_predict(model, test_data, hidden_size, topN=20):
    item_embs = model.output_items().cpu().detach().numpy()
    item_embs = normalize(item_embs, norm='l2')
    gpu_index = faiss.IndexFlatIP(hidden_size)
    gpu_index.add(item_embs)

    test_gd = dict()
    preds = dict()

    user_id = 0

    for (item_seq, mask, targets) in tqdm(test_data):

        # 获取用户嵌入
        # 多兴趣模型,shape=(batch_size, num_interest, embedding_dim)
        # 其他模型,shape=(batch_size, embedding_dim)
        user_embs = model(item_seq, mask, None, train=False)['user_emb']
        user_embs = user_embs.cpu().detach().numpy()

        # 用内积来近邻搜索,实际是内积的值越大,向量越近(越相似)
        if len(user_embs.shape) == 2:  # 非多兴趣模型评估
            user_embs = normalize(user_embs, norm='l2').astype('float32')
            D, I = gpu_index.search(user_embs, topN)  # Inner Product近邻搜索,D为distance,I是index
            #             D,I = faiss.knn(user_embs, item_embs, topN,metric=faiss.METRIC_INNER_PRODUCT)
            for i, iid_list in enumerate(targets):  # 每个用户的label列表,此处item_id为一个二维list,验证和测试是多label的
                test_gd[user_id] = iid_list
                preds[user_id] = I[i, :]
                user_id += 1
        else:  # 多兴趣模型评估
            ni = user_embs.shape[1]  # num_interest
            user_embs = np.reshape(user_embs,
                                   [-1, user_embs.shape[-1]])  # shape=(batch_size*num_interest, embedding_dim)
            user_embs = normalize(user_embs, norm='l2').astype('float32')
            D, I = gpu_index.search(user_embs, topN)  # Inner Product近邻搜索,D为distance,I是index
            #             D,I = faiss.knn(user_embs, item_embs, topN,metric=faiss.METRIC_INNER_PRODUCT)
            for i, iid_list in enumerate(targets):  # 每个用户的label列表,此处item_id为一个二维list,验证和测试是多label的
                recall = 0
                dcg = 0.0
                item_list_set = []

                # 将num_interest个兴趣向量的所有topN近邻物品(num_interest*topN个物品)集合起来按照距离重新排序
                item_list = list(
                    zip(np.reshape(I[i * ni:(i + 1) * ni], -1), np.reshape(D[i * ni:(i + 1) * ni], -1)))
                item_list.sort(key=lambda x: x[1], reverse=True)  # 降序排序,内积越大,向量越近
                for j in range(len(item_list)):  # 按距离由近到远遍历推荐物品列表,最后选出最近的topN个物品作为最终的推荐物品
                    if item_list[j][0] not in item_list_set and item_list[j][0] != 0:
                        item_list_set.append(item_list[j][0])
                        if len(item_list_set) >= topN:
                            break
                test_gd[user_id] = iid_list
                preds[user_id] = item_list_set
                user_id += 1
    return test_gd, preds


def evaluate(preds, test_gd, topN=50):
    total_recall = 0.0
    total_ndcg = 0.0
    total_hitrate = 0
    for user in test_gd.keys():
        recall = 0
        dcg = 0.0
        item_list = test_gd[user]
        for no, item_id in enumerate(item_list):
            if item_id in preds[user][:topN]:
                recall += 1
                dcg += 1.0 / math.log(no + 2, 2)
            idcg = 0.0
            for no in range(recall):
                idcg += 1.0 / math.log(no + 2, 2)
        total_recall += recall * 1.0 / len(item_list)
        if recall > 0:
            total_ndcg += dcg / idcg
            total_hitrate += 1
    total = len(test_gd)
    recall = total_recall / total
    ndcg = total_ndcg / total
    hitrate = total_hitrate * 1.0 / total
    return {f'recall@{topN}': recall, f'ndcg@{topN}': ndcg, f'hitrate@{topN}': hitrate}


def plot_embedding(data, title):
    x_min, x_max = np.min(data, 0), np.max(data, 0)
    data = (data - x_min) / (x_max - x_min)

    fig = plt.figure(dpi=120)
    plt.scatter(data[:, 0], data[:, 1], marker='.')

    plt.xticks([])
    plt.yticks([])
    plt.title(title)
    plt.show()
# 指标计算
def evaluate_model(model, test_loader, embedding_dim, topN=20):
    test_gd, preds = get_predict(model, test_loader, embedding_dim, topN=topN)
    return evaluate(preds, test_gd, topN=topN)
def train():
    config = {
        'train_path': 'E:/DeepMath/kuai_shou/train.csv',
        'valid_path': 'E:/DeepMath/kuai_shou/val.csv',
        'test_path': 'E:/DeepMath/kuai_shou/test.csv',
        'lr': 1e-4,
        'Epoch': 30,
        'batch_size': 512,
        'embedding_dim': 64,
        'max_length': 40,
        'n_items': 27077,
        'K': 4,
        'num_layers':2
    }

    # 读取数据
    train_df = pd.read_csv(config['train_path'])
    valid_df = pd.read_csv(config['valid_path'])
    test_df = pd.read_csv(config['test_path'])
    train_dataset = SeqnenceDataset(config, train_df, phase='train')
    valid_dataset = SeqnenceDataset(config, valid_df, phase='test')
    test_dataset = SeqnenceDataset(config, test_df, phase='test')
    train_loader = DataLoader(dataset=train_dataset, batch_size=config['batch_size'], shuffle=True, num_workers=8)
    valid_loader = DataLoader(dataset=valid_dataset, batch_size=config['batch_size'], shuffle=False,
                              collate_fn=my_collate)
    test_loader = DataLoader(dataset=test_dataset, batch_size=config['batch_size'], shuffle=False,
                             collate_fn=my_collate)

    model = GRU4Rec(config)
    optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=config['lr'])
    log_df = pd.DataFrame()
    best_reacall = -1

    exp_path = './exp/ml-20m_softmax/MIND_{}_{}_{}/'.format(config['lr'], config['batch_size'], config['embedding_dim'])
    os.makedirs(exp_path, exist_ok=True, mode=0o777)
    patience = 5
    last_improve_epoch = 1
    log_csv = exp_path + 'log.csv'
    # *****************************************************train*********************************************
    for epoch in range(1, 1 + config['Epoch']):
        # try :
        pbar = tqdm(train_loader)
        model.train()
        loss_list = []

        print()
        print('Training:')
        print()
        for batch_data in pbar:
            (item_seq, mask, item) = batch_data

            output_dict = model(item_seq, mask, item)
            loss = output_dict['loss']

            loss.backward()
            optimizer.step()
            optimizer.clear_grad()

            loss_list.append(loss.item())

            pbar.set_description('Epoch [{}/{}]'.format(epoch, config['Epoch']))
            pbar.set_postfix(loss=np.mean(loss_list))
        # *****************************************************valid*********************************************

        print('Valid')
        recall_metric = evaluate_model(model, valid_loader, config['embedding_dim'], topN=50)
        print(recall_metric)
        recall_metric['phase'] = 'valid'
        if log_df.empty:
            log_df = pd.DataFrame({k: [v] for k, v in recall_metric.items()})
        else:

            log_df = pd.concat([pd.DataFrame({k: [v] for k, v in recall_metric.items()}), log_df])
        log_df.to_csv(log_csv)

        if recall_metric['recall@50'] > best_reacall:
            save_model(model, exp_path)
            best_reacall = recall_metric['recall@50']
            last_improve_epoch = epoch

        if epoch - last_improve_epoch > patience:
            break

    print('Testing')
    model = load_model(model, exp_path)
    recall_metric = evaluate_model(model, test_loader, config['embedding_dim'], topN=50)
    print(recall_metric)
    recall_metric['phase'] = 'test'

    log_df = pd.concat([pd.DataFrame({k: [v] for k, v in recall_metric.items()}), log_df])
    log_df.to_csv(log_csv)
    item_emb = model.output_items().numpy()
    tsne_emb = TSNE(n_components=3).fit_transform(item_emb)
    plot_embedding(tsne_emb, 'GRU4Rec Item Embedding')
if __name__ == '__main__':
    train()

mind

import paddle
from paddle import nn
from paddle.io import DataLoader, Dataset
import paddle.nn.functional as F
import pandas as pd
import numpy as np
import copy
import os
import math
import random
from sklearn.metrics import roc_auc_score, log_loss
from sklearn.preprocessing import normalize
from tqdm import tqdm
from collections import defaultdict
from sklearn.manifold import TSNE
import seaborn as sns
from matplotlib import pyplot as plt
import faiss
import warnings

warnings.filterwarnings("ignore")


class SeqnenceDataset(Dataset):
    def __init__(self, config, df, phase='train'):
        self.config = config
        self.df = df
        self.max_length = self.config['max_length']
        self.df = self.df.sort_values(by=['user_id', 'timestamp'])
        self.user2item = self.df.groupby('user_id')['item_id'].apply(list).to_dict()
        self.user_list = self.df['user_id'].unique()
        self.phase = phase

    def __len__(self, ):
        return len(self.user2item)

    def __getitem__(self, index):
        if self.phase == 'train':
            user_id = self.user_list[index]
            item_list = self.user2item[user_id]
            hist_item_list = []
            hist_mask_list = []


            k = random.choice(range(4, len(item_list)))  # 从[8,len(item_list))中随机选择一个index

            # k = np.random.randint(2,len(item_list))
            item_id = item_list[k]  # 该index对应的item加入item_id_list

            if k >= self.max_length:  # 选取seq_len个物品
                hist_item_list.append(item_list[k - self.max_length: k])
                hist_mask_list.append([1.0] * self.max_length)
            else:
                hist_item_list.append(item_list[:k] + [0] * (self.max_length - k))
                hist_mask_list.append([1.0] * k + [0.0] * (self.max_length - k))

            return paddle.to_tensor(hist_item_list).squeeze(0), paddle.to_tensor(hist_mask_list).squeeze(
                0), paddle.to_tensor([item_id])
        else:
            user_id = self.user_list[index]
            item_list = self.user2item[user_id]
            hist_item_list = []
            hist_mask_list = []

            k = int(0.8 * len(item_list))
            # k = len(item_list)-1

            if k >= self.max_length:  # 选取seq_len个物品
                hist_item_list.append(item_list[k - self.max_length: k])
                hist_mask_list.append([1.0] * self.max_length)
            else:
                hist_item_list.append(item_list[:k] + [0] * (self.max_length - k))
                hist_mask_list.append([1.0] * k + [0.0] * (self.max_length - k))

            return paddle.to_tensor(hist_item_list).squeeze(0), paddle.to_tensor(hist_mask_list).squeeze(
                0), item_list[k:]

    def get_test_gd(self):
        self.test_gd = {}
        for user in self.user2item:
            item_list = self.user2item[user]
            test_item_index = int(0.8 * len(item_list))
            self.test_gd[user] = item_list[test_item_index:]
        return self.test_gd


class CapsuleNetwork(nn.Layer):

    def __init__(self, hidden_size, seq_len, bilinear_type=0, interest_num=4, routing_times=3, hard_readout=True,
                 relu_layer=False):
        super(CapsuleNetwork, self).__init__()
        self.hidden_size = hidden_size  # h
        self.seq_len = seq_len  # s
        self.bilinear_type = bilinear_type
        self.interest_num = interest_num
        self.routing_times = routing_times
        self.hard_readout = hard_readout
        self.relu_layer = relu_layer
        self.stop_grad = True
        self.relu = nn.Sequential(
            nn.Linear(self.hidden_size, self.hidden_size, bias_attr=False),
            nn.ReLU()
        )
        if self.bilinear_type == 0:  # MIND
            self.linear = nn.Linear(self.hidden_size, self.hidden_size, bias_attr=False)
        elif self.bilinear_type == 1:
            self.linear = nn.Linear(self.hidden_size, self.hidden_size * self.interest_num, bias_attr=False)
        else:  # ComiRec_DR
            self.w = self.create_parameter(
                shape=[1, self.seq_len, self.interest_num * self.hidden_size, self.hidden_size])

    def forward(self, item_eb, mask):
        if self.bilinear_type == 0:  # MIND
            item_eb_hat = self.linear(item_eb)  # [b, s, h]
            item_eb_hat = paddle.repeat_interleave(item_eb_hat, self.interest_num, 2)  # [b, s, h*in]
        elif self.bilinear_type == 1:
            item_eb_hat = self.linear(item_eb)
        else:  # ComiRec_DR
            u = paddle.unsqueeze(item_eb, 2)  # shape=(batch_size, maxlen, 1, embedding_dim)
            item_eb_hat = paddle.sum(self.w[:, :self.seq_len, :, :] * u,
                                     3)  # shape=(batch_size, maxlen, hidden_size*interest_num)

        item_eb_hat = paddle.reshape(item_eb_hat, (-1, self.seq_len, self.interest_num, self.hidden_size))
        item_eb_hat = paddle.transpose(item_eb_hat, perm=[0, 2, 1, 3])
        # item_eb_hat = paddle.reshape(item_eb_hat, (-1, self.interest_num, self.seq_len, self.hidden_size))

        # [b, in, s, h]
        if self.stop_grad:  # 截断反向传播,item_emb_hat不计入梯度计算中
            item_eb_hat_iter = item_eb_hat.detach()
        else:
            item_eb_hat_iter = item_eb_hat

        # b的shape=(b, in, s)
        if self.bilinear_type > 0:  # b初始化为0(一般的胶囊网络算法)
            capsule_weight = paddle.zeros((item_eb_hat.shape[0], self.interest_num, self.seq_len))
        else:  # MIND使用高斯分布随机初始化b
            capsule_weight = paddle.randn((item_eb_hat.shape[0], self.interest_num, self.seq_len))

        for i in range(self.routing_times):  # 动态路由传播3次
            atten_mask = paddle.repeat_interleave(paddle.unsqueeze(mask, 1), self.interest_num, 1)  # [b, in, s]
            paddings = paddle.zeros_like(atten_mask)

            # 计算c,进行mask,最后shape=[b, in, 1, s]
            capsule_softmax_weight = F.softmax(capsule_weight, axis=-1)
            capsule_softmax_weight = paddle.where(atten_mask == 0, paddings, capsule_softmax_weight)  # mask
            capsule_softmax_weight = paddle.unsqueeze(capsule_softmax_weight, 2)

            if i < 2:
                # s=c*u_hat , (batch_size, interest_num, 1, seq_len) * (batch_size, interest_num, seq_len, hidden_size)
                interest_capsule = paddle.matmul(capsule_softmax_weight,
                                                 item_eb_hat_iter)  # shape=(batch_size, interest_num, 1, hidden_size)
                cap_norm = paddle.sum(paddle.square(interest_capsule), -1,
                                      keepdim=True)  # shape=(batch_size, interest_num, 1, 1)
                scalar_factor = cap_norm / (1 + cap_norm) / paddle.sqrt(cap_norm + 1e-9)  # shape同上
                interest_capsule = scalar_factor * interest_capsule  # squash(s)->v,shape=(batch_size, interest_num, 1, hidden_size)

                # 更新b
                delta_weight = paddle.matmul(item_eb_hat_iter,  # shape=(batch_size, interest_num, seq_len, hidden_size)
                                             paddle.transpose(interest_capsule, perm=[0, 1, 3, 2])
                                             # shape=(batch_size, interest_num, hidden_size, 1)
                                             )  # u_hat*v, shape=(batch_size, interest_num, seq_len, 1)
                delta_weight = paddle.reshape(delta_weight, (
                    -1, self.interest_num, self.seq_len))  # shape=(batch_size, interest_num, seq_len)
                capsule_weight = capsule_weight + delta_weight  # 更新b
            else:
                interest_capsule = paddle.matmul(capsule_softmax_weight, item_eb_hat)
                cap_norm = paddle.sum(paddle.square(interest_capsule), -1, keepdim=True)
                scalar_factor = cap_norm / (1 + cap_norm) / paddle.sqrt(cap_norm + 1e-9)
                interest_capsule = scalar_factor * interest_capsule

        interest_capsule = paddle.reshape(interest_capsule, (-1, self.interest_num, self.hidden_size))

        if self.relu_layer:  # MIND模型使用book数据库时,使用relu_layer
            interest_capsule = self.relu(interest_capsule)

        return interest_capsule


class MIND(nn.Layer):
    def __init__(self, config):
        super(MIND, self).__init__()

        self.config = config
        self.embedding_dim = self.config['embedding_dim']
        self.max_length = self.config['max_length']
        self.n_items = self.config['n_items']

        self.item_emb = nn.Embedding(self.n_items, self.embedding_dim, padding_idx=0)
        self.capsule = CapsuleNetwork(self.embedding_dim, self.max_length, bilinear_type=0,
                                      interest_num=self.config['K'])
        self.loss_fun = nn.CrossEntropyLoss()
        self.reset_parameters()

    def calculate_loss(self, user_emb, pos_item):
        all_items = self.item_emb.weight
        scores = paddle.matmul(user_emb, all_items.transpose([1, 0]))
        return self.loss_fun(scores, pos_item)

    def output_items(self):
        return self.item_emb.weight

    def reset_parameters(self, initializer=None):
        for weight in self.parameters():
            paddle.nn.initializer.KaimingNormal(weight)

    def forward(self, item_seq, mask, item, train=True):

        if train:
            seq_emb = self.item_emb(item_seq)  # Batch,Seq,Emb
            item_e = self.item_emb(item).squeeze(1)

            multi_interest_emb = self.capsule(seq_emb, mask)  # Batch,K,Emb

            cos_res = paddle.bmm(multi_interest_emb, item_e.squeeze(1).unsqueeze(-1))
            k_index = paddle.argmax(cos_res, axis=1)

            best_interest_emb = paddle.rand((multi_interest_emb.shape[0], multi_interest_emb.shape[2]))
            for k in range(multi_interest_emb.shape[0]):
                best_interest_emb[k, :] = multi_interest_emb[k, k_index[k], :]

            loss = self.calculate_loss(best_interest_emb, item)
            output_dict = {
                'user_emb': multi_interest_emb,
                'loss': loss,
            }
        else:
            seq_emb = self.item_emb(item_seq)  # Batch,Seq,Emb
            multi_interest_emb = self.capsule(seq_emb, mask)  # Batch,K,Emb
            output_dict = {
                'user_emb': multi_interest_emb,
            }
        return output_dict


def my_collate(batch):
    hist_item, hist_mask, item_list = list(zip(*batch))

    hist_item = [x.unsqueeze(0) for x in hist_item]
    hist_mask = [x.unsqueeze(0) for x in hist_mask]

    hist_item = paddle.concat(hist_item, axis=0)
    hist_mask = paddle.concat(hist_mask, axis=0)
    return hist_item, hist_mask, item_list


def save_model(model, path):
    if not os.path.exists(path):
        os.makedirs(path)
    paddle.save(model.state_dict(), path + 'model.pdparams')


def load_model(model, path):
    state_dict = paddle.load(path + 'model.pdparams')
    model.set_state_dict(state_dict)
    print('model loaded from %s' % path)
    return model


def get_predict(model, test_data, hidden_size, topN=20):
    item_embs = model.output_items().cpu().detach().numpy()
    item_embs = normalize(item_embs, norm='l2')
    gpu_index = faiss.IndexFlatIP(hidden_size)
    gpu_index.add(item_embs)

    test_gd = dict()
    preds = dict()

    user_id = 0

    for (item_seq, mask, targets) in tqdm(test_data):

        # 获取用户嵌入
        # 多兴趣模型,shape=(batch_size, num_interest, embedding_dim)
        # 其他模型,shape=(batch_size, embedding_dim)
        user_embs = model(item_seq, mask, None, train=False)['user_emb']
        user_embs = user_embs.cpu().detach().numpy()

        # 用内积来近邻搜索,实际是内积的值越大,向量越近(越相似)
        if len(user_embs.shape) == 2:  # 非多兴趣模型评估
            user_embs = normalize(user_embs, norm='l2').astype('float32')
            D, I = gpu_index.search(user_embs, topN)  # Inner Product近邻搜索,D为distance,I是index
            #             D,I = faiss.knn(user_embs, item_embs, topN,metric=faiss.METRIC_INNER_PRODUCT)
            for i, iid_list in enumerate(targets):  # 每个用户的label列表,此处item_id为一个二维list,验证和测试是多label的
                test_gd[user_id] = iid_list
                preds[user_id] = I[i, :]
                user_id += 1
        else:  # 多兴趣模型评估
            ni = user_embs.shape[1]  # num_interest
            user_embs = np.reshape(user_embs,
                                   [-1, user_embs.shape[-1]])  # shape=(batch_size*num_interest, embedding_dim)
            user_embs = normalize(user_embs, norm='l2').astype('float32')
            D, I = gpu_index.search(user_embs, topN)  # Inner Product近邻搜索,D为distance,I是index
            #             D,I = faiss.knn(user_embs, item_embs, topN,metric=faiss.METRIC_INNER_PRODUCT)
            for i, iid_list in enumerate(targets):  # 每个用户的label列表,此处item_id为一个二维list,验证和测试是多label的
                recall = 0
                dcg = 0.0
                item_list_set = []

                # 将num_interest个兴趣向量的所有topN近邻物品(num_interest*topN个物品)集合起来按照距离重新排序
                item_list = list(
                    zip(np.reshape(I[i * ni:(i + 1) * ni], -1), np.reshape(D[i * ni:(i + 1) * ni], -1)))
                item_list.sort(key=lambda x: x[1], reverse=True)  # 降序排序,内积越大,向量越近
                for j in range(len(item_list)):  # 按距离由近到远遍历推荐物品列表,最后选出最近的topN个物品作为最终的推荐物品
                    if item_list[j][0] not in item_list_set and item_list[j][0] != 0:
                        item_list_set.append(item_list[j][0])
                        if len(item_list_set) >= topN:
                            break
                test_gd[user_id] = iid_list
                preds[user_id] = item_list_set
                user_id += 1
    return test_gd, preds


def evaluate(preds, test_gd, topN=50):
    total_recall = 0.0
    total_ndcg = 0.0
    total_hitrate = 0
    for user in test_gd.keys():
        recall = 0
        dcg = 0.0
        item_list = test_gd[user]
        for no, item_id in enumerate(item_list):
            if item_id in preds[user][:topN]:
                recall += 1
                dcg += 1.0 / math.log(no + 2, 2)
            idcg = 0.0
            for no in range(recall):
                idcg += 1.0 / math.log(no + 2, 2)
        total_recall += recall * 1.0 / len(item_list)
        if recall > 0:
            total_ndcg += dcg / idcg
            total_hitrate += 1
    total = len(test_gd)
    recall = total_recall / total
    ndcg = total_ndcg / total
    hitrate = total_hitrate * 1.0 / total
    return {f'recall@{topN}': recall, f'ndcg@{topN}': ndcg, f'hitrate@{topN}': hitrate}


# 指标计算
def evaluate_model(model, test_loader, embedding_dim, topN=20):
    test_gd, preds = get_predict(model, test_loader, embedding_dim, topN=topN)
    return evaluate(preds, test_gd, topN=topN)


def plot_embedding(data, title):
    x_min, x_max = np.min(data, 0), np.max(data, 0)
    data = (data - x_min) / (x_max - x_min)

    fig = plt.figure(dpi=120)
    plt.scatter(data[:, 0], data[:, 1], marker='.')

    plt.xticks([])
    plt.yticks([])
    plt.title(title)
    plt.show()

def Fr_train():
    config = {
        'train_path': 'E:/DeepMath/kuai_shou/train.csv',
        'valid_path': 'E:/DeepMath/kuai_shou/val.csv',
        'test_path': 'E:/DeepMath/kuai_shou/test.csv',
        'lr': 1e-4,
        'Epoch': 30,
        'batch_size': 512,
        'embedding_dim': 64,
        'max_length': 40,
        'n_items': 27077,
        'K': 4
    }

    # 读取数据
    train_df = pd.read_csv(config['train_path'])
    valid_df = pd.read_csv(config['valid_path'])
    test_df = pd.read_csv(config['test_path'])
    train_dataset = SeqnenceDataset(config, train_df, phase='train')
    valid_dataset = SeqnenceDataset(config, valid_df, phase='test')
    test_dataset = SeqnenceDataset(config, test_df, phase='test')
    train_loader = DataLoader(dataset=train_dataset, batch_size=config['batch_size'], shuffle=True, num_workers=8)
    valid_loader = DataLoader(dataset=valid_dataset, batch_size=config['batch_size'], shuffle=False,
                              collate_fn=my_collate)
    test_loader = DataLoader(dataset=test_dataset, batch_size=config['batch_size'], shuffle=False,
                             collate_fn=my_collate)

    model = MIND(config)
    optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=config['lr'])
    log_df = pd.DataFrame()
    best_reacall = -1

    exp_path = './exp/ml-20m_softmax/MIND_{}_{}_{}/'.format(config['lr'], config['batch_size'], config['embedding_dim'])
    os.makedirs(exp_path, exist_ok=True, mode=0o777)
    patience = 5
    last_improve_epoch = 1
    log_csv = exp_path + 'log.csv'
    # *****************************************************train*********************************************
    for epoch in range(1, 1 + config['Epoch']):
        # try :
        pbar = tqdm(train_loader)
        model.train()
        loss_list = []
        acc_50_list = []
        print()
        print('Training:')
        print()
        for batch_data in pbar:
            (item_seq, mask, item) = batch_data

            output_dict = model(item_seq, mask, item)
            loss = output_dict['loss']

            loss.backward()
            optimizer.step()
            optimizer.clear_grad()

            loss_list.append(loss.item())

            pbar.set_description('Epoch [{}/{}]'.format(epoch, config['Epoch']))
            pbar.set_postfix(loss=np.mean(loss_list))
        # *****************************************************valid*********************************************

        print('Valid')
        recall_metric = evaluate_model(model, valid_loader, config['embedding_dim'], topN=50)
        print(recall_metric)
        recall_metric['phase'] = 'valid'
        if log_df.empty:
            log_df = pd.DataFrame({k: [v] for k, v in recall_metric.items()})
        else:

            log_df = pd.concat([pd.DataFrame({k: [v] for k, v in recall_metric.items()}), log_df])
        log_df.to_csv(log_csv)

        if recall_metric['recall@50'] > best_reacall:
            save_model(model, exp_path)
            best_reacall = recall_metric['recall@50']
            last_improve_epoch = epoch

        if epoch - last_improve_epoch > patience:
            break

    print('Testing')
    model = load_model(model, exp_path)
    recall_metric = evaluate_model(model, test_loader, config['embedding_dim'], topN=50)
    print(recall_metric)
    recall_metric['phase'] = 'test'
    log_df = pd.concat([pd.DataFrame({k: [v] for k, v in recall_metric.items()}), log_df])
    log_df.to_csv(log_csv)

    item_emb = model.output_items().numpy()
    tsne_emb = TSNE(n_components=2).fit_transform(item_emb)
    plot_embedding(tsne_emb, 'MIND Item Embedding')


if __name__ == '__main__':
    Fr_train()

感谢:

  • 李清舟
  • 至味人间
  • 沐曦baba
  • 春雪芳菲
  • DataMastermind
  • Artemis
  • MAI
  • 皇城根奶爸
  • 一个小老虎
  • 遥远的瞧
  • 飞黄腾踏去
  • 小狐狸M
  • 一见导师就变乖
  • JamesHarden_
  • zibuyu9
  • 金城七
  • verwandte
  • 鄢希不是糖
  • 带带小猪頭
  • laforet
  • 珍儿要有梦
  • Alkaid.K
  • 打打印机
  • 优达学城(Udacity)
  • KerstinTongxi
  • 秦老猫
  • weixin_32592297
  • 勃拉图
  • 杜雨茜
  • 8枚
  • 伊红美兰
  • 鹤运
  • 赖智超
  • 嘉禾博研左方程
  • 2401_84036823
  • ShirahaneSuoh
  • 三脚猫功夫猴
  • 知心大哥
  • czsl
  • 苏远岫
  • 夜十六
  • 刘孝虎
  • 翻山狮
  • 雯雯呀
  • 鄂奎阿
  • 冯明溪
  • 刘不言
  • 孤傲雕
  • CRomputer-罗军
  • 俞组
  • weixin_28916013
  • 雾里元宝
  • 斗鱼直播-大司马~~
  • 钢蛋鸭
  • 各自安好吧
  • 徐辉947
  • 序雨
  • python作业毕设
  • O
  • lyg012
  • 荣耀张大仙mk~~
  • 黑雾思索者
  • Jan
  • Duo小妖
  • 戴某DEMO
  • 雨前羽街
  • easycofe
  • 赵利兴
  • 康儿妈咪
  • 文强孙
  • 小菜鸡记录生活
  • 恐怖电影爱好者
  • atQ4N
  • 张钧琦
  • Lhmily0718
  • 久作无端客
  • NetNinja
  • Sabrina
  • 5点的太阳
  • Quant最爱
  • 32罗翔说~~~
  • 聪明帅气的阿凯
  • 你来说我来听
  • 无心高调
  • 张大胃
  • 熙南君
  • pink怒怒酱
  • 开东
  • 本书本
  • 轻萌小说
  • 喂今天救公主了吗
  • 糯米不是饭
  • OurPlay
  • 弥古爱书法
  • UEgood雪姐姐
  • 柏林墙东侧
  • 非典型普通人类
  • Gdsw-D
  • pp夏
  • 北方南先生
  • AC编程
  • 宇哥讲电影
  • wx24e331e6d83e1b9f
  • PixelPuzzlist
  • 伊斯特艾格
  • weixin_34354231
  • 初小轨
  • 医脉通
  • 卢梅庆
  • 乐观观天下
  • 孔皓
  • 一块烤地瓜
  • 荷达
  • 土豆做成泥很好吃
  • 唰唰说创业
  • muyyyi
  • 665733489631
  • 玄铁匠
  • 珞珈小山
  • a301
  • kaorouwoyaochi
  • 甜甜爱笑
  • 拉斯科纳夫
  • 谐波治理小陈
  • 腾岳掌门
  • KimiOnZhihu
  • 中国计算机学会
  • 榣木
  • invalid
  • 火猫人
  • 有石
  • 田仲政
  • 好好医生one
  • 京城风四娘
  • rainman
  • 丹的小跟班
  • 灰色的男孩
  • 明德zhuang
  • 夏之幻想
  • 好什一
  • 王连涛
  • 云保链CIC
  • 科技娜评
  • 月华剑士张大彪
  • 罗大哥
  • 柒年tender
  • weixin_36462532
  • 伍世棋
  • 甘团路
  • 怂喵rise
  • 6d
  • 影子医生
  • WIDGAF
  • 氧化三氢正离子
  • 清水33
  • 张敬禹
  • Simon
  • 厂妹
  • blossomzwj
  • AI前线
  • Elsafun
  • 爱地人
  • konjunktur
  • tankCYT
  • codgician
  • 两半24409
  • Lucas
  • 鱼利安
  • 一两赘肉无
  • 叶建均
  • Julojulo
  • 金利来Goldlion
  • 晋小睿(已退乎)
  • 不爱吃mao
  • 暖色Cecilia
  • 渔翁丶稀饭
  • 香江不知名前浪
  • Kelly
  • 小后羿
  • DigitalElusion
  • 三叔侃侃
  • 苏沉船
  • 岁月未染
  • 携程邮轮
  • 铁拳无敌双鸭山
  • Troy爱滑雪
  • 智者也
  • 流氓拳宗师
  • zhoudiNEU
  • 三三俩俩
  • 罗小熙
  • 尼克六六
  • 2401_83815144
  • 科技888
  • laplaceliu
  • 白泽之水
  • 木子淇
  • medabroad
  • 斯迈尔齿科
  • 金渡江
  • 吕驰宇
  • jzjzjxjxj
  • Rrrrrrr_a
  • 喝墨水的猫
  • 武藤
  • 2401_83167347
  • InfoMaster
  • 张奕明
  • Cyber
  • jkyu
  • 我为歌狂有崽了
  • CVRunner
  • 老凯撒的钱
  • 豆蔻茶
  • 我在四平路上
  • gonggon
  • 吃素的pig
  • 戴戴好
  • 太田秋明
  • errommel
  • 赵少林
  • 稚一
  • 师父曰
  • 魔术狗
  • 18767873417
  • 璐寶
  • 吉田区块链
  • Shaun
  • 阿呆酱
  • SlyerD
  • 白酸奶
  • 暮汐颜
  • 朱庇特不是宙斯
  • 切高仔
  • 果舒
  • 花猫哥哥
  • 徘徊孤独
  • 弘世堇
  • 孙继军
  • 卤蛋鱼丸粗面
  • 张允健
  • 曹逆娘曹
  • 啊呀呀
  • 王羿秋
  • 42号车库
  • 剑使者
  • 日签君AIUX
  • 影歌小队长
  • Marcus
  • 木头骨头石头
  • 明治奶茶味雪糕
  • 张盛锋
  • Freya鸭鸭
  • Davider_Wu
  • hhhjknb
  • byco
  • 依JO
  • 孔祥謙
  • 温哥华小文青
  • 李大颖
  • misshohxil
  • 青山布衣
  • 慕云飞
  • 卡休微卡
  • 陳懋兒Hannah
  • 豆腐LZ
  • 钮钴禄·缇
  • Naoki
  • 东方安璇
  • Paradox
  • 解忧小巫仙
  • 溯水襄陵
  • 陈昊芝
  • 徵琛
  • 开发者傑
  • 王一点寒
  • 吴光于
  • 小大隐
  • 刘军莉
  • BossGuo果老板
  • 甲烷生产者
  • 司炉
  • 程军超
  • 綺懷
  • weixin_40675290
  • 苏友学
  • Daydayydayyy
  • Miuyana
  • 吴裕彬
  • 江涛校泵
  • 八卦钩沉
  • 冯鑫怡
  • 游道人
  • 圆宗
  • 亮姐
  • 樰篱
  • 今朝有昔
  • G僧东
  • weixin_40819800
  • 爱怹
  • 顾汐漫
  • 依然念鼬
  • 风之木叶
  • 住颜
  • off彩蛋
  • 王希亚
  • Mefls
  • Brandon
  • 邱荣城
  • 我不发文章啦
  • 北西南风
  • 林志强
  • 一颗墙上的稻草
  • 水精灵琼子
  • 来自宇宙外的未知生物
  • 周天无极
  • 十万泼皮
  • 连续失眠者C
  • Fred
  • bottomer
  • HyperliquidX
  • 杨良昆
  • Shelly陳一楠
  • 其实只是平凡人
  • 就叫D吧
  • PraiseSunMan
  • 解说柯基\x01mkq0.~
  • VizXu
  • 红糖小糍粑
  • 墨墨张
  • 章王舜
  • 皮肤医生朱岳衡
  • 林忆酒
  • 句子院
  • 七彩极光
  • 淬过火的家鸽
  • 维林兄弟
  • Krisinmel
  • 沈鸫驿
  • 燕仰
  • 据克
  • 新语丝
  • 漩凝
  • 陪刘耀文写五三
  • 声振研究
  • 言雨潇
  • Francis
  • 裕文璋
  • 球球铭刻录
  • 刘权德
  • 氪老师
  • 15886991492
  • a1072024
  • 灵境里的孤舟
  • 别人的鞋
  • JIA-璐
  • 介敏狼狼
  • 小丑逼
  • 天下的乌鸦不一般黑
  • 分秒帧
  • 丶方可
  • 草莓味儿柠檬
  • peyton-?
  • 这里是益达
  • 面料知识馆
  • 胖酷帅
  • 张宜辅
  • qq5471179162
  • 将作于少监
  • 真正的小蚂蚁
  • Piper蛋窝
  • 琥珀每人
  • 宠头条
  • Java天骄
  • 雪麻麻yl
  • Jovi.wang
  • 淡于水
  • 人知广
  • 实战剑术路人FIM
  • 架狙只打脚
  • 秋凤梧
  • chinhoyoo
  • weixin_53947681
  • 葵葵有问题
  • 知之者不如好之者
  • weixin_49192623
  • freevil
  • tanakajohn
  • 张小璇
  • 心碎的恶魔
  • ALEX
  • 刘天昭
  • yutin020
  • 长腿小姑娘
  • lambdaJi
  • sleep豆
  • 时维教育顾老师
  • 左歪
  • 阿木吃饭用大碗
  • 扒熊
  • 牛先森
  • 讲故事的妹妹
  • emitofomemeda
  • 澜方
  • 井冉
  • krisyoung1028
  • 苏沃洛夫
  • 韭菜后浪
  • 任博冰Bob
  • 莫尔奔
  • 高辰光
  • MHJCR
  • 彭迅鹏xp
  • CyberGoddess
  • 温柔对待自己
  • 尔你
  • 苟全性命于治世
  • Bonsen
  • 摘星星的男孩
  • 芒果加柠檬
  • About
  • 勤劳课代表
  • xinwuji312
  • 唐风宋影
  • Demon学长
  • 据说名字要够短
  • 耗子不偷油
  • 勋哥很忙
  • 疯而不jue
  • 大海贼青木
  • 兔撕鸡大老爷
  • dgccfhhv
  • 相月十久
  • 绳子上的蚂蚱
  • 卫迟
  • 星空下的史诗
  • ScriptHero
  • 熬夜编程小垃圾
  • 不知彼岸
  • 李德邻
  • Tfifthe
  • weixin_51792875
  • 删号怎么尕
  • 冯正华
  • cohen
  • Lucemon
  • 瓜瓜龙
  • 左脚刹车右脚油门
  • 刘兮
  • litterbug21
  • Virtus
  • 杨香蕉
  • 日更阿婆
  • 主播仁杰
  • 请叫我段教授
  • 超越学姐杭州分越
  • 流风兮回雪
  • Project
  • 东坡不改了
  • 藩依然
  • 胡天宝
  • 西门子中国
  • ScandalRafflesia
  • SY-EU德易至
  • 日读课
  • 味离
  • chunhui
  • 首席测评师
  • 王Tie塔儿
  • Scarlett(王萍)
  • 饶龙友
  • 柳飞祥
  • pk2017
  • Youlink
  • 薛莹莹de洋果子
  • 肖深刻的九叔
  • ECUSTJared
  • 不执不迷
  • 呦鱼儿
  • weixin_28730665
  • 亿丁丁
  • Facilidad
  • 彬者·诡道
  • 真格量化
  • 蔡千年
  • 相争何为
  • 杰长老
  • redchina111
  • frankie
  • 知之只
  • weixin_36972161
  • 绥哲所谓
  • 大力小豆
  • 一小撮人
  • 老年吉米
  • AY-onmyway
  • 兰艳知己
  • Yang
  • 一颗青木
  • 喜迁莺
  • Mio
  • Zzh3514
  • 一躲躲
  • 乔克蜀黍丶
  • 精明败家女杨爷
  • 零悠悠
  • 笔杆abc
  • 高中物理宋老师
  • 菲比她他它
  • 阿弥陀佛
  • 蓦风星吟
  • 钭胥冉
  • 胡世博
  • 养猪编码工
  • dyingflames
  • 酒夏
  • 品牌烧友-A
  • 郝艺益
  • 可可子姐姐教英语
  • 厉向晨
  • 13512954815
  • Camellia
  • shine-well
  • 日向夕阳
  • 薛玉玺
  • 吴名璞
  • 怪叔叔来了
  • 核电那些事
  • 无锡星晴侯鹏飞
  • 清峪沟的砍柴人
  • 猫咪的室友
  • 巴白比波布
  • da北斗ret
  • ffts0721
  • 小小仙女儿
  • Moriarty
  • 无糖信息
  • 忧伤的石一
  • 农资从业者
  • 舜祎魂
  • 赵阿
  • 爷兰
  • borninbad
  • 德格扎西次仁
  • 普罗马克
  • 走进良夜
  • Purkialo
  • 织浪
  • 邹正限
  • 键盘音乐家
  • 米斯特JIANG
  • 鱼水鲤缘
  • 学术入门
  • 285995986
  • 森因那夫
  • tkh831219
  • 好奇de梓洋
  • 雷米斯
  • 冯委
  • 就是雪
  • 马宇轩
  • 东海羊驼
  • 灰熊问题最优解
  • 浅盏半茗茶
  • 磅礴科技
  • 路I
  • 胡侃侃
  • 兰德水
  • TA家住在沙漠中
  • 碧海云天97
  • 霜之韵逸
  • 萧井陌
  • 酱好不
  • 墨尔本雪球兔
  • BinaryBard
  • 陈六六的成长笔记
  • 雕牌优质眼药水
  • 袁廷翠09050082
  • 月半羊
  • 懒小木
  • 王Jason王
  • 迷茫不再迷茫
  • qwrrq12134
  • 理性且坚决
  • 飞清一色
  • Dexter.Yy
  • Ms
  • 雄心似铁
  • 风自
  • 林琬清
  • 刘照云卡
  • 玫瑰妈妈
  • Amy婧
  • 张浩驰
  • 松果煲粥
  • 奶茶余香
  • Wonder王达
  • 西芹姑娘
  • 添奇艺术伞-立辉
  • Chau.Hui
  • 想法臃肿
  • 物语妖
  • 腿姐姐u
  • 牧心钰Cassie
  • talitzy
  • CyberHero
  • 赵仙君
  • CyberNinja
  • 杨浩鸣
  • 一璇
  • 往事浮烟
  • 遙朢鷰園
  • 苏式糖粥
  • 派网大话狗
  • 玩木丧志
  • 辟克匿克
  • lkxl
  • 九酱酱酱酱酱
  • 颜镇钟
  • 群响-刘思毅
  • 黄叶欣
  • iff-qyc
  • 亦未
  • 卜仆
  • weixin_31092081
  • 藏雍之
  • 金吉他
  • 堞堞
  • mydiplomacy
  • 宝贝入怀
  • 诚is
  • 黄衔
  • 芊暖
  • 徐行忠
  • 大白兔奶糖呀
  • 牛站长
  • 插座学院
  • 诚灏
  • 米佗耶目
  • 了了她姐
  • 我画的娃娃脸
  • 多问
  • jimy
  • 樊旖斐
  • 诗人流浪汉
  • 作者小怪兽
  • weixin_36955541
  • 住在树上的牛顿
  • 2301_80904942
  • 维权骑士
  • 徐再旭
  • zhihuyaowan
  • 阿证证证证
  • 娃咋养
  • 伊迪亚特
  • 十弦曲觞
  • 躺着不干活
  • fatgn
  • 兮扬
  • 李国凤
  • 龙黄天下
  • 牛奶浴花生
  • 小松ekko
  • 2401_83080457
  • 诺壹乔
  • 上官义飞
  • 没有名字233
  • 薛继续
  • 2301_80585628
  • 姜懿珊
  • Mr浪子相依
  • jackey-金融
  • 八度飞雪
  • 大叔默默路过
  • Tone
  • xpf769815576
  • PrivateRookie
  • 蛋卷毛毛
  • 2301_81244691
  • 银光秋叶
  • 胡格
  • DigitalDragon
  • 衡水中屑official
  • 运动与物理康复
  • 123456zggb
  • 牛开心
  • pmbian
  • 陈fay
  • 游很多话
  • 宋玄宾
  • 林潘
  • Zeng
  • 我的小幸运
  • 南极熊3D打印
  • 咻电联盟18336067661
  • prettySXY
  • 官真
  • 千面娇娃酒不修
  • m0_73127071
  • 茶未凉人已散
  • 碧微公子
  • 呱呱呱www
  • wei0168520
  • 你猜-我是谁
  • 鞠猫
  • 曜冰
  • ONES
  • 长余陆离
  • weixin_58632235
  • guonilp
  • 冷幽香
  • 晚点LatePost
  • 天氣真好喔
  • 2401_83010645
  • 我有烧饼你有酒吗
  • 酱呀
  • cyhjty
  • 唐臭臭
  • ICT杂谈
  • 甘雨火光
  • 雷幺幺
  • 懒床上的猫
  • 江啾
  • 0000
  • 花开知多少
  • 让我眼熟你
  • 北山南湖
  • 兰榕笙
  • 托卡马克之冠\x01m~~
  • 燕衔泥PPT
  • 狠茬子嘻嘻
  • 飞翔的嘉别
  • ChuaChuaFeng
  • 牛人说
  • baby小花
  • 朱耶伽罗
  • 李奇正
  • 邱教练学堂
  • 庄蹊
  • 南洋野人
  • DeepWeaver
  • 材料搬砖狗
  • 叶苏培
  • Gavin
  • 一捆稻草垛
  • youye
  • 庄黑胖-伍拾万
  • naif_cy
  • 一杨千里迢迢牵牛星
  • 天街踏尽公卿骨
  • 兔子同学
  • 夕风彦
  • khaki轩然
  • 已经退乎的路人
  • Dumb丁
  • 郭啧西
  • 请给我骨头
  • 北京永诚印刷
  • 邹益健
  • 往里卷
  • AllFiredUp
  • 对视三秒
  • Lrsmn-x
  • 潜水队长
  • 锋剑一族
  • 耀眼曦光
  • 小灰灰同学
  • HermanXYZ
  • 富富设计
  • 胃泰小胃君
  • 叶修的伞
  • 卢策吾
  • 宁敏
  • CN队长
  • 本尼桑
  • 岑做
  • 一土水丰色今口
  • 偏偏无理取闹
  • 小巧的高跟鞋
  • mhj1990
  • 11先生
  • 肉丸君
  • 宁艳玲
  • sweet
  • TKSJ
  • 李华晨
  • 摩羯啪啦啪啦
  • Lilililipretty
  • wow机智兮米粒丘
  • 罪歌2011
  • 天才娜娜ln
  • AT姜
  • 你找不到我啦
  • its斯弟文
  • 一米八七的大帅哥
  • 北木南烟
  • 叶伏城
  • 陈华葵
  • xclca
  • 非典型工科生
  • 何书欣
  • 肉身君
  • 罗宏宝
  • 会写代码的好厨师
  • Nature自然科研
  • 李首良
  • 已婚屌丝
  • [HUC]–ksh
  • big
  • 曹胜波
  • Evelyn
  • 勃恶霸
  • 太球
  • 惢安
  • 科技缪缪
  • 观后感刚刚好
  • 行影旅行
  • rrKnow
  • 旋叶芦荟mkq
  • darkdress
  • 我喜欢你小朋友
  • 苏安桥
  • 江思捷
  • 李月巴鱼
  • 解说柯基\x01mkq
  • 腕表天地
  • 阿文说钱
  • 西瓜苦力怕
  • 何沐沐
  • 亚大伯斯
  • Kotori
  • 无伤大雅的骆驼
  • 默认关系
  • 站在天台上看上帝
  • 兔卡
  • 知乎商业小管家
  • 谢月生
  • 晓文说财
  • weixin_40423078
  • 顺数人
  • Tatasisy
  • 大地孤狼
  • 袁大岛
  • 燕枝
  • 我寄几
  • 苏瑞文
  • 精神心理何日辉
  • 机械堡垒
  • 葛艺潇
  • hore12
  • 月之地
  • 林中白鹿
  • 黄莉娟
  • m0_75009479
  • 宋世泊
  • peng
  • 欧阳万里
  • 白衣战土
  • 撸铁妹
  • 思哈豆
  • 夜盏
  • 陈仁浩
  • 在韩国的敏欧尼
  • myosin
  • Yan
  • 东南前哨
  • 番茄罐
  • 游魂2
  • Balinda婷婷
  • greatwallisme
  • Maple
  • 老徐说
  • Hi-iD
  • PettySoul
  • 伟星啊
  • 密斯how
  • 蒋栋蔚
  • Fei
  • 运营老高
  • 水廿八
  • 于伟豪
  • gaojb2141129
  • weixin_44983006
  • 暂停一下下
  • 北美地产学堂
  • lange
  • 清宵月明
  • 马利碳笔
  • zLiM5
  • 不止尚行
  • 光阳果
  • 唐杰宇
  • 雾里寻声
  • 刘宏山083
  • 筛分技术
  • weixin_28726871
  • 黄差败
  • whygqm
  • 瓦罗兰十字军
  • SlowdownDdddddd
  • 精灵之火
  • Capex
  • 刘杭州
  • Tim
  • 爱燃烧
  • 水龙敬
  • 智诚1818
  • 鎏怀瑾
  • 20250101
  • 易职嗨
  • 柯学友
  • 歹小悦
  • filweo
  • d198902
  • 会员联盟
  • weixin_41699549
  • 玺微の时光
  • 卫酷酷
  • Reaper
  • 2301_80615417
  • weixin_59061340
  • CDKingHang
  • 2301_81786037
  • 2401_82590801
  • 2301_79370722
  • 2301_80735542
  • 2301_80471080
  • 2401_82563337
  • ashshouldgo
  • 2301_81323248
  • xiaogang206
  • 2201_75708777
  • 2301_81875574
  • nipponofficial
  • 2301_81669415
  • 2301_82229336
  • MessyCandle丶
  • qq_44388469
  • 2301_81211889
  • linhj20
  • 阳和启蛰834
  • 2401_82407173
  • 2302_79604626
  • 2302_80430759
  • hp125626
  • upup293
  • 路野没有苏
  • 你好刘同学
  • 布拉达勇士
  • 2301_82091956
  • 連117
  • 2303_81635589
  • 爱吃薯条的l
  • 杀手海王
  • u013665684
  • kmn04
  • Famiglistimo_01
  • [Neptune]
  • 2301_82105743
  • 凯瑟琳大王
  • 2401_82478192
  • 忙着长大的丫丫
  • 2401_82497365
  • 萌萌1212
  • |
  • 2301_81343863
  • 天盗盗
  • 2401_82491506
  • 柠檬小仙女C
  • Riceman
  • 2401_82397406
  • 2401_82484621
  • qbkivlin
  • Chrix
  • 君有点小暖
  • 剪好头发回家
  • weixin_40564623
  • 薇莉
  • 木楠依
  • 苏小晗
  • 马骏骁
  • Dr.Rodney
  • weixin_44710965
  • 会飞的洋子
  • 成都AG超玩会老帅
  • Mikey
  • livhui
  • 2301_79218897
  • 不想说话的树
  • maggie67
  • m0_62212436
  • 333M
  • 张卡特
  • 周晓农
  • 山簡
  • 坚强努力地活下去
  • 兔兔xuan
  • yaoyao是我
  • 住范儿石乐天
  • 呼呼啦啦就瘸了
  • 大司马了不起
  • 周达和
  • 雷雨航
  • 清清本清
  • 诶你说什么
  • summerrabit
  • YE625
  • 就念
  • Raymond
  • 袁江旭
  • 辟谣的大舌头LONG
  • 悠悠黄鹤楼
  • 鵬鵬鵬鵬
  • 丁子栩
  • 清风余欢
  • 林秀秀g
  • CodeWhiz
  • 我鸿
  • weixin_30453651
  • 吴寒笛
  • 蓝盐泳池1983
  • 销声
  • 真实故事计划
  • 卖猫粮的小叔
  • 元音a
  • 马渊程
  • 杜扬Seatory
  • 南燕Jo
  • InnovationGuru
  • 老先队员
  • 小xs
  • 原点GD
  • 华清阙
  • lcct_shu
  • 谈修竹
  • TechTinkerer
  • Seolac
  • 野蛮人柯南
  • weixin_27727467
  • 你一直在玩儿
  • 屁师
  • 春华秋实的夏
  • 我累个擦:<
  • 宋朗坤
  • Ruby437
  • 無酒
  • 郴江郑明兰
  • 心理咨询师-宋杨
  • Twopothead
  • 护城河河长
  • ianlesliejet
  • 弍戈
  • 林中有一只小猫猫
  • 张蛋花
  • 缪加
  • 少刷知乎多读书
  • 海边的弗兰克
  • 纪发发
  • 秋水顾盼
  • 煌煌不安
  • myy4988
  • Dreamer寻
  • 好孩纸kimi爱大圣
  • 米凯勒
  • 雪停时偶遇一叶春
  • kagb
  • Elka
  • 投稿小助手
  • 橘子咚咚
  • wanchuanlong
  • moxirich
  • qq_55253983
  • 刘锋135538569000
  • 托尼郭
  • Lybrust
  • a291337862
  • 江泓
  • 有点小病
  • 寻尘客
  • 六号轨迹
  • 丹凤张杰
  • 王靖海
  • Tasrue
  • 雕粱画栋
  • 胡启奋
  • 人间最好小师叔
  • gaocegege
  • 张大有
  • 网易《了不起的中国制造》
  • 026后勤处
  • re硕君
  • 张玮(O-o)
  • 布拉格2
  • I6and7
  • 李军文
  • 柯尔鸭鸭
  • 龙一歌
  • 霉斯漫
  • 我爱专利
  • bathroom火冒
  • blhzmmf
  • 上海买房人
  • 颜究员
  • 堂堂堂堂堂主
  • 江文锴
  • 门田木
  • Li
  • Books.Fan
  • 夏洛特Charlotte
  • 希茅
  • 张坤平安
  • &D先生
  • parisbob
  • 指路明灯君
  • 菜菜美食日记
  • 乞力马扎罗的猴子
  • 安藤崇
  • Wawzyniec
  • Caprcorn
  • liuzhiyaoooo
  • ྲ552
  • 司马各
  • 晒太阳的小黑猫
  • 2301_80761895
  • 2301_81284979
  • 江千里
  • lsgn
  • 方头Pokerman
  • monprotocol
  • 2301_78823239
  • weixin_57449952
  • 2301_79683098
  • 好き丸子
  • AlpHaCracker
  • hzhangsa
  • Miaozerong
  • 2301_81056293
  • m0_72041520
  • 2301_81213077
  • 望月愁
  • 拿秃子的酒杯
  • 朱凤仙
  • 啥雷慧星
  • 2301_77149178
  • Tagtax
  • 2301_81188326
  • 田哥玛丽
  • 2305_79018775
  • 云扰
  • otx009super
  • 2301_81192457
  • 影视后期王荣
  • 林声飘扬
  • 逆光纪
  • 阿廖林诺
  • 一人一猫浪迹天涯
  • 温糯米
  • 穆迪老师
  • 一滴血的记忆
  • 好奇宝宝打脸怪
  • 谢艺馨
  • Lucy-露西娅
  • 淡庸
  • Manting
  • 西天取经路遥迢
  • 型爷
  • 诗无忌
  • Luca_Lu
  • xsvipx4869
  • Rachel瑞小秋
  • Damon
  • 尘箬芳桦
  • 达欣欣
  • 东予薏米
  • 罗元裳
  • 麓雍
  • 黄鱼冻
  • 早鸟
  • 江仕蕾
  • 王金龙花柒
  • 咸鱼豆腐
  • LearningandStudy
  • 幸福暗恋我
  • 冰镐供应商
  • 克莱儿儿儿
  • quant林
  • 梦里看花a
  • 华亿
  • 司徒夜
  • Gnocchiiii
  • 心理咨询师林博宇
  • 3菲菲
  • andyyah
  • 明日座头鲸
  • 曼仔呀
  • 不吐槽会死星人i
  • 燕山美发
  • 央企小老头
  • 跑马溜溜
  • Ming小然
  • 一朵云从平流层坠下
  • 何钦尧
  • 吃肉的梅小姐
  • 每天一个收货
  • 王谭
  • 陈村
  • 埃斯蓬托的篡位者
  • 俯卧撑菜鸟
  • 怪怪的Mogeko
  • 最上川灵感大王
  • qq_48582659
  • noah642
  • 人and人
  • m0_64601486
  • Yorium
  • 2301_80668056
  • 好588
  • RyFooX
  • 2301_76448989
  • 用户昵称已存在……错误……
  • itwebber
  • 林闽琦
  • wxd86d5613e425e18b
  • 2301_80071268
  • 2301_76403620
  • 2301_81011043
  • 2301_81013940
  • 2301_80383138
  • weixin_46615692
  • 微软技术分享
  • 黔台老酒坊
  • 小瓮同学
  • 灵魂机器
  • 耀怡
  • baskice
  • longyang0917
  • 啃老师
  • 有伱真好
  • 罗俊(顺义PICC)
  • 刘为龙
  • 馋包包我们走
  • 葛店小学张洪雨
  • 发现者号
  • biu~
  • FUUFK
  • m0_67598909
  • 南小吕
  • m0_61393398
  • ShAn
  • .
  • weixin_39505051
  • 借我一把金太刀
  • 不会飞的鹰08
  • qq_64694880
  • weixin_47898112
  • qq_45292756
  • 希出崖涘
  • 20240901
  • GALAXY
  • Lllixy%
  • m0_70563695
  • m0_74282103
  • 2301_77131751
  • MasterZerα
  • m0_61098022
  • qq_48962699
  • weixin_51793392
  • CSDN_alearner
  • 2301_80044454
  • Cyber_D
  • 沈聪祥
  • weixin_40376578
  • weixin_48071367
  • Jiang_Immortals
  • weixin_45392838
  • 和光-ycl
  • 长沙何书桓
  • m0_59123733
  • 古月氵
  • 阳光一直都在
  • iohgy
  • 2301_76764655
  • oooqoyooo
  • lspppppp
  • 褪色的,记忆
  • 探索者_SHU
  • jackey0135
  • th1157828416
  • qq_46311760
  • 真命天子xy
  • ,。,。,。770
  • yupo555
  • chun_yin
  • Leo
  • idea-second
  • dsqykf
  • Messi20145102
  • weixin_44953803
  • AriSan_XD
  • YWSFFJ
  • weixin_38912254
  • thepolest
  • weixin_46378822
  • ?Endless??
  • 王早起Mornings
  • weixin_40328981
  • kerwin666666
  • 穆如清风-
  • weixin_45676656
  • 叫牛奶的特仑苏
  • 2301_78036593
  • 2301_79547616
  • ll489
  • z726218y
  • HUCONcong
  • Sakura20201017
  • Idie_
  • m0_69349550
  • RS+DLer
  • Antisocial
  • m405230843
  • 鱼-qq
  • hamzsy
  • I123456T
  • weixin_45526931
  • 像风像雾又像雨6
  • qq_36497656
  • 憨化龙猫
  • 白小岩
  • TobetterMan
  • Brain
  • sa16225447_aasdf
  • weixin_48030023
  • m0_66285644
  • 129beer
  • python_dizhongdi
  • 2301_79442945
  • 梦想变成光
  • 浩浩是我阿
  • a2233883
  • 飞凡850
  • luojing913
  • weixin_39750622
  • 偏爱中国红
  • DemonHunter211
  • paperxxx
  • zuojunming0600
  • wink537
  • u010544479
  • 小赵啊。嗯哼
  • weixin_44218547
  • 可乐小超人
  • 211统计
  • 黎罹
  • 巨量HTTP
  • 一只快乐的小龟
  • m0_70472418
  • 高祺
  • m0_74060374
  • 2301_79349731
  • qq_39169688
  • 刘635
  • wlwlwl0511
  • 野心未泯
  • weixin_48511181
  • poptar
  • Cape0915
  • qq_16068833
  • lycdc_z
  • byhehe
  • 懒-洋洋
  • ghjud
  • 语音识别_小白
  • 桦曳
  • qq_36722565
  • 211统计课堂
  • 充电君
  • h15728721597
  • qq_35154867
  • 鲸云夕陌
  • lobster.
  • 胖鸽
  • qq_51644107
  • 极客曰报
  • oceanao
  • m0_69876149
  • 2301_79201558
  • 我就笑吧728
  • 醴碘
  • 大金Mrking
  • CN930804
  • 日向小太阳
  • weixin_54669750
  • weixin_40701906
  • iso230
  • 2301_76718493
  • satellite7
  • m0_68703686
  • m0_63268594
  • 随风56
  • qq_34029746
  • 宝贝今晚想吃啥
  • slc18698726058
  • 咚咚锵的小波波
  • zz_comeon
  • wfshan06
  • 弈诚
  • 毛毛
  • mbwlhf666
  • ai__xiaoyang
  • skyvoice2
  • 二七学长
  • Strawberrer
  • weixin_54896532
  • 华为OD面试指南
  • 叶庭云
  • xydlovecjj
  • qq_40412114
  • Yuyang7372
  • 灰格
  • wude111
  • weixin_45428949
  • Yanzhenjinghan_
  • Charlie_1541
  • satday725
  • fuwy
  • 2301_76386433
  • Curtain?(o^^o)?
  • weixin_47520923
  • qq_57626668
  • m0_55989410
  • a1780335808
  • zzc2323
  • Pandaser
  • xyvybun
  • 颜肆陆
  • 山月记469
  • c_s_____d_n
  • a1205683
  • 快乐晓笑98
  • li53957741
  • 小武落泪
  • zou_jian_
  • 刘建杰
  • 麻烦指证批评
  • weixin_41756759
  • 叶尖上跳跃
  • zrr12620
  • everylovebc
  • 20250401
  • qq_41411881
  • m0_73519261
  • 陆臣杰
  • 朽木莲
  • 尘埃里的月光
  • chenfulong005
  • m0_37680878
  • 笨小孩Qu
  • xyz9527xyz
  • kidmix
  • weixin_44829335
  • 夏701
  • zkk9390
  • wudehua55555
  • 陈嘉嘉嘉嘉
  • m0_38065375
  • m0_46178874
  • LYB_383409060
  • YANYAOHUI_
  • weixin_46067110
  • l66624766
  • 编程大狮
  • Katherine_19
  • 2201_75836058
  • m0_61916878
  • Nanxious_Leo
  • txfTrap
  • sinat_23581595
  • 求学80后
  • 魔力矩阵
  • nana_lhan
  • 码码小猿
  • m0_49149738
  • 小头先森
  • starry
  • m0_49217555
  • m0_64335638
  • 啥时开始
  • weixin_69926086
  • 黄开炎
  • Csdsdfa
  • relaxing520
  • aaaaaaaaddd2
  • weixin_57061799
  • pighead_1016
  • 奶茶舒胡蕾
  • qq_43630189
  • m0_69898704
  • babykikii
  • m0_59673911
  • 2301_78564831
  • m0_57230756
  • qq_20754835
  • 我是我儿爹
  • qq_36877641
  • m0_51528231
  • weixin_53774310
  • 依然饭特稀_0574
  • 麦唛
  • weixin_57126192
  • weixin_44542985
  • LZ创
  • 小白abner
  • m0_69859729
  • 春待月九
  • qq_45760142
  • 2301_77334809
  • 宇宙小菜菜
  • QiranMu
  • qq_52184092
  • weixin_68946462
  • 帅帅的单身狗
  • 風火雷
  • btbtmy?
  • CYX441
  • sovelen
  • Philowen
  • 2301_77965635
  • NZGMTCAH
  • m0_71178254
  • l501900
  • JohnWong007
  • m0_70902221
  • cldyg222
  • qq_57897148
  • m0_63740483
  • evil2333
  • WayneBin
  • qq_46663976
  • weixin_46190290
  • chaosDY
  • 不争之德
  • shuxuejianmo314
  • 白白。猫
  • qq_47348533
  • 一枚程序员
  • Benjamin_Young
  • fadedol
  • 棒棒哒小纸盒z
  • IT_baiban
  • weixin_38270019
  • 0Oo�
  • weixin_58616412
  • 2201_75706509
  • gaokeaiya
  • 三窗
  • Gatorade001
  • m0_69453712
  • weixin_46808723
  • MOB2333
  • qq_42114034
  • welkin_lg
  • m0_58448384
  • Energia_Buran
  • axl668
  • weixin_44855103
  • qq_30681957
  • 我随心动
  • 水日之秋
  • 李无趣
  • qq_37510379
  • qq_38057104
  • Hsatr
  • Y~404
  • 图灵软件技术
  • 十螺纹
  • AllenSun34
  • 这个年纪你怎么睡得着的
  • 大约在雨季。
  • 大羊腿
  • 2201_76066153
  • qq_27794783
  • 聂鲁达不哒
  • ncuthmk
  • nvoian
  • SD1way
  • Typhoonn
  • lttzy
  • 2301_77693996
  • jiagang_
  • 布丁_码到成功
  • 别任性
  • m0_70818773
  • let_wang
  • u010181864
  • gt17969
  • hshsjp
  • tmachina
  • a48631685
  • zzerhtd
  • engine_men
  • 2301_77601254
  • qq_45871585
  • 二分法QwQ
  • weixin_48950343
  • Arlene_08
  • Diamond我
  • 寄给你星河
  • Alex
  • Z.Robot
  • comic
  • m0_59457021
  • qq_57218083
  • dawn_breeze_
  • sleepyshaman
  • GLewis
  • 妳っ
  • 杲昃
  • Transient_520
  • angledou
  • 杳冥、
  • 伈刼@
  • qq_34052077
  • Anoxia_Tian
  • m0_67716204
  • relax
  • O氧
  • awnusk
  • 0o圈圈o0爱
  • jin946
  • 再不学就来不及了
  • lwj070117
  • 嗨和嗨
  • lijiejie1
  • KYRIE00
  • 走心371
  • tcyxy123
  • THAST
  • 小猫了
  • xy66_
  • 2301_76672683
  • 咖啡凉了_hy
  • 摆摆渡人
  • wL0NG
  • 四幺
  • 7thheavenWML
  • 狄水云笙
  • 打铁匠Mr_Lee
  • 等你下课ソ
  • Cynthiacircle
  • 天海一直在AI
  • Wbig
  • d⊙▽⊙x
  • qq_42796828
  • NowLoadY
  • weixin_44170459
  • weixin_40352994
  • apinapple
  • Python_15
  • The
  • F0oreVeR
  • 晚椒
  • qq_46010292
  • +vvv
  • 贝塔西塔
  • simonlijili
  • rabbit3691
  • weixin_45202744
  • qq779670222
  • nbmn
  • qa_ws_99
  • A1234587_000
  • qq_38343917
  • 话唠画废
  • ZtLoveWym
  • 五分Q
  • Y199826
  • dyz13
  • hanhanyld
  • 2301_76678729
  • MountVoom
  • agneskan
  • m0_74424405
  • weixin_49078858
  • 假面游魂
  • ChA0s007
  • a646711278
  • Phantom_ruin
  • weixin_45749271
  • qq_53270509
  • Delanncy
  • m0_50111564
  • 扫地僧的扫帚
  • stone_312
  • m0_59039269
  • 慕容飞
  • yishujiayou
  • D.Woodward
  • for?;;?
  • qq_36042424
  • 小张tostring
  • Henderson_X
  • Since_july
  • weixin_49142770
  • sinat_39136647
  • weixin_67033104
  • superliuchun
  • 夏目幸一
  • slide
  • vapnik222
  • WwwhaiXuu
  • Darry00
  • HuMHk
  • mr9725
  • qq_57621558
  • 2301_76608612
  • DeemeDD
  • Bean_3
  • qq_42939186
  • m0_54165145
  • m0_63405099
  • 秃头猿是可可粉
  • La
  • yeyeye37
  • 咕噜Kerwin
  • myccver
  • 酷ky
  • Holy姜姜
  • weixin_46800063
  • 彭彭丫
  • qq_44488613
  • m0_69353409
  • X_Jun005
  • 千君殇
  • 普通网友
  • zz_qq32107
  • ZacharyZzl
  • m0_74935297
  • 优秀木木.
  • 归居于尘°
  • Floraaaa?
  • 无敌番茄酱
  • Mr.利威尔
  • 多尝试多记录多积累
  • 希望_睿智
  • weixin_51440866
  • 一不小心嗑到牙了
  • Fyzqae
  • 炫荡之灵
  • ➹枫丹白露
  • 喝摩卡的狐狸
  • 小糖宝
  • 哈佛215
  • 柏劲松
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Scala 推荐系统是一种基于 Scala 编程语言实现的推荐系统。Scala 是一种功能强大的静态类型编程语言,它被广泛用于大规模数据处理、机器学习和人工智能等领域。Scala 推荐系统通常采用基于协同过滤、基于内容的过滤、深度学习等算法来实现,用于为用户提供个性化的推荐服务。Scala 推荐系统常见的应用场景包括电子商务、社交网络、音乐和视频推荐等领域。 ### 回答2: Scala推荐系统是基于Scala语言构建的一种推荐算法模型或系统。推荐系统是一种根据用户过去行为和兴趣来向其推荐可能感兴趣的物品或信息的系统。Scala推荐系统在实现推荐功能时,通常采用协同过滤、内容过滤或混合过滤等算法来分析用户的历史行为和物品的内容特征,并根据这些信息给用户生成个性化的推荐结果。 Scala作为一种强类型的静态编程语言,具有开发效率高、代码易读性好、可扩展性强等特点,因此在推荐系统的开发中得到了广泛应用。Scala推荐系统可以利用Scala语言的强大特性,如模式匹配、集合操作、并发编程等来实现推荐算法的设计和优化。同时,Scala还可以与Java等其他语言进行无缝对接,方便与现有系统进行集成。 Scala推荐系统的开发过程通常包括数据预处理、特征提取、模型构建、结果生成等步骤。首先,开发人员需要对原始数据进行清洗和整理,从中提取出有用的特征。然后,根据特征选取适合的推荐算法模型,如协同过滤模型、基于内容的模型等,并通过Scala语言实现这些模型。最后,利用已经训练好的模型,根据用户的行为和特征生成个性化的推荐结果,并以可视化或其他方式呈现给用户。 总之,Scala推荐系统是一种基于Scala语言构建的推荐算法模型或系统,它能够利用Scala的特点来设计和优化推荐算法,并通过分析用户的行为和物品的特征生成个性化的推荐结果。 ### 回答3: Scala推荐系统是一种使用Scala编程语言开发的推荐系统。推荐系统是一种能够为用户提供个性化推荐的软件系统。它根据用户的兴趣、行为以及其他相关信息,预测用户可能感兴趣的物品,并将这些推荐展示给用户。 Scala是一种现代化的静态类型编程语言,它结合了面向对象编程和函数式编程的特性。Scala具有强大的类型推断能力和表达能力,使得开发者可以用更简洁、更具表达力的方式编写代码。因此,使用Scala来开发推荐系统可以提高开发效率和代码可读性。 Scala推荐系统通常会利用机器学习算法和数据挖掘技术来提取用户行为数据和物品特征,进行特征工程和模型训练。常见的推荐算法包括协同过滤、内容过滤、深度学习等。这些算法可以根据不同的应用场景和问题进行选择和调整,从而提高推荐系统的准确性和效果。 Scala推荐系统的特点包括高性能、分布式计算能力、灵活的数据处理和算法实现等。Scala可以方便地与其他大数据框架(如Apache Spark)集成,实现快速、可扩展的推荐计算。此外,Scala还具备丰富的函数库和工具包,为推荐系统的开发和部署提供了很多有力的支持。 总之,Scala推荐系统是一种使用Scala编程语言开发的能够根据用户行为和特征进行个性化推荐的软件系统。它利用机器学习算法和数据挖掘技术,具备高性能、分布式计算能力和灵活的数据处理和算法实现,可以提供准确、有效的推荐服务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东方佑

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值