Task3 特征工程

本文介绍了一个基于海洋数据的竞赛实践,重点介绍了特征工程的过程,包括特征构建、特征提取与选择,以及数据预处理方法。同时探讨了基础特征的构建如距离、时间和速度划分等,并引入了embedding特征的应用。
摘要由CSDN通过智能技术生成

智慧海洋竞赛实践 专题三

1. 特征工程概述

特征工程大体可分为3部分,特征构建、特征提取和特征选择。

1.1 特征构建

把现有特征进行组合或互相计算,得到新的特征。

1.2 特征提取和特征选择

  • 特征提取

通过特征转换得到一组具有明显物理或统计意义的特征

  • 特征选择(属性选择/变量选择)

从这些特征集合中选出一个子集。

2. 数据预处理

2.1 读入数据

参考链接:https://blog.csdn.net/weixin_43496331/article/details/115769140?spm=1001.2014.3001.5501

2.2 基本处理

读入数据(df)预览:

在这里插入图片描述

# 将中文名改为英文
df.rename(columns = {'渔船ID': 'id', '速度': 'v', '方向': 'dir'},inplace = True)
# 把分类变量数值化
df.rename(columns ={'type': 'label'},inplace = True) #修改变量名
df['label'] = df['label'].map({'拖网': 0, '围网': 1, '刺网': 2})

# 修改变量类型为float
cols = ['x','y','v']
for col in cols:
    df[col] = df[col].astype('float')
df['dir'] = df['dir'].astype('int')

# 修改变量类型为时间类型,并增加年时间字段
df['time'] = pd.to_datetime(df['time'], format='%m%d %H:%M:%S')
df['date'] = df['time'].dt.date
df['hour'] = df['time'].dt.hour
df['month'] = df['time'].dt.month
df['weekday'] = df['time'].dt.weekday

3. 基础特征

3.1 距离计算

d = ( x − x 0 ) 2 + ( y − y 0 ) 2 2 d = \sqrt[2]{(x-x_0)^2+(y-y_0)^2} d=2(xx0)2+(yy0)2

3.2 时间划分

# 白天、黑天划分
df['day_nig'] = 0
df.loc[(df['hour'] > 5) & (df['hour'] < 20),'day_nig'] = 1

# 季度划分
df['quarter'] = 0
df.loc[(df['month'].isin([1, 2, 3])), 'quarter'] = 1
df.loc[(df['month'].isin([4, 5, 6, ])), 'quarter'] = 2
df.loc[(df['month'].isin([7, 8, 9])), 'quarter'] = 3
df.loc[(df['month'].isin([10, 11, 12])), 'quarter'] = 4

3.3 速度划分

定义速度划分区间,生成新变量‘v_cut’

def v_cut(v):
    if v < 0.1:
        return 0
    elif v < 0.5:
        return 1
    elif v < 1:
        return 2
    elif v < 2.5:
        return 3
    elif v < 5:
        return 4
    elif v < 10:
        return 5
    elif v < 20:
        return 5
    else:
        return 6

df['v_cut'] = df['v'].apply(lambda x:v_cut(x))

统计每个id的对应速度等级的个数,生成工具表c1

# 分组计算
tmp = df.groupby(['id', 'v_cut'], as_index=False)['v_cut'].agg({'v_cut_count': 'count'})
# 透视
c1 = tmp.pivot(index='id',columns='v_cut',values='v_cut_count')
# 修改列名
c1.columns = ['v_cut_' + str(col) for col in c1.columns.tolist()]
c1 = c1.reset_index()

3.4 方位划分

# 对方位进行16均分
df['d16'] = df['d'].apply(lambda x: int((x / 22.5) + 0.5) % 16 if not np.isnan(x) else np.nan)

# 分组
tmp = df.groupby(['id', 'd16'], as_index=False)['d16'].agg({'d16_count': 'count'})
# 透视
c3 = c3.pivot(index='ship', columns='d16', values='d16_count')
# 修改列名
c3.columns = ['d16_' + str(col) for col in c3.columns.tolist()]
c3 = c3.reset_index()

3.5 描述性统计

方法一:groupby().agg()

详细请参考:http://joyfulpandas.datawhale.club/Content/ch4.html

对速度不为0的数据进行描述性统计

# 统计速度为0的个数,以及速度不为0的统计量
df_zero_count = df.query("v==0")[['id', 'v']].groupby('id', as_index=False)['v'].agg({'num_zero_v': 'count'})
df_not_zero_agg = df.query("v!=0")[['ship', 'v']].groupby('id', as_index=False)['v'].agg(
    {'v_max_drop_0': 'max',
     'v_min_drop_0': 'min',
     'v_mean_drop_0': 'mean',
     'v_std_drop_0': 'std',
     'v_median_drop_0': 'median',
     'v_skew_drop_0': 'skew'})
