categorical_data(类别型数据)预处理笔记:转化为数字

本文介绍如何使用Python和R语言进行数据预处理,包括读取文件、转换数据类型、处理异常值等步骤。针对具体数据集如Soybean,提供详细的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

1、用Python转化为标准格式。

import pandas as pd
import numpy as np
from pandas import Series, DataFrame
from sklearn.preprocessing import LabelEncoder

#一般操作
#读文件:
#e:/cate_data/before/filename.txt
#1将文件读入成Dataframe数据。分隔符默认为"\t",读的时候文件中无列名(否则把第一行作为列名)。
data = pd.read_table('old_path',',',header = None)
#2类别型数据转化为数字表示。
num = data.shape[1]
for i in range(num):
    dimensional_name = data.columns[i]#第i个维度的列名。
    data[dimensional_name] = LabelEncoder().fit_transform(data[dimensional_name].values)#转化
#3将DataFrame数据写入文件。写的时候不要索引和标题。
data.to_csv('new_path',index=False,header=None)

#附加操作
data = data.drop(data.columns[1],axis = 1) #去掉第1(二)行。
length = len(data[data.columns[2]][0].split()[0])#字符串长度
data1 = DataFrame(columns=range(length))#初始化一个空的DataFrame。
for i in range(data[data.columns[1]].shape[0]):
    a = list(data[data.columns[1]][i].split())
    b = list(a[0])
    # 将字典输入给DataFrame构造器,各项会成为DataFrame的一行,字典健将成为DataFrame的列标
    dashabi = dict(zip(list(range(length)),b))
    dashabi1 = DataFrame(dashabi,index=[0])
    # 往DataFrame添加行的方式(gnore_index=True表示去掉原来的行标,重新开始编排)
    data1= data1.append(dashabi1,ignore_index=True)
    # pd.concat([data1, dashabi1, dashabi2, ...], ignore_index=True)(第二种)
data = data.drop(data.columns[1],axis = 1) #去掉第1(二)行。
data1 = pd.concat([data1,data],axis =1,ignore_index=True)#axis默认为0,列拼接。
data = data1

#额外操作
del data[0] #删除第0列,删除后列编号就没有0了。
data.columns = range(10) #给列重新编号。
data.dtypes  #查看每一列的数据类型。

输出:
0     int64
1     int64
2     int64
3     int64
4     int64
5    object #第五列含有异常值'?'。
6     int64
7     int64
8     int64
9     int64
dtype: object

#去除含有异常值的行
#1统计含有异常值的行。
j = []
for i in range(699):
    if(data[5][i] == '?'): #是字符。
        j.append(i)
#2删除行。
data = data.drop(j)
#3行重新编号。
data.index = range(len(data.index))
#4将类型转化为int64。
data[5] = pd.to_numeric(data[5])

#查看每一列的数据类型。
data.dtypes 
输出:
0     int64
1     int64
2     int64
3     int64
4     int64
5     int64 #转化完毕。
6     int64
7     int64
8     int64
9     int64
dtype: object

#mushroom(替换缺失值(异常值'?'))。
#1读入。
data = pd.read_table('e:/lxt/cate_data/before/mushroom.txt',',',header = None)
#2统计含有异常值的列。
l = []
for i in range(data.shape[1]):
    if '?' in pd.unique(data[i]):
        l.append(i)
#3随机替换异常值为值域中的值。
for i in l:
    #生成值域(pd.unique返回类型为numpy.ndarray)。
    hahaha = pd.unique(data[i])['?' != pd.unique(data[i])]
    for j in range(data.shape[0]):
        if(data[i][j] == '?'):
            #随机从值域挑选替换。
            data[i][j] = hahaha[np.random.randint(0,hahaha.shape[0])]
#转化为连续数字。
for i in range(data.shape[1]):
    dimensional_name = data.columns[i]#第i个维度的列名。
    data[dimensional_name] = LabelEncoder().fit_transform(data[dimensional_name].values)
#将类别换到最后。
label = data[0].copy()
del data[0]
data = pd.concat([data,label],axis =1,ignore_index=True)
#输出。
data.to_csv('e:/lxt/cate_data/after/mushroom.txt',index=False,header=None)
data.to_csv('e:/lxt/cate_data/after/mushroom.csv',index=False,header=None)
        

数据:UCI数据集:Soybean(small),Connect4,Promoters。

需要进行附加操作的数据:Promoters:

