数据处理常用到的一些方法/drop_duplicates()/映射map()/replace()/rename()/分箱/过滤异常值/随机抽样take()/random.permutation()

本文深入探讨了Pandas库在数据处理方面的高级应用,包括如何使用drop_duplicates()函数去除重复数据,利用replace()、map()和rename()函数进行数据映射和索引替换,异常值检测与过滤的方法,以及排序和随机抽样的技巧。

1、删除重复元素
使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import matplotlib.pyplot as plt
%matplotlib inline


创建数据集:

# color 0 :red;1:green;2:blue
df = DataFrame({'color':np.random.randint(0,3,size = 300),'num':np.random.randint(0,5,size = 300)})
df


 
#或者:

b=np.random.choice(['B','M'],size=(100,2))
b1=DataFrame(b,columns=['True','Predict'])
b1


# 计算True的总个数,即计算重复的总行数
df.duplicated().sum()
Out: 285
使用drop_duplicates()函数删除重复的行【inplace=True则会修改原数组】
df.drop_duplicates()


查看图片中的重复元素
img = plt.imread('./芝麻.jpg')
img.shape
Out: (662, 1000, 3)
 
# 这张图片总共有多少个像素呢?
# (红,绿,蓝)
662*1000
Out: 662000
 
# numpy没有去重的方法
img2 = img.reshape(-1,3)
img2
# img2 必须是转化成n行n列,比如reshape(-1,3)
df = DataFrame(img2,columns=['red','green','blue'])
df

# 总数据662000
# 非重复的像素,71526个  ,inplace=True则能修改原数组


 Pandas之drop_duplicates:去除重复项

方法
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
1
参数
这个drop_duplicate方法是对DataFrame格式的数据,去除特定列下面的重复行。返回DataFrame格式的数据。

方法
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
1
参数
这个drop_duplicate方法是对DataFrame格式的数据,去除特定列下面的重复行。返回DataFrame格式的数据。

subset : column label or sequence of labels, optional 
用来指定特定的列,默认所有列
keep : {‘first’, ‘last’, False}, default ‘first’ 
删除重复项并保留第一次出现的项
inplace : boolean, default False 
是直接在原来数据上修改还是保留一个副本


df.drop_duplicates().shape
Out: (71526, 3)
【注意】如果使用pd.concat([df1,df2],axis = 1)生成新的DataFrame,新的df中columns相同,使用duplicate()和drop_duplicates()都会出问题

 

2. 映射
映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定

需要使用字典:

map = { 'label1':'value1', 'label2':'value2', ... }

包含三种操作:

replace()函数:替换元素
最重要:map()函数:新建一列
rename()函数:替换索引
 
1) replace()函数:替换元素
使用replace()函数,对values进行替换操作

定义数据集
df = DataFrame({'color':np.random.randint(0,3,size = 300),'num':np.random.randint(10,30,size = 300)})
df


首先定义一个字典
m = {0:'red',1:'green',2:'blue'}
调用.replace()
# replace方法,可将DataFrame中所有满足条件的数据,进行替换
df.replace(m)


replace还经常用来替换NaN元素
# 字典的key类型要一致
m = {0:'red',1:'green',2:'blue',1024:'purple',2048:'cyan'}
 
# 字典中映射关系,键值对,去DataFrame找数据,找到了就替换,没有找到,也不会报错
df.replace(m)
使用正则匹配替换:
数据集 data1 ——> 杂质:-数字\t

法①:遍历—> re.sub

import re
data1[0].map(lambda x: re.sub('.*\d+\\t','',x))
法②【一定要加上.str才能替换】:data1[0].str.replace

pd.DataFrame(data1[0].str.replace('.*?\d+?\\t ', '')) #用正则表达式修改数据
 

2) map()函数:新建一列
使用map()函数,由已有的列生成一个新列

适合处理某一单独的列。

仍然是新建一个字典

map()函数中可以使用lambda函数

transform()和map()类似

使用map()函数新建一个新列

 

新建数据集
df = DataFrame(np.random.randint(0,150,size = (10,3)),
    columns=['Python','Math','En'],index=list('ABCDEFGHJK'))
df
map映射简单lambda函数