c2 = df_zero_count.merge(df_not_zero_agg,on='id',how='left')

方法二:groupby().describe()

计算各种位数:[0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875]

df_raw.groupby('id')[key[i]].describe(percentiles=[0.05] + [ii / 1000 for ii in range(125, 1000, 125)] + [0.95])

3.6 坐标与角度偏移指标计算

方法:.shift()、.fillna(method=‘ffill’)

# 坐标
temp['ynext'] = temp.groupby('ship')['y'].shift(-1)
temp['ynext'] = temp['ynext'].fillna(method='ffill')

temp['xnext'] = temp.groupby('ship')['x'].shift(-1)
temp['xnext'] = temp['xnext'].fillna(method='ffill')

temp['angle_next'] = (temp['ynext'] - temp['y']) / (temp['xnext'] - temp['x'])
temp['angle_next'] = np.arctan(temp['angle_next']) / math.pi * 180
temp['angle_next_next'] = temp['angle_next'].shift(-1)

# 时间
temp['timenext'] = temp.groupby('ship')['time'].shift(-1)
temp['timediff'] = np.abs(temp['timenext'] - temp['time'])
temp['timediff'] = temp['timediff'].fillna(method='ffill')
temp['hc_xy'] = abs(temp['angle_next_next'] - temp['angle_next'])

3.7 分箱

方法:pd.qcut()、zip()、map()、transform()

# 速度
df['v_bin'] = pd.qcut(df['v'], 200, duplicates='drop') # 速度进行 200分位数分箱
df['v_bin'] = df['v_bin'].map(dict(zip(df['v_bin'].unique(),range(df['v_bin'].nunique()))))# 分箱后

# 坐标
for f in ['x', 'y']:
    df[f + '_bin1'] = pd.qcut(df[f], 1000, duplicates='drop') # x,y位置分箱1000
    df[f + '_bin1'] = df[f + '_bin1'].map(dict(zip(df[f + '_bin1'].unique(), range(df[f + '_bin1'].nunique()))))#编码
    df[f + '_bin2'] = df[f] // 10000 # 取整操作
    df[f + '_bin1_count'] = df[f + '_bin1'].map(df[f + '_bin1'].value_counts()) #x,y不同分箱的数量映射
    df[f + '_bin2_count'] = df[f + '_bin2'].map(df[f + '_bin2'].value_counts()) #数量映射
    df[f + '_bin1_id_nunique'] = df.groupby(f + '_bin1')['id'].transform('nunique')#基于分箱1 id数量映射
    df[f + '_bin2_id_nunique'] = df.groupby(f + '_bin2')['id'].transform('nunique')#基于分箱2 id数量映射

pre_cols = df.columns

一开始一直在想为什么要把这个放到最开始,执行到最后,才发现是为了过滤出新增列的数据。

new_cols = [i for i in df.columns if i not in pre_cols]
df[new_cols].head()

通过字典的形式来构建方法和重命名

agg_dict = {}
for ag in ['max','mean','median','std','skew']:
    agg_dict['{}_{}_{}'.format('speed',ag,"0")] = ag
print(agg_dict)

RUN:

{'speed_max_0': 'max', 'speed_mean_0': 'mean', 'speed_median_0': 'median', 'speed_std_0': 'std', 'speed_skew_0': 'skew'}

4. embedding特征

4.1 简介

word embedding就是把一个词用编码的方式表示以便于feed到网络中。Word Embedding有的时候也被称作为分布式语义模型或向量空间模型等,所以从名字和其转换的方式我们就可以明白, Word Embedding技术可以将相同类型的词归到一起,例如苹果,芒果香蕉等,在投影之后的向量空间距离就会更近,而书本,房子这些则会与苹果这些词的距离相对较远。

4.2 使用场景

Word Embedding可以用到特征生成,文件聚类,文本分类和自然语言处理等任务

如此次数据针对的航海问题中,对相同经纬度上不同的船进行Embedding,就可以得到每个船只的向量,就可以得到经常在某些区域工作的船只

4.3 Word2Vec

Word2vec在向量空间中对词进行表示, 或者说词以向量的形式表示,在词向量空间中:相似含义的单词一起出现,而不同的单词则位于很远的地方。这也被称为语义关系。神经网络不理解文本,而只理解数字。词嵌入提供了一种将文本转换为数字向量的方法。Word2vec就是在重建词的语言上下文。

**上下文:**在一般的生活情景中,当我们通过说话或写作来交流,其他人会试图找出句子的目的。例如,“印度的温度是多少”,这里的上下文是用户想知道“印度的温度”即上下文。

embedding_size=70
iters=70
min_count=3
window_size=25
num_runs=1
seed=9012