+,S10,		tactagcaatacgcttgcgttcggtggttaagtatgtataatgcgcgggcttgtcgt
+,AMPC,		tgctatcctgacagttgtcacgctgattggtgtcgttacaatctaacgcatcgccaa
+,AROH,		gtactagagaactagtgcattagcttatttttttgttatcatgctaaccacccggcg
+,DEOP2,	aattgtgatgtgtatcgaagtgtgttgcggagtagatgttagaatactaacaaactc
+,LEU1_TRNA,	tcgataattaactattgacgaaaagctgaaaaccactagaatgcgcctccgtggtag
+,MALEFG,	aggggcaaggaggatggaaagaggttgccgtataaagaaactagagtccgtttaggt
+,MALK,		cagggggtggaggatttaagccatctcctgatgacgcatagtcagcccatcatgaat
+,RECA,		tttctacaaaacacttgatactgtatgagcatacagtataattgcttcaacagaaca
+,RPOB,		cgacttaatatactgcgacaggacgtccgttctgtgtaaatcgcaatgaaatggttt
+,RRNAB_P1,	ttttaaatttcctcttgtcaggccggaataactccctataatgcgccaccactgaca
+,RRNAB_P2,	gcaaaaataaatgcttgactctgtagcgggaaggcgtattatgcacaccccgcgccg
+,RRNDEX_P2,	cctgaaattcagggttgactctgaaagaggaaagcgtaatatacgccacctcgcgac
+,RRND_P1,	gatcaaaaaaatacttgtgcaaaaaattgggatccctataatgcgcctccgttgaga
+,RRNE_P1,	ctgcaatttttctattgcggcctgcggagaactccctataatgcgcctccatcgaca
+,RRNG_P1,	tttatatttttcgcttgtcaggccggaataactccctataatgcgccaccactgaca
+,RRNG_P2,	aagcaaagaaatgcttgactctgtagcgggaaggcgtattatgcacaccgccgcgcc
+,RRNX_P1,	atgcatttttccgcttgtcttcctgagccgactccctataatgcgcctccatcgaca
+,TNAA,		aaacaatttcagaatagacaaaaactctgagtgtaataatgtagcctcgtgtcttgc
+,TYRT,		tctcaacgtaacactttacagcggcgcgtcatttgatatgatgcgccccgcttcccg
+,ARAC,		gcaaataatcaatgtggacttttctgccgtgattatagacacttttgttacgcgttt
+,LACI,		gacaccatcgaatggcgcaaaacctttcgcggtatggcatgatagcgcccggaagag
+,MALT,		aaaaacgtcatcgcttgcattagaaaggtttctggccgaccttataaccattaatta
+,TRP,		tctgaaatgagctgttgacaattaatcatcgaactagttaactagtacgcaagttca
+,TRPP2,	accggaagaaaaccgtgacattttaacacgtttgttacaaggtaaaggcgacgccgc
+,THR,		aaattaaaattttattgacttaggtcactaaatactttaaccaatataggcatagcg
+,BIOB,		ttgtcataatcgacttgtaaaccaaattgaaaagatttaggtttacaagtctacacc
+,FOL,		catcctcgcaccagtcgacgacggtttacgctttacgtatagtggcgacaatttttt
+,UVRBP1,	tccagtataatttgttggcataattaagtacgacgagtaaaattacatacctgcccg
+,UVRBP3,	acagttatccactattcctgtggataaccatgtgtattagagttagaaaacacgagg
+,LEXA,		tgtgcagtttatggttccaaaatcgccttttgctgtatatactcacagcataactgt
+,PORI-L,	ctgttgttcagtttttgagttgtgtataacccctcattctgatcccagcttatacgg
+,SPOT42,	attacaaaaagtgctttctgaactgaacaaaaaagagtaaagttagtcgcgtagggt
+,M1RNA,	atgcgcaacgcggggtgacaagggcgcgcaaaccctctatactgcgcgccgaagctg
+,GLNS,		taaaaaactaacagttgtcagcctgtcccgcttataagatcatacgccgttatacgt
+,TUFB,		atgcaattttttagttgcatgaactcgcatgtctccatagaatgcgcgctacttgat
+,SUBB-E,	ccttgaaaaagaggttgacgctgcaaggctctatacgcataatgcgccccgcaacgc
+,STR,		tcgttgtatatttcttgacaccttttcggcatcgccctaaaattcggcgtcctcata
+,SPC,		ccgtttattttttctacccatatccttgaagcggtgttataatgccgcgccctcgat
+,RPOA,		ttcgcatatttttcttgcaaagttgggttgagctggctagattagccagccaatctt
+,RPLJ,		tgtaaactaatgcctttacgtgggcggtgattttgtctacaatcttacccccacgta
+,PORI-R,	gatcgcacgatctgtatacttatttgagtaaattaacccacgatcccagccattctt
+,ALAS,		aacgcatacggtattttaccttcccagtcaagaaaacttatcttattcccacttttc
+,ARABAD,	ttagcggatcctacctgacgctttttatcgcaactctctactgtttctccatacccg
+,BIOA,		gccttctccaaaacgtgttttttgttgttaattcggtgtagacttgtaaacctaaat
+,DEOP1,	cagaaacgttttattcgaacatcgatctcgtcttgtgttagaattctaacatacggt
+,GALP2,	cactaatttattccatgtcacacttttcgcatctttgttatgctatggttatttcat
+,HIS,		atataaaaaagttcttgctttctaacgtgaaagtggtttaggttaaaagacatcagt
+,HISJ,		caaggtagaatgctttgccttgtcggcctgattaatggcacgatagtcgcatcggat
+,ILVGEDA,	ggccaaaaaatatcttgtactatttacaaaacctatggtaactctttaggcattcct
+,LACP1,	taggcaccccaggctttacactttatgcttccggctcgtatgttgtgtggaattgtg
+,LPP,		ccatcaaaaaaatattctcaacataaaaaactttgtgtaatacttgtaacgctacat
+,TRPR,		tggggacgtcgttactgatccgcacgtttatgatatgctatcgtactctttagcgag
+,UVRB_P2,	tcagaaatattatggtgatgaactgtttttttatccagtataatttgttggcataat
-, 867,		atatgaacgttgagactgccgctgagttatcagctgtgaacgacattctggcgtcta
-,1169,		cgaacgagtcaatcagaccgctttgactctggtattactgtgaacattattcgtctc
-, 802,		caatggcctctaaacgggtcttgaggggttttttgctgaaaggaggaactatatgcg
-, 521,		ttgacctactacgccagcattttggcggtgtaagctaaccattccggttgactcaat
-, 918,		cgtctatcggtgaacctccggtatcaacgctggaaggtgacgctaacgcagatgcag
-,1481,		gccaatcaatcaagaacttgaagggtggtatcagccaacagcctgacatccttcgtt
-,1024,		tggatggacgttcaacattgaggaaggcataacgctactacctgatgtttactccaa
-,1149,		gaggtggctatgtgtatgaccgaacgagtcaatcagaccgctttgactctggtatta
-, 313,		cgtagcgcatcagtgctttcttactgtgagtacgcaccagcgccagaggacgacgac
-, 780,		cgaccgaagcgagcctcgtcctcaatggcctctaaacgggtcttgaggggttttttg
-,1384,		ctacggtgggtacaatatgctggatggagatgcgttcacttctggtctactgactcg
-, 507,		atagtctcagagtcttgacctactacgccagcattttggcggtgtaagctaaccatt
-,  39,		aactcaaggctgatacggcgagacttgcgagccttgtccttgcggtacacagcagcg
-,1203,		ttactgtgaacattattcgtctccgcgactacgatgagatgcctgagtgcttccgtt
-, 988,		tattctcaacaagattaaccgacagattcaatctcgtggatggacgttcaacattga
-,1171,		aacgagtcaatcagaccgctttgactctggtattactgtgaacattattcgtctccg
-, 753,		aagtgcttagcttcaaggtcacggatacgaccgaagcgagcctcgtcctcaatggcc
-, 630,		gaagaccacgcctcgccaccgagtagacccttagagagcatgtcagcctcgacaact
-, 660,		ttagagagcatgtcagcctcgacaacttgcataaatgctttcttgtagacgtgccct
-,1216,		tattcgtctccgcgactacgatgagatgcctgagtgcttccgttactggattgtcac
-, 835,		tgctgaaaggaggaactatatgcgctcatacgatatgaacgttgagactgccgctga
-,  35,		catgaactcaaggctgatacggcgagacttgcgagccttgtccttgcggtacacagc
-,1218,		ttcgtctccgcgactacgatgagatgcctgagtgcttccgttactggattgtcacca
-, 668,		catgtcagcctcgacaacttgcataaatgctttcttgtagacgtgccctacgcgctt
-, 413,		aggaggaactacgcaaggttggaacatcggagagatgccagccagcgcacctgcacg
-, 991,		tctcaacaagattaaccgacagattcaatctcgtggatggacgttcaacattgagga
-, 751,		tgaagtgcttagcttcaaggtcacggatacgaccgaagcgagcctcgtcctcaatgg
-, 850,		ctatatgcgctcatacgatatgaacgttgagactgccgctgagttatcagctgtgaa
-,  93,		gcggcagcacgtttccacgcggtgagagcctcaggattcatgtcgatgtcttccggt
-,1108,		atccctaatgtctacttccggtcaatccatctacgttaaccgaggtggctatgtgta
-, 915,		tggcgtctatcggtgaacctccggtatcaacgctggaaggtgacgctaacgcagatg
-,1019,		tctcgtggatggacgttcaacattgaggaaggcataacgctactacctgatgtttac
-,  19,		tattggcttgctcaagcatgaactcaaggctgatacggcgagacttgcgagccttgt
-,1320,		tagagggtgtactccaagaagaggaagatgaggctagacgtctctgcatggagtatg
-,  91,		cagcggcagcacgtttccacgcggtgagagcctcaggattcatgtcgatgtcttccg
-, 217,		ttacgttggcgaccgctaggactttcttgttgattttccatgcggtgttttgcgcaa
-, 957,		acgctaacgcagatgcagcgaacgctcggcgtattctcaacaagattaaccgacaga
-, 260,		ggtgttttgcgcaatgttaatcgctttgtacacctcaggcatgtaaacgtcttcgta
-, 557,		aaccattccggttgactcaatgagcatctcgatgcagcgtactcctacatgaataga
-,1355,		agacgtctctgcatggagtatgagatggactacggtgggtacaatatgctggatgga
-, 244,		tgttgattttccatgcggtgttttgcgcaatgttaatcgctttgtacacctcaggca
-, 464,		tgcacgggttgcgatagcctcagcgtattcaggtgcgagttcgatagtctcagagtc
-, 296,		aggcatgtaaacgtcttcgtagcgcatcagtgctttcttactgtgagtacgcaccag
-, 648,		ccgagtagacccttagagagcatgtcagcctcgacaacttgcataaatgctttcttg
-, 230,		cgctaggactttcttgttgattttccatgcggtgttttgcgcaatgttaatcgcttt
-,1163,		tatgaccgaacgagtcaatcagaccgctttgactctggtattactgtgaacattatt
-,1321,		agagggtgtactccaagaagaggaagatgaggctagacgtctctgcatggagtatga
-, 663,		gagagcatgtcagcctcgacaacttgcataaatgctttcttgtagacgtgccctacg
-, 799,		cctcaatggcctctaaacgggtcttgaggggttttttgctgaaaggaggaactatat
-, 987,		gtattctcaacaagattaaccgacagattcaatctcgtggatggacgttcaacattg
-,1226,		cgcgactacgatgagatgcctgagtgcttccgttactggattgtcaccaaggcttcc
-, 794,		ctcgtcctcaatggcctctaaacgggtcttgaggggttttttgctgaaaggaggaac
-,1442,		taacattaataaataaggaggctctaatggcactcattagccaatcaatcaagaact

 2、用R语言读入。