# df['Python']  10 个数据 迭代器
df['Java'] = df['Python'].map(lambda x : 2*x - 100)
df


f = lambda x : x*2 - 100
type(f)
Out: function
 
def fun(x):
    x*2 - 100    
type(fun)
Out: function
定义一个函数level,带入map函数:
def convert(x):
    if x >=130:
        return '优秀'
    elif x <130 and x >=100:
        return '良好'
    elif x < 100 and x >=80:
        return '中等'
    elif x < 80 and x >=60:
        return '及格'
    else:
        return '不及格'
 
df['Level'] = df['Python'].map(convert)
df


 

给某一列都加上某个数:法① df['Python'] += 10
# Python 这一列,老师出考题的时候,有一道题出错了,每个人Python加10分
df['Python'] += 10
df




给某一列都加上某个数:法② map(lambda x : x+10)
# map 这个方法,可以修改当前的列
df['Python'] = df['Python'].map(lambda x :x + 10)
df
分箱操作:
分箱、分块、分类——》

# 分箱,分类
# 葡萄品质0~10 
# 0~4 low
# 5~7 median
# 8~10 high

# 分箱,分类
# 葡萄品质0~10 
# 0~4 low
# 5~7 median
# 8~10 high
 
# 0 ~ 10 信用
# 0~3 low
# 4~ 6 median
# 7~10 high
 
# 根据这个人手机产生数据
def convert(x):
    if x >=140:
        return 150
    elif x < 140 and x >= 100:
        return 125
    elif x < 100 and x>=60:
        return 80
    else:
        return 0
 
df['Python'] = df['Python'].map(convert)
df


 

3) rename()函数:替换索引
新建数据集:
df = DataFrame(np.random.randint(0,150,size = (4,3)))
df


仍然是新建一个字典,使用rename()函数替换行索引
# 更改列标题   【axis = 0 行】
m = {0:'张三',1:'李四',2:'王五',3:'小刘'}
df.rename(m,axis = 0,inplace=True)
 
# 更改行标题
m = {0:'Python',1:'Math',2:'En'}
df.rename(m,axis = 1,inplace=True)
df



3. 异常值检测和过滤

使用describe()函数查看每一列的描述性统计量

新建数据集
df = DataFrame(np.random.randn(10000,3),columns=list('ABC'))
df


检测异常值:① 求出每一列均值;② 异常值判断条件:大于5倍均值
# 过滤条件,大于5倍平均,异常
# 均值0.79,则大于3.95为异常值
df.abs().mean()
Out: 
A    0.798357
B    0.793909
C    0.789348
dtype: float64
 
# 找出各个属性的异常值
cond = df.abs() > 3.95
cond.sum()
Out:
A    2
B    2
C    0
dtype: int64
 
# 异常值总和
(cond.sum()).sum()
 
# 异常值总行数
cond.any(axis = 1).sum() 
Out: 4
 
# 以DataFrame形式展示存在异常值的行数
df[cond.any(axis = 1)]


展示满足要求的数据:

# 满足要求的数据
cond = df.abs() <=3.95
cond = cond.all(axis = 1)
df[cond]


 

使用std()函数可以求得DataFrame对象每一列的标准差;
根据每一列的标准差,对DataFrame元素进行过滤;
借助any()函数, 测试是否有True,有一个或以上返回True,反之返回False;
对每一列应用筛选条件,去除标准差太大的数据
 

3原则:如果数据服从正态分布,在3原则下,异常值被定义为一组测定值中与平均值的偏差超过3倍标准差的值。在正态分布的假设下,距离平均值3之外的值出现的概率为P(|x-|>3)≤0.003,属于极个别的小概率事件。

#平均值上下三倍标准差之间属于正常点
std=df.abs().std()
std
Out:
A    0.607076
B    0.598781
C    0.594652
dtype: float64
 
mean=df.abs().mean()
mean
Out:
A    0.798357
B    0.793909
C    0.789348
dtype: float64
 
low=mean-3*std
high=mean+3*std
display(low.mean(),high.mean())
Out:
-1.0066372280404017
2.5943795581659246
 