sentences = []
for i in boat_id:
    traj = traj_data_corpus[traj_data_corpus['id']==i]
    sentences.append(traj['no_bin'].values.tolist())
    
model = Word2Vec(sentences, size=embedding_size,
                          min_count=min_count,
                          workers=mp.cpu_count(),
                          window=window_size,
                          seed=seed, iter=iters, sg=0)

embedding_vec = []
for ind, seq in enumerate(sentences):
    seq_vec, word_count = 0, 0
    for word in seq:
        if word not in model:
            continue
        else:
            seq_vec += model[word]
            word_count += 1
    if word_count == 0:
        embedding_vec.append(embedding_size * [0])
    else:
        embedding_vec.append(seq_vec / word_count)

4.4 NMF提取文本的主题分布

class nmf_list(object):
    def __init__(self,data,by_name,to_list,nmf_n,top_n):
        self.data = data
        self.by_name = by_name
        self.to_list = to_list
        self.nmf_n = nmf_n
        self.top_n = top_n

    def run(self,tf_n):
        df_all = self.data.groupby(self.by_name)[self.to_list].apply(lambda x :'|'.join(x)).reset_index()
        self.data =df_all.copy()

        print('bulid word_fre')
        # 词频的构建
        def word_fre(x):
            word_dict = []
            x = x.split('|')
            docs = []
            for doc in x:
                doc = doc.split()
                docs.append(doc)
                word_dict.extend(doc)
            word_dict = Counter(word_dict)
            new_word_dict = {}
            for key,value in word_dict.items():
                new_word_dict[key] = [value,0]
            del word_dict  
            del x
            for doc in docs:
                doc = Counter(doc)
                for word in doc.keys():
                    new_word_dict[word][1] += 1
            return new_word_dict 
        self.data['word_fre'] = self.data[self.to_list].apply(word_fre)

        print('bulid top_' + str(self.top_n))
        # 设定100个高频词
        def top_100(word_dict):
            return sorted(word_dict.items(),key = lambda x:(x[1][1],x[1][0]),reverse = True)[:self.top_n]
        self.data['top_'+str(self.top_n)] = self.data['word_fre'].apply(top_100)
        def top_100_word(word_list):
            words = []
            for i in word_list:
                i = list(i)
                words.append(i[0])
            return words 
        self.data['top_'+str(self.top_n)+'_word'] = self.data['top_' + str(self.top_n)].apply(top_100_word)
        # print('top_'+str(self.top_n)+'_word的shape')
        print(self.data.shape)

        word_list = []
        for i in self.data['top_'+str(self.top_n)+'_word'].values:
            word_list.extend(i)
        word_list = Counter(word_list)
        word_list = sorted(word_list.items(),key = lambda x:x[1],reverse = True)
        user_fre = []
        for i in word_list:
            i = list(i)
            user_fre.append(i[1]/self.data[self.by_name].nunique())
        stop_words = []
        for i,j in zip(word_list,user_fre):
            if j>0.5:
                i = list(i)
                stop_words.append(i[0])

        print('start title_feature')
        # 讲融合后的taglist当作一句话进行文本处理
        self.data['title_feature'] = self.data[self.to_list].apply(lambda x: x.split('|'))
        self.data['title_feature'] = self.data['title_feature'].apply(lambda line: [w for w in line if w not in stop_words])
        self.data['title_feature'] = self.data['title_feature'].apply(lambda x: ' '.join(x))

        print('start NMF')
        # 使用tfidf对元素进行处理
        tfidf_vectorizer = TfidfVectorizer(ngram_range=(tf_n,tf_n))
        tfidf = tfidf_vectorizer.fit_transform(self.data['title_feature'].values)
        #使用nmf算法,提取文本的主题分布
        text_nmf = NMF(n_components=self.nmf_n).fit_transform(tfidf)


        # 整理并输出文件
        name = [str(tf_n) + self.to_list + '_' +str(x) for x in range(1,self.nmf_n+1)]
        tag_list = pd.DataFrame(text_nmf)
        print(tag_list.shape)
        tag_list.columns = name
        tag_list[self.by_name] = self.data[self.by_name]
        column_name = [self.by_name] + name
        tag_list = tag_list[column_name]
        return tag_list

data = df.copy()
data.rename(columns={'v':'speed','id':'ship'},inplace=True)
for j in range(1):
    print('********* {} *******'.format(j))
    for i in ['speed','x','y']:
        data[i + '_str'] = data[i].astype(str)
        nmf = nmf_list(data,'ship',i + '_str',8,2)
        nmf_a = nmf.run(j)
        nmf_a.rename(columns={'ship':'id'},inplace=True)
        data_label = data_label.merge(nmf_a,on = 'id',how = 'left')

RUN:

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值