#函数(自己写)
read_data <- function(file_path,header = FALSE){
    data_list = read.csv(file = file_path,header = header)
    dimensional_num = length(data_list)
    data_num = length(data_list[[1]])
    dataset = list()
    data_set = matrix(0,dimensional_num-1,data_num)
    for (i in 1:(dimensional_num-1)) {
        data_set[i,] = data_list[[i]]
    }
    dataset$data = data_set
    dataset$label = data_list[[dimensional_num]]
    dataset$hidden_clusters = Hidden_clusters(dataset$label)
    return(dataset)
}
#label生成(原分类)
Hidden_clusters <- function(data_labels){
    uni = unique(data_labels)
    num = length(data_labels)
    hidden_clusters = list()
    i = 1
    for(j in uni){
        hidden_clusters[[i]] = (1:num)[data_labels == j]
        i = i + 1
    }
    return(hidden_clusters)
}
#读入(例子)
Soybean = read_data(file_path = "e:\\lxt\\cate_data\\after\\soybean.txt")

 

# -*- coding: utf-8 -*- """ 京东高价值客户识别与全链路行为预测系统 - 修复版 作者:李梓翀 李富生 数据来源:京东公开数据(模拟生成) """ import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from datetime import datetime, timedelta import random import time import os from faker import Faker from sklearn.preprocessing import LabelEncoder, StandardScaler from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.cluster import KMeans from sklearn.metrics import (roc_auc_score, precision_score, recall_score, f1_score, mean_absolute_error, roc_curve) from sklearn.decomposition import PCA # -------------------------- # 数据爬取与模拟生成 # -------------------------- def generate_jd_simulation_data(num_users=5000, num_records=50000): """ 模拟生成京东用户行为数据 """ print("开始生成模拟京东数据...") fake = Faker('zh_CN') np.random.seed(42) # 创建用户基础数据 users = pd.DataFrame({ 'user_id': [f'U{str(i).zfill(6)}' for i in range(1, num_users+1)], 'age': np.random.randint(18, 65, num_users), 'gender': np.random.choice(['男', '女'], num_users, p=[0.55, 0.45]), 'city': [fake.city() for _ in range(num_users)], 'is_plus_member': np.random.choice([0, 1], num_users, p=[0.7, 0.3]), 'join_date': [fake.date_between(start_date='-3y', end_date='today') for _ in range(num_users)] }) # 创建行为数据 behavior_types = ['浏览', '加购', '购买', '评价', '收藏'] categories = { '家电': ['冰箱', '洗衣机', '空调', '电视', '微波炉'], '手机': ['智能手机', '配件', '平板', '智能手表'], '电脑': ['笔记本', '台式机', '显示器', '外设'], '数码': ['相机', '耳机', '音箱', '存储设备'], '家居': ['家具', '家纺', '厨具', '灯具'] } records = [] for _ in range(num_records): user_id = f'U{str(np.random.randint(1, num_users+1)).zfill(6)}' behavior_time = fake.date_time_between(start_date='-90d', end_date='now') # 随机选择品类和子类 main_cat = random.choice(list(categories.keys())) sub_cat = random.choice(categories[main_cat]) # 行为类型概率分布 behavior_prob = [0.5, 0.2, 0.15, 0.1, 0.05] behavior_type = np.random.choice(behavior_types, p=behavior_prob) # 订单相关数据 order_amount = 0 if behavior_type == '购买': # 高价商品概率 if main_cat == '家电' and np.random.random() < 0.3: order_amount = np.random.uniform(3000, 20000) else: order_amount = np.random.uniform(100, 3000) # 促销活动参与 is_promotion = 1 if np.random.random() < 0.4 else 0 # 物流评分 delivery_rating = np.random.randint(3, 6) if behavior_type == '购买' else 0 records.append({ 'user_id': user_id, 'behavior_time': behavior_time, 'behavior_type': behavior_type, 'main_category': main_cat, 'sub_category': sub_cat, 'order_amount': order_amount, 'is_promotion': is_promotion, 'delivery_rating': delivery_rating }) # 创建DataFrame df = pd.DataFrame(records) # 添加未来行为标签(模拟未来3个月行为) print("添加未来行为标签...") user_purchase_future = df[df['behavior_type'] == '购买'].groupby('user_id')['order_amount'].sum().reset_index() # 修正语法错误:括号匹配 user_purchase_future['will_buy_high_end'] = np.where( (user_purchase_future['order_amount'] > 5000) & (np.random.random(len(user_purchase_future)) > 0.3), 1, 0).astype(int) # PLUS会员续费倾向 - 修正语法错误 plus_users = users[users['is_plus_member'] == 1]['user_id'].tolist() user_purchase_future['will_renew_plus'] = np.where( user_purchase_future['user_id'].isin(plus_users), np.random.choice([0, 1], len(user_purchase_future)), 0).astype(int) # 合并数据 df = pd.merge(df, users, on='user_id', how='left') df = pd.merge(df, user_purchase_future[['user_id', 'will_buy_high_end', 'will_renew_plus']], on='user_id', how='left').fillna(0) # 保存数据 os.makedirs('data', exist_ok=True) df.to_csv('data/jd_simulated_data.csv', index=False) print(f"模拟数据生成完成,共 {len(df)} 条记录,保存至 data/jd_simulated_data.csv") return df # -------------------------- # 数据预处理 - 修复版本 # -------------------------- def preprocess_data(df): """数据预处理与特征工程""" print("\n开始数据预处理与特征工程...") # 1. 数据清洗 # 过滤异常订单(金额异常) df = df[df['order_amount'] <= 50000] # 修复时间戳错误(修复未来时间戳) current_date = pd.Timestamp.now() df['behavior_time'] = pd.to_datetime(df['behavior_time']) df = df[df['behavior_time'] <= current_date] # 确保日期列转换 df['join_date'] = pd.to_datetime(df['join_date']) # 2. 特征工程 - 基础特征 # 计算用户活跃天数(最近90天) active_days = df.groupby('user_id')['behavior_time'].apply( lambda x: x.dt.date.nunique()).reset_index(name='active_days') # 促销敏感度(参与促销活动比例) promo_sensitivity = df[df['is_promotion'] == 1].groupby('user_id').size().reset_index(name='promo_count') total_actions = df.groupby('user_id').size().reset_index(name='total_actions') promo_sensitivity = pd.merge(promo_sensitivity, total_actions, on='user_id') promo_sensitivity['promo_sensitivity'] = promo_sensitivity['promo_count'] / promo_sensitivity['total_actions'] # 品类浏览集中度 category_concentration = df.groupby(['user_id', 'main_category']).size().reset_index(name='category_count') category_concentration = category_concentration.groupby('user_id')['category_count'].apply( lambda x: (x.max() / x.sum())).reset_index(name='category_concentration') # 3. 高价值客户标签定义 high_value_criteria = df.groupby('user_id').agg( total_spend=('order_amount', 'sum'), purchase_count=('behavior_type', lambda x: (x == '购买').sum()), category_count=('main_category', 'nunique'), # 修复:保留目标列 will_buy_high_end=('will_buy_high_end', 'first'), will_renew_plus=('will_renew_plus', 'first') ).reset_index() high_value_criteria['is_high_value'] = np.where( (high_value_criteria['total_spend'] > 5000) | (high_value_criteria['purchase_count'] > 8) | (high_value_criteria['category_count'] >= 3), 1, 0) # 4. 合并特征(修复:保留目标列) features = pd.merge(active_days, promo_sensitivity[['user_id', 'promo_sensitivity']], on='user_id') features = pd.merge(features, category_concentration, on='user_id') features = pd.merge(features, high_value_criteria[['user_id', 'is_high_value', 'will_buy_high_end', 'will_renew_plus']], on='user_id') # 5. 添加用户基本信息 user_base = df[['user_id', 'age', 'gender', 'city', 'is_plus_member', 'join_date']].drop_duplicates() features = pd.merge(features, user_base, on='user_id') # 6. 修复:添加时间相关特征 last_activity = df.groupby('user_id')['behavior_time'].max().reset_index(name='last_activity') features = pd.merge(features, last_activity, on='user_id') current_time = pd.Timestamp.now() features['last_activity_gap'] = (current_time - features['last_activity']).dt.days features['membership_duration'] = (current_time - features['join_date']).dt.days # 7. 添加行为统计特征 behavior_counts = pd.crosstab(df['user_id'], df['behavior_type']).reset_index() features = pd.merge(features, behavior_counts, on='user_id') # 8. 品类偏好特征 for cat in ['家电', '手机', '电脑', '数码', '家居']: cat_users = df[df['main_category'] == cat]['user_id'].unique() features[f'prefers_{cat}'] = np.where(features['user_id'].isin(cat_users), 1, 0) print(f"特征工程完成,共生成 {len(features.columns)} 个特征") # 添加数据验证 if validate_features(features): return features else: raise ValueError("特征工程验证失败!") def validate_features(features): """验证特征数据完整性""" required_columns = ['user_id', 'is_high_value', 'will_buy_high_end', 'will_renew_plus'] missing = [col for col in required_columns if col not in features.columns] if missing: print(f"错误: 缺失必要列: {missing}") return False print("特征工程验证通过,所有必要列均存在") return True # -------------------------- # 探索性数据分析 (EDA) # -------------------------- def perform_eda(df, features): """执行探索性数据分析""" print("\n开始探索性数据分析...") # 设置绘图风格 sns.set_style("whitegrid") plt.figure(figsize=(18, 12)) # 1. 用户行为类型分布 plt.subplot(2, 2, 1) behavior_counts = df['behavior_type'].value_counts() sns.barplot(x=behavior_counts.index, y=behavior_counts.values, palette="viridis") plt.title('用户行为类型分布') plt.ylabel('数量') # 2. PLUS会员与非会员客单价对比 plt.subplot(2, 2, 2) purchase_df = df[df['behavior_type'] == '购买'] sns.boxplot(x='is_plus_member', y='order_amount', data=purchase_df, palette="Set2") plt.title('PLUS会员 vs 非会员客单价对比') plt.xlabel('PLUS会员') plt.ylabel('订单金额') # 3. 物流评分与复购率关系 plt.subplot(2, 2, 3) # 计算复购率 repurchase_users = purchase_df.groupby('user_id').filter(lambda x: len(x) > 1)['user_id'].unique() purchase_df['is_repurchase'] = purchase_df['user_id'].isin(repurchase_users).astype(int) # 按物流评分分组计算复购率 delivery_repurchase = purchase_df.groupby('delivery_rating')['is_repurchase'].mean().reset_index() sns.lineplot(x='delivery_rating', y='is_repurchase', data=delivery_repurchase, marker='o', linewidth=2.5, color='darkorange') plt.title('物流评分对复购率的影响') plt.xlabel('物流评分') plt.ylabel('复购率') plt.ylim(0, 1) # 4. 高价值客户特征热力图 plt.subplot(2, 2, 4) corr_matrix = features[['active_days', 'promo_sensitivity', 'category_concentration', '购买', '加购', 'is_high_value']].corr() sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt=".2f") plt.title('行为特征相关性') plt.tight_layout() plt.savefig('results/eda_results.png', dpi=300) plt.show() # 5. 高价值客户人口统计特征 plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) sns.countplot(x='gender', hue='is_high_value', data=features, palette="Set1") plt.title('高价值客户性别分布') plt.xlabel('性别') plt.ylabel('数量') plt.subplot(1, 2, 2) sns.boxplot(x='is_high_value', y='age', data=features, palette="Set2") plt.title('高价值客户年龄分布') plt.xlabel('是否高价值客户') plt.ylabel('年龄') plt.tight_layout() plt.savefig('results/high_value_demographics.png', dpi=300) plt.show() print("EDA分析完成,结果保存至 results/ 目录") return True # -------------------------- # 预测模型构建 - 修复版本 # -------------------------- # ... 前面的代码保持不变 ... # -------------------------- # 预测模型构建 - 修复版本 # -------------------------- def build_prediction_models(features, target_column): """构建预测模型""" print(f"\n构建预测模型: {target_column}") # 1. 数据准备 # 选择特征 model_features = features.drop(['user_id', 'join_date', 'last_activity', 'will_buy_high_end', 'will_renew_plus'], axis=1, errors='ignore') # 处理分类变量 categorical_cols = ['gender', 'city'] model_features = pd.get_dummies(model_features, columns=categorical_cols, drop_first=True) # 定义目标变量 y = features[target_column] # 2. 划分训练集/测试集 X_train, X_test, y_train, y_test = train_test_split( model_features, y, test_size=0.25, random_state=42, stratify=y) # 3. 模型初始化 models = { '随机森林': RandomForestClassifier( n_estimators=150, max_depth=8, min_samples_split=10, class_weight='balanced', random_state=42 ), '逻辑回归': LogisticRegression( max_iter=1000, class_weight='balanced', penalty='l2', C=0.1, random_state=42, solver='liblinear' ) } # 4. 模型训练与评估 results = {} feature_importances = {} for name, model in models.items(): print(f"训练 {name} 模型...") start_time = time.time() model.fit(X_train, y_train) train_time = time.time() - start_time # 预测 y_pred = model.predict(X_test) # 关键指标计算 precision = precision_score(y_test, y_pred, zero_division=0) recall = recall_score(y_test, y_pred, zero_division=0) f1 = f1_score(y_test, y_pred, zero_division=0) # 尝试计算AUC,处理不支持的场景 try: y_proba = model.predict_proba(X_test)[:, 1] if hasattr(model, 'predict_proba') else [0]*len(y_test) auc = roc_auc_score(y_test, y_proba) if len(np.unique(y_test)) > 1 else 0.5 except Exception as e: print(f"警告: {name} 模型无法计算AUC: {e}") auc = 0.5 y_proba = np.zeros(len(y_test)) # 自定义加权MAE(高价商品权重更高) # 添加索引验证,确保不越界 valid_index = y_test.index.intersection(features.index) sample_weights = np.where(features.loc[valid_index, 'is_high_value'] == 1, 2.0, 1.0) # 确保长度匹配 y_proba = y_proba[:len(y_test)] mae = mean_absolute_error(y_test, y_proba, sample_weight=sample_weights) results[name] = { 'AUC': auc, '精确率': precision, '召回率': recall, 'F1分数': f1, '加权MAE': mae, '训练时间()': train_time } # 保存重要特征 - 修复缺失代码 if hasattr(model, 'feature_importances_'): feat_imp = pd.Series(model.feature_importances_, index=X_train.columns) feature_importances[name] = feat_imp # 可视化特征重要性 plt.figure(figsize=(10, 6)) feat_imp.nlargest(15).plot(kind='barh') plt.title(f'{name}特征重要性排名 (TOP 15)') plt.tight_layout() plt.savefig(f'results/{name}_{target_column}_feature_importance.png', dpi=200) plt.close() # 绘制ROC曲线 if auc > 0.5: fpr, tpr, thresholds = roc_curve(y_test, y_proba) plt.figure(figsize=(8, 6)) plt.plot(fpr, tpr, label=f'AUC = {auc:.2f}') plt.plot([0, 1], [0, 1], 'r--') plt.xlabel('假阳性率') plt.ylabel('真阳性率') plt.title(f'{name} ROC曲线') plt.legend(loc='lower right') plt.tight_layout() plt.savefig(f'results/{name}_{target_column}_roc_curve.png', dpi=200) plt.close() # 5. 打印并保存结果 print("\n模型评估结果:") results_df = pd.DataFrame(results).T print(results_df) results_df.to_csv(f'results/{target_column}_model_results.csv') return results, feature_importances # -------------------------- # 用户聚类分析 # -------------------------- def perform_clustering(features): """对用户进行聚类分析""" print("\n开始用户聚类分析...") # 选择特征 clustering_features = features.drop([ 'user_id', 'join_date', 'last_activity', 'will_buy_high_end', 'will_renew_plus' ], axis=1, errors='ignore') # 处理分类变量 categorical_cols = ['gender', 'city'] clustering_features = pd.get_dummies(clustering_features, columns=categorical_cols, drop_first=True) # 数据标准化 scaler = StandardScaler() scaled_data = scaler.fit_transform(clustering_features) # 寻找最佳聚类数量 inertias = [] for k in range(2, 11): kmeans = KMeans(n_clusters=k, random_state=42, n_init=10) kmeans.fit(scaled_data) inertias.append(kmeans.inertia_) # 绘制肘部法则图 plt.figure(figsize=(8, 5)) plt.plot(range(2, 11), inertias, marker='o') plt.title('肘部法则 - 确定最佳聚类数量') plt.xlabel('聚类数量') plt.ylabel('内平方和') plt.tight_layout() plt.savefig('results/clustering_elbow_method.png', dpi=200) plt.show() # 使用最佳聚类数量进行聚类 optimal_k = 5 # 根据肘部法则选择 kmeans = KMeans(n_clusters=optimal_k, random_state=42, n_init=10) features['cluster'] = kmeans.fit_predict(scaled_data) # 分析聚类特征 cluster_profiles = features.groupby('cluster').mean(numeric_only=True).reset_index() # 可视化聚类中心特征 cluster_features = [ 'active_days', 'promo_sensitivity', 'category_concentration', '购买', '加购', 'membership_duration' ] plt.figure(figsize=(12, 8)) for i, feature in enumerate(cluster_features, 1): plt.subplot(2, 3, i) sns.barplot(x='cluster', y=feature, data=features, ci=None) plt.title(f'{feature} 按集群分布') plt.tight_layout() plt.savefig('results/cluster_characteristics.png', dpi=300) plt.show() # 保存聚类结果 features[['user_id', 'cluster']].to_csv('results/user_clusters.csv', index=False) print(f"聚类分析完成,用户被分为 {optimal_k} 个不同群体") return features # -------------------------- # 主执行流程 # -------------------------- if __name__ == "__main__": # 创建结果目录 os.makedirs('data', exist_ok=True) os.makedirs('results', exist_ok=True) # 生成模拟数据 if not os.path.exists('data/jd_simulated_data.csv'): df = generate_jd_simulation_data() else: # 避免日期转换问题 df = pd.read_csv('data/jd_simulated_data.csv') # 分别转换日期列 date_cols = ['behavior_time', 'join_date'] for col in date_cols: if col in df.columns: df[col] = pd.to_datetime(df[col]) print("加载现有模拟数据...") # 预处理与特征工程 features = preprocess_data(df) # 探索性数据分析 perform_eda(df, features) # 构建预测模型 model_results = {} feature_importances = {} # 1. 预测高价值客户 high_value_results, high_value_models = build_prediction_models(features, 'is_high_value') model_results['is_high_value'] = high_value_results # 2. 预测购买高端产品意愿 high_end_results, high_end_models = build_prediction_models(features, 'will_buy_high_end') model_results['will_buy_high_end'] = high_end_results # 3. 预测PLUS会员续费意愿 renew_plus_results, renew_plus_models = build_prediction_models(features, 'will_renew_plus') model_results['will_renew_plus'] = renew_plus_results # 用户聚类分析 clustered_features = perform_clustering(features) print("\n⭐️ 系统执行完成!模型结果已保存至 results/ 目录") 这个数据模拟的太完美了,能帮我模拟的数据实际一点吗,结果不要太准确
最新发布
06-05
<think>我们注意到用户希望模拟的数据更实际一点,结果不要太准确。这意味着我们需要在数据生成过程中引入更多的噪声和随机性,以模拟真实世界数据的不完美性。具体调整方向:1.在定义高价值客户时,加入更多的随机因素,降低特征与目标变量之间的直接关联性。2.在生成目标变量(如未来购买高端产品、续费PLUS会员)时,使用更弱的关联特征,并增加随机性。3.在生成用户行为时,使用更均匀的概率分布,避免某些行为过于集中。4.加入一些异常值和缺失值。我们将对以下函数进行调整:-generate_jd_simulation_data:调整目标变量的生成逻辑,引入更多随机性。-preprocess_data:在特征工程步骤中,可能因为数据生成逻辑的改变而调整。具体修改点:1.调整高价值客户标签的生成:减少使用特征工程中使用的特征(如总消费金额、购买次数等)作为直接标准,而是加入随机因素和间接特征。2.在生成未来行为标签时,降低条件概率(例如,原本在满足条件时有70%的概率被标记为1,现在可以降低到50%或更低)。3.在行为类型概率分布上,降低浏览行为的概率,提高其他行为的概率,使其更均匀(但依然保持浏览占主导)。4.引入缺失值:随机选择一部分记录,将某些特征设置为NaN(比如物流评分、订单金额等)。5.引入异常值:在订单金额中,随机插入一些极大值(如10万以上)和负值(但随后在数据清洗中可能会被过滤,以模拟真实数据清洗过程)。修改步骤:1.修改generate_jd_simulation_data函数中的目标变量生成逻辑。2.在生成订单金额时,有极小概率生成异常值(大额或负值)。3.在生成的数据中随机插入缺失值(NaN)。4.调整行为类型的概率分布,使其更均匀。我们将逐步修改代码:</think> 好的,我来帮你改进模拟数据的真实性和预测准确性。以下是调整后的代码,主要从数据分布、特征关联、随机性和数据噪声四个方面进行优化: ```python # -*- coding: utf-8 -*- """ 京东高价值客户识别与全链路行为预测系统 - 增强现实版 数据来源:京东公开数据(带噪声模拟生成) """ # ... 前面的导入语句保持不变 ... # -------------------------- # 数据爬取与模拟生成(增强现实版) # -------------------------- def generate_more_realistic_jd_data(num_users=5000, num_records=50000): """ 模拟生成更贴近现实的京东用户行为数据 """ print("开始生成更现实的京东模拟数据...") fake = Faker('zh_CN') np.random.seed(42) # 创建更符合现实的人口分布 # 年龄分布更接近真实情况 ages = np.concatenate([ np.random.normal(25, 3, int(num_users*0.3)), # 年轻用户 np.random.normal(35, 5, int(num_users*0.4)), # 主力用户 np.random.normal(50, 7, int(num_users*0.3)) # 年长用户 ]) ages = np.clip(ages, 18, 65).astype(int) # 城市分布更符合中国实际 tier1_cities = ['北京', '上海', '广州', '深圳'] tier2_cities = ['杭州', '南京', '成都', '武汉', '重庆', '天津'] other_cities = [fake.city() for _ in range(100)] city_choice = np.random.choice( ['tier1', 'tier2', 'other'], num_users, p=[0.15, 0.35, 0.5] ) cities = [] for choice in city_choice: if choice == 'tier1': cities.append(np.random.choice(tier1_cities)) elif choice == 'tier2': cities.append(np.random.choice(tier2_cities)) else: cities.append(np.random.choice(other_cities)) # 创建用户基础数据 users = pd.DataFrame({ 'user_id': [f'U{str(i).zfill(6)}' for i in range(1, num_users+1)], 'age': ages, 'gender': np.random.choice(['男', '女'], num_users, p=[0.52, 0.48]), 'city': cities, # PLUS会员概率与城市等级挂钩 'is_plus_member': np.where( city_choice == 'tier1', np.random.choice([0, 1], num_users, p=[0.45, 0.55]), np.random.choice([0, 1], num_users, p=[0.75, 0.25]) ), 'join_date': [fake.date_between(start_date='-3y', end_date='today') for _ in range(num_users)] }) # 创建行为数据 - 增加更多随机性和噪声 behavior_types = ['浏览', '加购', '购买', '评价', '收藏'] # 更复杂的品类分布 categories = { '家电': {'概率': 0.15, '子类': ['冰箱', '洗衣机', '空调', '电视', '微波炉'], '高价概率': 0.4}, '手机': {'概率': 0.25, '子类': ['智能手机', '配件', '平板', '智能手表'], '高价概率': 0.3}, '电脑': {'概率': 0.10, '子类': ['笔记本', '台式机', '显示器', '外设'], '高价概率': 0.5}, '数码': {'概率': 0.20, '子类': ['相机', '耳机', '音箱', '存储设备'], '高价概率': 0.2}, '家居': {'概率': 0.30, '子类': ['家具', '家纺', '厨具', '灯具'], '高价概率': 0.1} } # 增强现实:增加伪相关性和噪声 records = [] for _ in range(num_records): user_idx = np.random.randint(0, num_users) user_id = f'U{str(user_idx+1).zfill(6)}' user = users.iloc[user_idx] # 时间分布:工作日晚上和周末是高峰期 is_weekend = np.random.random() < 0.4 if is_weekend: behavior_time = fake.date_time_between(start_date='-90d', end_date='now', hour=np.random.choice([10, 11, 14, 15, 16, 20, 21])) else: behavior_time = fake.date_time_between(start_date='-90d', end_date='now', hour=np.random.choice([12, 13, 19, 20, 21, 22])) # 品类选择增加年龄偏好逻辑 age_group = "young" if user['age'] < 30 else "middle" if user['age'] < 50 else "senior" if age_group == "young": adj_categories = {k: v['概率'] * [1.0, 1.4, 0.8, 1.2, 0.6][i] for i, (k, v) in enumerate(categories.items())} elif age_group == "middle": adj_categories = {k: v['概率'] * [1.2, 1.1, 1.3, 0.9, 1.0][i] for i, (k, v) in enumerate(categories.items())} else: adj_categories = {k: v['概率'] * [0.8, 0.7, 0.5, 0.6, 1.5][i] for i, (k, v) in enumerate(categories.items())} # 标准化概率 total_prob = sum(adj_categories.values()) main_cat = np.random.choice( list(adj_categories.keys()), p=[v/total_prob for v in adj_categories.values()] ) sub_cat = np.random.choice(categories[main_cat]['子类']) # 行为类型:更复杂的概率分布 behavior_probs = [0.45, 0.15, 0.15, 0.10, 0.15] # 基础概率 # 会员用户更倾向于购买 if user['is_plus_member']: behavior_probs = [p * mult for p, mult in zip(behavior_probs, [0.9, 1.0, 1.4, 1.1, 1.2])] # 周末购买意愿更强 if is_weekend: behavior_probs = [p * mult for p, mult in zip(behavior_probs, [0.8, 1.1, 1.3, 1.0, 1.1])] # 归一化概率 behavior_probs = [p/sum(behavior_probs) for p in behavior_probs] behavior_type = np.random.choice(behavior_types, p=behavior_probs) # 订单金额:更现实的分布(对数正态分布) base_amount = 0 if behavior_type == '购买': # 基于品类的价格分布 if np.random.random() < categories[main_cat]['高价概率']: # 高价商品(对数正态分布) base_amount = np.random.lognormal(mean=8.5, sigma=0.7) else: # 普通商品(对数正态分布) base_amount = np.random.lognormal(mean=6.0, sigma=0.5) # 添加城市和会员等级的影响 city_multiplier = 1.5 if user['city'] in tier1_cities else 1.0 member_multiplier = 1.2 if user['is_plus_member'] else 1.0 order_amount = base_amount * city_multiplier * member_multiplier # 增加30%的概率出现异常值(模拟输入错误或特殊交易) if np.random.random() < 0.3: order_amount *= np.random.uniform(0.7, 1.3) # ±30%的波动 else: order_amount = 0 # 促销活动参与(与城市等级、年龄有关) promo_prob = 0.35 if user['city'] in tier1_cities: promo_prob *= 0.9 # 一线城市用户对促销敏感度略低 elif user['age'] > 45: promo_prob *= 1.3 # 年长用户更关注促销 is_promotion = 1 if np.random.random() < promo_prob else 0 # 物流评分(增加非购买行为的缺失值) if behavior_type == '购买': # 基础评分(二项分布) base_rating = np.random.binomial(4, 0.85) + 1 # 1-5星的离散值 # 城市影响(一线城市物流更好) city_bonus = 0.3 if user['city'] in tier1_cities else 0 delivery_rating = min(5, max(1, base_rating + city_bonus + np.random.normal(0, 0.2))) else: delivery_rating = np.nan # 非购买行为无物流评分 records.append({ 'user_id': user_id, 'behavior_time': behavior_time, 'behavior_type': behavior_type, 'main_category': main_cat, 'sub_category': sub_cat, 'order_amount': order_amount, 'is_promotion': is_promotion, 'delivery_rating': delivery_rating }) # 创建DataFrame df = pd.DataFrame(records) # 添加更多噪音:随机删除5%的行为类型和品类信息 mask = np.random.random(len(df)) < 0.05 df.loc[mask, 'behavior_type'] = np.nan mask = np.random.random(len(df)) < 0.03 df.loc[mask, ['main_category', 'sub_category']] = np.nan # 添加未来行为标签(减弱可预测性) print("添加带噪声的未来行为标签...") # 1. 购买高端产品的意愿(弱相关) user_high_end_prob = [] for user_id, group in df.groupby('user_id'): # 基础概率(用户消费能力相关) base_prob = min(0.7, np.log1p(group['order_amount'].sum()) / 15) # 添加随机因素(50%来自可解释因素,50%来自随机噪声) final_prob = (base_prob * 0.5) + (np.random.random() * 0.5) user_high_end_prob.append((user_id, int(final_prob > 0.4))) user_high_end = pd.DataFrame(user_high_end_prob, columns=['user_id', 'will_buy_high_end']) # 2. PLUS会员续费倾向(弱相关) plus_renew_prob = [] for user_id, group in users[users['is_plus_member'] == 1].groupby('user_id'): # 与活跃度弱相关 base_prob = min(0.8, len(df[df['user_id'] == user_id]) / 100) # 添加随机因素 final_prob = (base_prob * 0.4) + (np.random.random() * 0.6) plus_renew_prob.append((user_id, int(final_prob > 0.5))) plus_renew = pd.DataFrame(plus_renew_prob, columns=['user_id', 'will_renew_plus']) # 合并数据 df = pd.merge(df, users, on='user_id', how='left') df = pd.merge(df, user_high_end, on='user_id', how='left') df = pd.merge(df, plus_renew, on='user_id', how='left').fillna(0) # 保存数据 os.makedirs('data', exist_ok=True) df.to_csv('data/jd_realistic_data.csv', index=False) print(f"更现实的模拟数据生成完成,共 {len(df)} 条记录,保存至 data/jd_realistic_data.csv") return df # -------------------------- # 数据预处理 - 增强现实版 # -------------------------- def realistic_preprocess_data(df): """数据预处理与特征工程(更贴近现实场景)""" print("\n开始数据处理(带噪声)...") # 1. 数据清洗 # 过滤极端异常订单(金额>100万)但保留一些合法异常值 df = df[(df['order_amount'] <= 1000000) & (df['order_amount'] >= 0)] # 处理缺失值 df['behavior_type'].fillna('浏览', inplace=True) # 最常见的行为 df['main_category'].fillna('家居', inplace=True) # 最常见品类 df['sub_category'] = df.apply( lambda x: np.random.choice(categories[x['main_category']]['子类']) if pd.isna(x['sub_category']) else x['sub_category'], axis=1 ) # 物流评分插补 df['delivery_rating'].fillna( df.groupby('city')['delivery_rating'].transform('median'), inplace=True ) df['delivery_rating'].fillna(4.0, inplace=True) # 中位数值填充 # 2. 特征工程(增强现实特性) # 计算用户活跃天数(增加非线性) active_days = df.groupby('user_id')['behavior_time'].apply( lambda x: np.log1p(x.dt.date.nunique()) # 对数变换更符合真实分布 ).reset_index(name='log_active_days') # 促销参与度(带权重) promo_sensitivity = df.groupby('user_id').apply( lambda x: (x['is_promotion'] * (x['order_amount'] > 0).astype(int)).mean() ).reset_index(name='promo_sensitivity') # 品类偏好(考虑时序变化) df['month'] = df['behavior_time'].dt.month seasonal_prefs = df.groupby(['user_id', 'month', 'main_category']).size().unstack(fill_value=0) seasonal_prefs = seasonal_prefs.groupby('user_id').mean() # 平均月度偏好 # 3. 高价值客户标签(更模糊的定义) user_stats = df.groupby('user_id').agg( total_spend=('order_amount', 'sum'), purchase_freq=('behavior_type', lambda x: (x == '购买').sum() / len(x)), avg_order_value=('order_amount', 'mean'), cat_diversity=('main_category', 'nunique') ).reset_index() # 更复杂的模糊逻辑(而不是简单阈值) user_stats['spend_score'] = pd.cut( user_stats['total_spend'], bins=[0, 1000, 5000, 20000, float('inf')], labels=[1, 2, 3, 4], include_lowest=True ) user_stats['freq_score'] = pd.cut( user_stats['purchase_freq'], bins=[0, 0.1, 0.25, 0.5, float('inf')], labels=[1, 2, 3, 4], include_lowest=True ) # 综合评分(带随机扰动) user_stats['value_score'] = ( user_stats['spend_score'].astype(int) * 0.4 + user_stats['freq_score'].astype(int) * 0.3 + user_stats['cat_diversity'] * 0.2 + np.random.normal(0, 0.1, len(user_stats)) # 添加噪声 ) # 前30%定义为高价值客户(而不是固定阈值) threshold = user_stats['value_score'].quantile(0.7) user_stats['is_high_value'] = (user_stats['value_score'] > threshold).astype(int) # 4. 合并特征(保留原始特征) features = pd.merge(active_days, promo_sensitivity, on='user_id') features = pd.merge(features, user_stats[['user_id', 'is_high_value']], on='user_id') features = pd.merge(features, seasonal_prefs.reset_index(), on='user_id', how='left').fillna(0) # 添加用户基础信息 user_base = df[['user_id', 'age', 'gender', 'city', 'is_plus_member', 'join_date']].drop_duplicates() features = pd.merge(features, user_base, on='user_id') # 添加时间相关特征 last_activity = df.groupby('user_id')['behavior_time'].max().reset_index(name='last_activity') features = pd.merge(features, last_activity, on='user_id') current_time = pd.Timestamp.now() features['days_since_last_activity'] = (current_time - features['last_activity']).dt.days print(f"特征工程完成(带噪声),共生成 {len(features.columns)} 个特征") return features # ... 其他函数(EDA、模型构建等)保持不变,但调用上述新函数 ... ``` ### 主要改进点: 1. **更真实的用户分布**: - 年龄采用三峰分布模拟实际人群结构 - 城市层级划分(一线/二线/其他),影响消费行为和会员概率 - 会员
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值