# 异常值 位于小于mean-3*std or 大于mean+3*std
low1=df.abs()<low.mean()
high1=df.abs() > high.mean()
low_high1=np.logical_or(low1,high1)
low_high1
 
# 显示异常值个数
df[low_high1.any(axis=1)].shape
Out: (259, 3)
# 过滤掉正常值,显示异常值
df[low_high1.any(axis=1)]
 
#平均值上下三倍标准差之间属于正常点
lowcond=df.abs()>low.mean()
highcond=df.abs() < high.mean()
low_high=np.logical_and(lowcond,highcond)
low_high
 
# 过滤异常值,满足条件 df.mean()-3*df.std() ~ df.mean()+3*df.std() 
df[low_high.all(axis=1)].shape
Out: (9741, 3)
 
df.shape
Out:(10000, 3)
259+9741=10000
新建数据集:身高、体重
手动创建异常值
判定异常值范围
过滤异常值
df =DataFrame(
    {'height':np.random.randint(150,200,1000),
    'weight':np.random.randint(50,90,size = 1000)})
df
 
# 创造异常值
# 每隔10个数据加一个300,比如第10个原本63,处理后变363,第20,30..一样
df['weight'][::10] +300
df
 
# 判定异常值范围:
# 体重的异常值:>300公斤
cond = df['weight'] < 300
 
# 异常值筛选:给定条件(数据不同,条件不一样,根据数据属性来做选择)
df[cond]


 

4. 排序及打乱下标随机排序
使用.take()函数排序,可以借助np.random.permutation()函数随机排序

df.take([100,300,210])


# 产生5个0-4的随机数
np.random.permutation(5)
Out: array([2, 0, 4, 3, 1])
 
# 产生1000个0-999的随机数
index = np.random.permutation(1000)
index
type(index)
Out: numpy.ndarray
 
# 使用产生的随机数作为下标排序显示数据
df.take(index)
另一种产生n个 0 ~ n-1 的随机数
# 产生1000个从0~999的升序数列
index = np.arange(1000)
index
 
# 打乱0~999的顺序数列
np.random.shuffle(index)
index
display(type(index),index)
Out: numpy.ndarray
 
# 使用随机打乱的数列作为下标显示数据
df.take(index)
随机抽样
当DataFrame规模足够大时,直接使用np.random.randint()函数,就配合take()函数实现随机抽样

df = DataFrame(np.random.randn(10000,3),columns=list('ABC'))
df
 
df.size
Out: 30000


ss=np.random.randint(0,10000,size = 100)
ss
Out:
array([4065, 9998, 4088, 2039, 4184, 1807, 1325, 1569, 6657, 2974, 3211,
       2982, 8154, 7668, 6738, 7486, 4362,  105, 6373, 3119, 1261, 1648,
       2962, 7112, 2243, 6014, 2211, 6357, 2032, 1761, 7664, 6734, 1882,
       6126, 8942, 4872, 8935, 9207, 4533, 4558, 9922, 5127, 9340, 5148,
        640, 8374, 5681, 1160,  325, 2469, 9823, 7114, 8228, 5019, 4217,
       2901, 8420, 4888, 4274, 6595, 2289, 1446, 8035,  958,  736, 7005,
       5490, 2752, 3260, 9686, 5241, 3165, 8381, 7885, 4582, 8015, 7215,
       8430, 8921, 4957, 2419, 7912, 9510, 1614, 1102, 3070, 2390,  228,
       3588,  829, 6808, 4883,  349, 1869, 2073, 1992, 9280, 1085, 5495,
       5396])
 
DataFrame(ss)[0].unique().size
Out: 100
 
# 可以直接使用random.randint 产生的数据来做下标随机抽取数据
df.take(np.random.randint(0,10000,size = 100))
 
 

