一.对train.csv中数据的预处理
在机器学习任务中,对数据的分析是首要的
uuid为样本唯一标识,eid为访问行为ID,udmap为行为属性,其中的key1到key9表示不同的行为属性,如项目名、项目id等相关字段,common_ts为应用访问记录发生时间(毫秒时间戳),其余字段x1至x8为用户相关的属性,为匿名处理字段。target字段为预测目标,即是否为新增用户。
我们可以发现,除了udmap和common_ts列外,其余列格式基本统一,也就是说首先要对这两个特殊列进行数据处理.
1.1对udmap的数据处理
udmap为行为属性,其中的key1到key9表示不同的行为属性,如项目名、项目id等相关字段,处理起来相对困难
baseline中对udmap处理的相关代码:
# 定义函数 udmap_onethot,用于将 'udmap' 列进行 One-Hot 编码
def udmap_onethot(d):
v = np.zeros(9) # 创建一个长度为 9 的零数组
if d == 'unknown': # 如果 'udmap' 的值是 'unknown'
return v # 返回零数组
d = eval(d) # 将 'udmap' 的值解析为一个字典
for i in range(1, 10): # 遍历 'key1' 到 'key9', 注意, 这里不包括10本身
if 'key' + str(i) in d: # 如果当前键存在于字典中
v[i - 1] = d['key' + str(i)] # 将字典中的值存储在对应的索引位置上
return v # 返回 One-Hot 编码后的数组
# 使用 apply() 方法将 udmap_onethot 函数应用于每个样本的 'udmap' 列
# np.vstack() 用于将结果堆叠成一个数组
train_udmap_df = pd.DataFrame(np.vstack(train_data['udmap'].apply(udmap_onethot)))
test_udmap_df = pd.DataFrame(np.vstack(test_data['udmap'].apply(udmap_onethot)))
# 为新的特征 DataFrame 命名列名
train_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
test_udmap_df.columns = ['key' + str(i) for i in range(1, 10)]
# 将编码后的 udmap 特征与原始数据进行拼接,沿着列方向拼接
train_data = pd.concat([train_data, train_udmap_df], axis=1)
test_data = pd.concat([test_data, test_udmap_df], axis=1)
# 4. 编码 udmap 是否为空
# 使用比较运算符将每个样本的 'udmap' 列与字符串 'unknown' 进行比较,返回一个布尔值的 Series
# 使用 astype(int) 将布尔值转换为整数(0 或 1),以便进行后续的数值计算和分析
train_data['udmap_isunknown'] = (train_data['udmap'] == 'unknown').astype(int)
test_data['udmap_isunknown'] = (test_data['udmap'] == 'unknown').astype(int)
第一次处理时,我不想和baseline代码写的一模一样,所以在对其进行模仿的基础上,我没有使用函数的形式,而是直接对udmap进行数据处理,但我完全没搞懂baseline中的许多东西,
如:
向udmap_onethot传入的参数d应该是个什么数据类,
zeros和eval函数应该如何
于是第一次尝试遭遇了失败.
之后,我使用print(type())的方式一步一步将
train_data['udmap']
train_data['udmap'].apply(udmap_onethot)
np.vstack(train_data['udmap'].apply(udmap_onethot))
的类型输出,算是有了初步的认识,但我感觉以目前水准难以自己进行这样的数据分析,就暂且搁置对源代码的修改
1.2对common_ts的数据处理
common_ts是时间戳特征,处理起来较为简单,特征数据都是十三位,故单位是ms.但将时间戳进行初步的转化后,时间戳实际就是当前时间距离1970年1月1日0点0时0分0秒的时间, 和剩余数据格式仍然不统一,baseline中使用了hour作为提取的目标,我个人认为hour也确实可能对target的影响比较大,就未做修改
# 使用 pd.to_datetime() 函数将时间戳列转换为 datetime 类型
# 样例:1678932546000->2023-03-15 15:14:16
# 注: 需要注意时间戳的长度, 如果是13位则unit 为 毫秒, 如果是10位则为 秒, 这是转时间戳时容易踩的坑
# 具体实现代码:
train_data['common_ts'] = pd.to_datetime(train_data['common_ts'], unit='ms')
test_data['common_ts'] = pd.to_datetime(test_data['common_ts'], unit='ms')
# 使用 dt.hour 属性从 datetime 列中提取小时信息,并将提取的小时信息存储在新的列 'common_ts_hour'
train_data['common_ts_hour'] = train_data['common_ts'].dt.hour
test_data['common_ts_hour'] = test_data['common_ts'].dt.hour
二.对train.csv中数据的分析
在进行完数据预处理的工作,将数据格式基本统一之后,我依次使用了画柱状图 卡方检验 皮尔逊检验 ANOVA检验 画箱线图 画热力图等方式进行数据分析,希望能得出来哪些特征对target的预测更为重要
2.1柱图
以上依次是x8和x7的柱状图,以这两个图举例,我从这两个图中发现了他们的取值确实和target有一定关联,比如我们能发现x7取0的时候target取1的比例明显大于其他值,我将所有特征的柱状图都画了出来,发现他们确实对target都有一定影响,但柱状图似乎只说明了他们和target有关联而很难判断出他们关联性的大小
2.2卡方检验及皮尔逊检验
所以接下来我使用了卡方检验,希望借此来看出来他们关联性的强弱
出乎意料的是,这些特征卡方检验的结果要么是0,要么非常小非常接近0
这是我进行卡方检验的结果
而皮尔逊检验的结果也和其相似
2.3ANOVA检验
我再次进行了ANOVA检验,出乎意料的是,部分特征并未得到结果(猜想:原因是先前未进行数据放缩)
并且得到结果特征的都显示它们与target存在很大关联
2.4箱线图和热力图
由于之前的ANOVA检验许多特征没得到结果,我猜测可能是我没有进行数据放缩,所以在绘制之前我先进行数据放缩
这是我得到的一张热力图
由于之前并未接触过热力图,我难以对其分析.
箱线图也绘制了许多,但同样,我难以对其分析
三.对baseline代码的更改尝试
在进行了一些并不成熟数据处理和分析后,我开始尝试对baseline代码进行更改
先前我提到,虽然各种检验都显示这些特征都与target有不小关联,但是我决定挑选出其中关联较大的一批而舍弃关联较小的一批进行机器学习训练,在对卡方检验和ANOVA检验取交集以后,我将对target特征影响相对小的x3和x6剔除并进行训练
糟糕的是,我将得到的结果提交之后,得到的分数仅有0.44
四.反思与总结
首先,baseline代码的分数在0.66左右,而我将部分特征删除后仅得到了0.44,两次结果都不算好,但这是否预示着我应该向数据欠拟合的方向努力而不是数据过拟合的方向努力?
总之,在对baseline进行学习之后,作为一个0基础我学到了很多,希望在接下来的任务中能学到更多!