Day 10 [Python ML、特徵工程] 特徵生成

汇入基线模型(Baseline model)

%matplotlib inline

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
from sklearn.preprocessing import LabelEncoder

ks = pd.read_csv('./ks-projects-201801.csv',
                 parse_dates=['deadline', 'launched'])

# Drop live projects
ks = ks.query('state != "live"')

# Add outcome column, "successful" == 1, others are 0
ks = ks.assign(outcome=(ks['state'] == 'successful').astype(int))

# Timestamp features
ks = ks.assign(hour=ks.launched.dt.hour,
               day=ks.launched.dt.day,
               month=ks.launched.dt.month,
               year=ks.launched.dt.year)

# Label encoding
cat_features = ['category', 'currency', 'country']
encoder = LabelEncoder()
encoded = ks[cat_features].apply(encoder.fit_transform)

data_cols = ['goal', 'hour', 'day', 'month', 'year', 'outcome']
baseline_data = ks[data_cols].join(encoded)

Interactions

可以组合不同的feature来产生新的feature

interactions = ks['category'] + "_" + ks['country']
print(interactions.head(5))
0            Poetry_GB
1    Narrative Film_US
2    Narrative Film_US
3             Music_US
4      Film & Video_US
dtype: object

将资料经过labelencoder处理,这样model才能够读取资料

label_enc = LabelEncoder()
data_interaction = baseline_data.assign(category_country=label_enc.fit_transform(interactions))
data_interaction.head()

Number of projects in the last week

若是想知道一个礼拜前的资料有几笔,该如何处理
可以使用.rolling的方法

将资料中launched的column当作是index,创造一个series,并且将index资料设定成value

launched = pd.Series(ks.index, index=ks.launched, name="count_7_days").sort_index()
launched.head(20)
launched
1970-01-01 01:00:00     94579
1970-01-01 01:00:00    319002
1970-01-01 01:00:00    247913
1970-01-01 01:00:00     48147
1970-01-01 01:00:00     75397
1970-01-01 01:00:00      2842
1970-01-01 01:00:00    273779
2009-04-21 21:02:48    169268
2009-04-23 00:07:53    322000
2009-04-24 21:52:03    138572
2009-04-25 17:36:21    325391
2009-04-27 14:10:39    122662
2009-04-28 13:55:41    213711
2009-04-29 02:04:21    345606
2009-04-29 02:58:50    235255
2009-04-29 04:37:37     98954
2009-04-29 05:26:32    342226
2009-04-29 06:43:44    275091
2009-04-29 13:52:03    284115
2009-04-29 22:08:13     32898
Name: count_7_days, dtype: int64

当我们有一个timeseries的index,可以使用.rolling去选取需要滑动的窗格
Example launched.rolling('7d')可以创建一个滑动7天的窗格
为了不要计算到现在的时间,因此我们要将资料-1

count_7_days = launched.rolling('7d').count()-1
print(count_7_days.head(20))

# Ignore records with broken launch dates
plt.plot(count_7_days[7:]);
plt.title("Number of projects launched over periods of 7 days");
launched
1970-01-01 01:00:00     0.0
1970-01-01 01:00:00     1.0
1970-01-01 01:00:00     2.0
1970-01-01 01:00:00     3.0
1970-01-01 01:00:00     4.0
1970-01-01 01:00:00     5.0
1970-01-01 01:00:00     6.0
2009-04-21 21:02:48     0.0
2009-04-23 00:07:53     1.0
2009-04-24 21:52:03     2.0
2009-04-25 17:36:21     3.0
2009-04-27 14:10:39     4.0
2009-04-28 13:55:41     5.0
2009-04-29 02:04:21     5.0
2009-04-29 02:58:50     6.0
2009-04-29 04:37:37     7.0
2009-04-29 05:26:32     8.0
2009-04-29 06:43:44     9.0
2009-04-29 13:52:03    10.0
2009-04-29 22:08:13    11.0
Name: count_7_days, dtype: float64

现在我们有7天内有几笔资料的Series,现在我们要将这些资料加入training data

# 将时间资料改为index
count_7_days.index = launched.values
# 将时间资料fit原始资料的index
count_7_days = count_7_days.reindex(ks.index)
# 也可以用sort_index
# count_7_days = count_7_days.sort_index()
count_7_days.head(10)
0    1487.0
1    2020.0
2     279.0
3     984.0
4     752.0
5     522.0
6     708.0
7    1566.0
8    1048.0
9     975.0
Name: count_7_days, dtype: float64
baseline_data.join(count_7_days).head(10)

Time since the last project in the same category

若是想投资一个游戏,但另一个相同类型的游戏才刚上市,就会赚不到钱
因此我们需要去抓出在同一个类型中,最後上市的时间

我们需要先将资料做.groupby在用.transform.
.transform

def time_since_last_project(series):
    # Return the time in hours
    return series.diff().dt.total_seconds() / 3600.

df = ks[['category', 'launched']].sort_values('launched')
df.head(20)

timedeltas = df.groupby('category').transform(time_since_last_project)
timedeltas.head(20)

将NaN利用timedeltas的median或是mean填入,再reindex,才能将资料加入其他data中

timedeltas = timedeltas.fillna(timedeltas.median()).reindex(baseline_data.index)
timedeltas.head(10)

Transforming numerical features

"goal"这一个column中显示很多比赛的奖金少於5000USD
但有些比赛的奖金却高达100,000USD

所以我们需要对数值资料做处理,去移除这些离群值(outliers)

一些比较常见的选择为square root和natual logarithm

plt.hist(ks.goal, range=(0, 100000), bins=50);
plt.title('Goal');

从上图中可以看出,接近0的数值非常多,但接近100,000的值却很少

plt.hist(np.sqrt(ks.goal), range=(0, 400), bins=50);
plt.title('Sqrt(Goal)');

将资料开根号之後可以让资料较为平缓

plt.hist(np.log(ks.goal), range=(0, 25), bins=50);
plt.title('Log(Goal)');

将资料做log处理後,资料会变得较为集中

这类型的转换对tree-based model的影响并不大
但却能帮助linear model或neural network

产生特徵的方法很多,但都要基於经验
另外一个方法就是我们可以产生很多特徵,并且利用特徵筛选的工具来选择较好的特徵


<<:  Batch Processing (1) - Batch Processing with Unix Tools

>>:  [Day8] 有意识地沟通:每个成员都有自己的功课

Day 0xC - Debug 地狱第三天,终於逃脱了 (建立订单)

0x1 前言 从 Day 0xA 开始撞墙,撞到今天总算解出来了 几个问题请让我娓娓道来 0x2 好...

15. HTTP request methods ( 上 )--- GET vs. POST

HTTP 定义 网路通讯之间必须有共同的标准,而为了界定这些标准,於是产生协定(Protocol)。...

Day 15 K3S & Raspberry Pi

k3s 下载 安装 wget https://github.com/k3s-io/k3s/relea...

[DAY25]建立资料库

打开PGADMIN,新增表格 填入表单名,按下columns新增需要的栏位,Data type首先推...

利用Cloudflare API关闭Cloudflare IPv6兼容性功能

在使用一段时间Cloudflare加速后,发现网站程序并不兼容IPV6,目前厂家未作升级处理,整了好...