请帮我检查优化代码,并完整输出结果:import pandas as pd import numpy as np import lightgbm as lgb from lightgbm import early_stopping, log_evaluation from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score import chardet def detect_encoding(file_path): with open(file_path, &#39;rb&#39;) as f: result = chardet.detect(f.read(10000)) return result[&#39;encoding&#39;], result[&#39;confidence&#39;] def load_all_data(days=32): see_list, click_list, play_list = [], [], [] dtypes = {&#39;did&#39;: &#39;category&#39;, &#39;vid&#39;: &#39;category&#39;} for i in range(1, days + 1): day = f"{i:02d}" # 加载 see 数据 see = pd.read_csv(f&#39;see_{day}.csv&#39;, encoding=&#39;latin1&#39;, dtype=dtypes) if &#39;did&#39; not in see.columns or &#39;vid&#39; not in see.columns: raise ValueError(f"see_{day}.csv 缺少必要字段") see[&#39;day&#39;] = day see_list.append(see) # 加载 click 数据 click = pd.read_csv( f&#39;click_{day}.csv&#39;, encoding=&#39;ISO-8859-1&#39;, on_bad_lines=&#39;skip&#39;, dtype=dtypes ) if &#39;click_time&#39; not in click.columns: raise ValueError(f"click_{day}.csv 缺少 click_time 字段") click[&#39;date&#39;] = pd.to_datetime(click[&#39;click_time&#39;]).dt.date click_list.append(click[[&#39;did&#39;, &#39;vid&#39;, &#39;date&#39;]]) # 加载 play 数据 play = pd.read_csv( f&#39;playplus_{day}.csv&#39;, engine=&#39;python&#39;, encoding_errors=&#39;ignore&#39;, dtype=dtypes ) if &#39;play_time&#39; not in play.columns: raise ValueError(f"playplus_{day}.csv 缺少 play_time 字段") play_list.append(play[[&#39;did&#39;, &#39;vid&#39;, &#39;play_time&#39;]]) all_see = pd.concat(see_list).drop_duplicates([&#39;did&#39;, &#39;vid&#39;]) all_click = pd.concat(click_list).drop_duplicates([&#39;did&#39;, &#39;vid&#39;]) all_play = pd.concat(play_list).groupby([&#39;did&#39;, &#39;vid&#39;], observed=True).sum().reset_index() return all_see, all_click, all_play def prepare_samples(all_see, all_click, all_play): video_info = pd.read_csv(&#39;vid_info_table.csv&#39;, encoding=&#39;gbk&#39;, dtype={&#39;vid&#39;: &#39;category&#39;}) # 合并基础数据 samples = all_see.merge(all_play, on=[&#39;did&#39;, &#39;vid&#39;], how=&#39;left&#39;).fillna({&#39;play_time&#39;: 0}) samples = samples.merge(video_info, on=&#39;vid&#39;, how=&#39;left&#39;) # 计算完成率(仅用于分析,不用于预测) samples[&#39;completion_rate&#39;] = (samples[&#39;play_time&#39;] / samples[&#39;item_duration&#39;]).clip(0, 1).astype(np.float32) # 点击标记 click_flag = all_click.groupby([&#39;did&#39;, &#39;vid&#39;]).size().reset_index(name=&#39;clicked&#39;) click_flag[&#39;clicked&#39;] = 1 samples = samples.merge(click_flag, on=[&#39;did&#39;, &#39;vid&#39;], how=&#39;left&#39;).fillna({&#39;clicked&#39;: 0}) samples[&#39;clicked&#39;] = samples[&#39;clicked&#39;].astype(np.int8) # 标签定义 samples[&#39;label&#39;] = np.select( [ (samples[&#39;completion_rate&#39;] > 0.9), (samples[&#39;clicked&#39;] == 1) ], [2, 1], # 2=完成, 1=点击 default=0 # 0=曝光未点击 ) # 二分类目标(点击或完成为正类) samples[&#39;binary_label&#39;] = samples[&#39;label&#39;].apply(lambda x: 1 if x >= 1 else 0).astype(int) # 计算用户点击率(修正版) user_exposure = all_see.groupby(&#39;did&#39;).size().rename(&#39;exposure_count&#39;) user_click_count = all_click.groupby(&#39;did&#39;).size().rename(&#39;click_count&#39;) user_click_rate = (user_click_count / user_exposure).fillna(0).astype(np.float32) # 视频流行度 video_popularity = all_click.groupby(&#39;vid&#39;).size().rename(&#39;video_popularity&#39;) # 映射特征 samples[&#39;user_click_rate&#39;] = samples[&#39;did&#39;].map(user_click_rate).fillna(0) samples[&#39;video_popularity&#39;] = samples[&#39;vid&#39;].map(video_popularity).fillna(0) # 修复:保存唯一用户点击率(关键修复点) user_click_rate_df = pd.DataFrame({ &#39;did&#39;: user_click_rate.index, &#39;user_click_rate&#39;: user_click_rate.values }).drop_duplicates(&#39;did&#39;) # 修复:保存唯一视频流行度 video_popularity_df = pd.DataFrame({ &#39;vid&#39;: video_popularity.index, &#39;video_popularity&#39;: video_popularity.values }).drop_duplicates(&#39;vid&#39;) # 保存特征 user_click_rate_df.to_csv(&#39;user_click_rate.csv&#39;, index=False) video_popularity_df.to_csv(&#39;video_popularity.csv&#39;, index=False) return samples, user_click_rate, video_popularity def train_model(samples): # 仅使用可复现的特征 features = [&#39;user_click_rate&#39;, &#39;video_popularity&#39;] X = samples[features] y = samples[&#39;binary_label&#39;] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) lgb_train = lgb.Dataset(X_train, y_train) lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train) params = { &#39;boosting_type&#39;: &#39;gbdt&#39;, &#39;objective&#39;: &#39;binary&#39;, &#39;metric&#39;: &#39;auc&#39;, &#39;num_leaves&#39;: 31, &#39;learning_rate&#39;: 0.05, &#39;feature_fraction&#39;: 0.9, &#39;bagging_fraction&#39;: 0.8, &#39;bagging_freq&#39;: 5, &#39;verbose&#39;: -1 } model = lgb.train( params, lgb_train, num_boost_round=100, valid_sets=[lgb_train, lgb_eval], callbacks=[ early_stopping(stopping_rounds=20), log_evaluation(period=50) ] ) y_pred = model.predict(X_test) auc_score = roc_auc_score(y_test, y_pred) print(f"Validation AUC: {auc_score:.4f}") return model, features, auc_score def predict_new_data(model, feature_columns, test_file): # 读取测试数据 test_data = pd.read_csv(test_file, dtype={&#39;did&#39;: &#39;category&#39;, &#39;vid&#39;: &#39;category&#39;}) # 修复:正确读取特征映射 user_click_rate_df = pd.read_csv(&#39;user_click_rate.csv&#39;) video_popularity_df = pd.read_csv(&#39;video_popularity.csv&#39;) # 计算全局均值用于填充新用户/新视频 global_user_rate = user_click_rate_df[&#39;user_click_rate&#39;].mean() global_video_pop = video_popularity_df[&#39;video_popularity&#39;].mean() # 创建映射字典 user_click_map = user_click_rate_df.set_index(&#39;did&#39;)[&#39;user_click_rate&#39;].to_dict() video_pop_map = video_popularity_df.set_index(&#39;vid&#39;)[&#39;video_popularity&#39;].to_dict() # 映射特征 test_data[&#39;user_click_rate&#39;] = test_data[&#39;did&#39;].map(user_click_map).fillna(global_user_rate) test_data[&#39;video_popularity&#39;] = test_data[&#39;vid&#39;].map(video_pop_map).fillna(global_video_pop) # 预测 test_data[&#39;click_prob&#39;] = model.predict(test_data[feature_columns]) # 生成结果 top_predictions = test_data.sort_values(&#39;click_prob&#39;, ascending=False).groupby(&#39;did&#39;).head(1) result = top_predictions[[&#39;did&#39;, &#39;vid&#39;, &#39;click_prob&#39;]].copy() result.columns = [&#39;did&#39;, &#39;vid&#39;, &#39;click_prob&#39;] result.to_csv(&#39;prediction_result.csv&#39;, index=False) return result if __name__ == &#39;__main__&#39;: encoding, confidence = detect_encoding(&#39;see_01.csv&#39;) print(f"编码: {encoding}, 置信度: {confidence:.2f}") all_see, all_click, all_play = load_all_data() samples, _, _ = prepare_samples(all_see, all_click, all_play) model, features, auc_score = train_model(samples) result = predict_new_data(model, features, &#39;testA_did_show.csv&#39;)
最新发布
07-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值