kaggle - xiaoxin01/Blog GitHub Wiki

Using Pandas to Get Familiar With Your Data

The first step in any machine learning project is familiarize yourself with the data. You'll use the Pandas library for this. Pandas is the primary tool data scientists use for exploring and manipulating data.

The most important part of the Pandas library is the DataFrame. A DataFrame holds the type of data you might think of as a table. This is similar to a sheet in Excel, or a table in a SQL database.

data = pd.read_csv
data.columns

Selecting Data for Modeling

Your dataset had too many variables to wrap your head around, or even to print out nicely. How can you pare down this overwhelming amount of data to something you can understand?

We'll start by picking a few variables using our intuition.

"LotArea", "YearBuilt", "1stFlrSF", "2ndFlrSF", "FullBath", "BedroomAbvGr", "TotRmsAbvGrd"

features = [""]
X = data[features]
X.describe()
X.head()

Building Your Model

You will use the scikit-learn library to create your models. When coding, this library is written as sklearn, as you will see in the sample code. Scikit-learn is easily the most popular library for modeling the types of data typically stored in DataFrames.

from sklearn.tree import DecisionTreeRegressor

# Define model. Specify a number for random_state to ensure same results each run
melbourne_model = DecisionTreeRegressor(random_state=1)

# Fit model
melbourne_model.fit(X, y)

# Predict
melbourne_model.predict(X)

Model Validation

Measuring model quality is the key to iteratively improving your models.

MAE: mean_absolute_error

Split data: train_test_split(from sklearn.model_selection import train_test_split)

Underfitting and Overfitting

决策树的问题:

  1. feature 越多,层级越多
  2. 然后每个节点包含的数据越少,容易过拟合,在预测上表现不好
  3. 层级越少,容易欠拟合
  4. 平衡点曲线,随着层级加深, validation date 的 MAE 开始增加
# compare MAE with differing values of max_leaf_nodes
for max_leaf_nodes in [5, 50, 500, 5000]:
    my_mae = get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y)
    print("Max leaf nodes: %d  \t\t Mean Absolute Error:  %d" %(max_leaf_nodes, my_mae))

Overfitting: capturing spurious patterns that won't recur in the future, leading to less accurate predictions, or Underfitting: failing to capture relevant patterns, again leading to less accurate predictions. We use validation data, which isn't used in model training, to measure a candidate model's accuracy. This lets us try many candidate models and keep the best one.

scores = {leaf_size: get_mae(leaf_size, train_X, val_X, train_y, val_y) for leaf_size in candidate_max_leaf_nodes}
best_tree_size = min(scores, key=scores.get)

Random Forests

Decision trees leave you with a difficult decision. A deep tree with lots of leaves will overfit because each prediction is coming from historical data from only the few houses at its leaf. But a shallow tree with few leaves will perform poorly because it fails to capture as many distinctions in the raw data.

The random forest uses many trees, and it makes a prediction by averaging the predictions of each component tree. It generally has much better predictive accuracy than a single decision tree and it works well with default parameters. If you keep modeling, you can learn more models with even better performance, but many of those are sensitive to getting the right parameters.

from sklearn.ensemble import RandomForestRegressor

Pandas

  • DataFrame
  • Serias
  • iloc, index-based selection, row-first, column-second,
  • loc, label-based selection,

iloc uses the Python stdlib indexing scheme, where the first element of the range is included and the last one excluded. So 0:10 will select entries 0,...,9. loc, meanwhile, indexes inclusively. So 0:10 will select entries 0,...,10

  • loc[isin

Summary Functions

  • describe

  • mean

  • unique

  • value_counts

  • map(lambda p: p - x)

  • apply(func, axis=)

Note that map() and apply() return new, transformed Series and DataFrames, respectively. They don't modify the original data they're called on.

# a lot of values on the left-hand side (everything in the Series) and a single value on the right-hand side
review_points_mean = reviews.points.mean()
reviews.points - review_points_mean

# Series of equal length
reviews.country + " - " + reviews.region_1

These operators are faster than map() or apply() because they use speed ups built into pandas. All of the standard Python operators (>, <, ==, and so on) work in this manner.

Grouping and Sorting

  • groupby('').price.count()
  • agg([min, max])

Data Type

  • astype
  • isnull
  • fillna

Renaming and Combining

  • rename(columns={'points': 'score'})

  • rename(index={0:'', 1:''})

  • rename_axis("", axis='rows' | 'columns')

  • pd.concat([csv1, csv2])

# join
# 注意这边都是生成新的 DataFrame,而不是更改原来的
left = canadian_youtube.set_index(['title', 'trending_date'])
right = british_youtube.set_index(['title', 'trending_date'])

left.join(right, lsuffix='_CAN', rsuffix='_UK')

Intermediate Machine Learning

dealing with missing values

  1. Drop columns with missing value
  2. Imputation
  3. An extension to imputation (add a field)

采用何种方法,取决于数据集的特性,并不一定后面的比前面的好,可以实际跑一下试试看

Categorical Variables

  1. Drop
  2. Encoding (Enum),注意顺序
    1. "Never" (0) < "Rarely" (1) < "Most days" (2) < "Every day" (3).
  3. One-hot encoding,没有顺序,超过 15 个不同值表现不好
    1. 001, 010, 100
from sklearn.preprocessing import OrdinalEncoder

ordinal_encoder = OrdinalEncoder()
label_X_train[object_cols] = ordinal_encoder.fit_transform(X_train[object_cols])
label_X_valid[object_cols] = ordinal_encoder.transform(X_valid[object_cols])

有时候训练集和验证集正好有不同的 lebel,这时候可以通过 set 来找出这些 column

from sklearn.preprocessing import OneHotEncoder

# Use as many lines of code as you need!
one_hot_encoder = OneHotEncoder(handle_unknown='ignore',sparse = False)


OH_X_train = pd.DataFrame(one_hot_encoder.fit_transform(X_train[low_cardinality_cols]))
OH_X_valid = pd.DataFrame( one_hot_encoder.transform(X_valid[low_cardinality_cols]))

OH_X_train.index = X_train.index
OH_X_valid.index = X_valid.index

# Remove categorical columns (will replace with one-hot encoding)
num_X_train = X_train.drop(object_cols, axis=1)
num_X_valid = X_valid.drop(object_cols, axis=1)

# Add one-hot encoded columns to numerical features
OH_X_train = pd.concat([num_X_train, OH_X_train], axis=1)
OH_X_valid = pd.concat([num_X_valid, OH_X_valid], axis=1)

Data Visualization

Line Charts

import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

museum_data = pd.read_csv('', index_col='')

# Set the width and height of the figure
plt.figure(figsize=(12,6))
# Add title
plt.title("Monthly Visitors to Avila Adobe")

sns.lineplot(data=museum_data)

plt.xlabel("Date")

Bar Charts and Heatmap

# Important Note: You must select the indexing column with flight_data.index, and it is not possible to use flight_data['Month'] (which will return an error). This is because when we loaded the dataset, the "Month" column was used to index the rows. We always have to use this special notation to select the indexing column.
sns.barplot(x=flight_data.index, y=flight_data['NK'])

# annot=True - This ensures that the values for each cell appear on the chart. (Leaving this out removes the numbers from each of the cells!)
sns.heatmap(data=flight_data, annot=True)

Scatter Plots

Leverage the coordinate plane to explore relationships between variables

sns.scatterplot(x=insurance_data['bmi'], y=insurance_data['charges'])

# regression line
sns.regplot(x=insurance_data['bmi'], y=insurance_data['charges'])

# the relationships between (not two, but...) three variables
sns.scatterplot(x=insurance_data['bmi'], y=insurance_data['charges'], hue=insurance_data['smoker'])

# add two regression lines
sns.lmplot(x="bmi", y="charges", hue="smoker", data=insurance_data)

# categorical scatter plot
sns.swarmplot(x=insurance_data['smoker'],
              y=insurance_data['charges'])

histograms and density plots

# Histogram 
sns.histplot(iris_data['Petal Length (cm)'])

# KDE plot 
sns.kdeplot(data=iris_data['Petal Length (cm)'], shade=True)

# 2D KDE plot
sns.jointplot(x=iris_data['Petal Length (cm)'], y=iris_data['Sepal Width (cm)'], kind="kde")

# Histograms for each species
sns.histplot(data=iris_data, x='Petal Length (cm)', hue='Species')

# KDE plots for each species
sns.kdeplot(data=iris_data, x='Petal Length (cm)', hue='Species', shade=True)

Pipeline

# Preprocessing for numerical data
numerical_transformer = SimpleImputer(strategy='constant')

# Preprocessing for categorical data
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))
])

# Bundle preprocessing for numerical and categorical data
preprocessor = ColumnTransformer(
    transformers=[
        ('num', numerical_transformer, numerical_cols),
        ('cat', categorical_transformer, categorical_cols)
    ])

my_pipeline = Pipeline(steps=[('preprocessor', preprocessor),
                              ('model', model)
                             ])

# Preprocessing of training data, fit model 
my_pipeline.fit(X_train, y_train)

Cross-Validation

因为数据集的随机性,所以一个模型可能在一部分验证集表现很好,但是在另外一部分验证集表现不好

使用 Cross-Validatiaon,比如将数据分为 5 份,进行 5 次实验,分别对这 5 份数据来计算 误差

什么时候使用?

  • 对于小数据集,额外的计算负担不是什么大问题,您应该运行交叉验证。
  • 对于更大的数据集,单个验证集就足够了。
from sklearn.model_selection import cross_val_score

# Multiply by -1 since sklearn calculates *negative* MAE
scores = -1 * cross_val_score(my_pipeline, X, y,
                              cv=5,
                              scoring='neg_mean_absolute_error')

print("MAE scores:\n", scores)

XGBost

梯度下降库

  • early_stopping_rounds: 多少次没有下降之后,结束 cycle
my_model = XGBRegressor(n_estimators=1000, learning_rate=0.05, n_jobs=4)
my_model.fit(X_train, y_train, 
             early_stopping_rounds=5, 
             eval_set=[(X_valid, y_valid)], 
             verbose=False)

Data Leakage

target leakage

train-test contamination

Feature Engineering

特征工程可以帮助:

  • 提高模型的预测性能
  • 减少计算或数据需求
  • 提高结果的可解释性

比如当我们预测土地价格的时候,有一个 feature 叫 length,如果我们直接用这个 feature 来创建模型,则对样本集的拟合效果将不是很好,但是当我们新增一个 feature 叫 面积 = length^2,用这个新的 feature 将会很好的拟合

Mutual Information

Locate features with the most potential.

好处:

  • 易于使用和解释,
  • 计算效率高,
  • 理论上有根据,
  • 抗过度拟合,并且,
  • 能够检测任何类型的关系

当然,MI 分数越低并不一定没有用,这时候 domain knowledge 就非常有帮助

discrete_features = X.dtypes == int
# discrete_features = [pd.api.types.is_integer_dtype(t) for t in X.dtypes]

from sklearn.feature_selection import mutual_info_regression

def make_mi_scores(X, y, discrete_features):
    mi_scores = mutual_info_regression(X, y, discrete_features=discrete_features)
    mi_scores = pd.Series(mi_scores, name="MI Scores", index=X.columns)
    mi_scores = mi_scores.sort_values(ascending=False)
    return mi_scores

mi_scores = make_mi_scores(X, y, discrete_features)
mi_scores[::3]  # show a few features with their MI scores

Creating Features

Transform features with Pandas to suit your model.

发现新功能的技巧

  • 了解特征。 请参阅数据集的数据文档。
  • 研究问题领域以获得领域知识(domain knowledge)。 如果您的问题是预测房价,例如对房地产进行一些研究。
  • 研究以前的工作。 过去 Kaggle 竞赛的解决方案记录是一个很好的资源。
  • 使用数据可视化。

Mathematical Transforms

autos["stroke_ratio"] = autos.stroke / autos.bore
autos["displacement"] = (
    np.pi * ((0.5 * autos.bore) ** 2) * autos.stroke * autos.num_of_cylinders
)
# If the feature has 0.0 values, use np.log1p (log(1+x)) instead of np.log
accidents["LogWindSpeed"] = accidents.WindSpeed.apply(np.log1p)

# Plot a comparison
fig, axs = plt.subplots(1, 2, figsize=(8, 4))
sns.kdeplot(accidents.WindSpeed, shade=True, ax=axs[0])
sns.kdeplot(accidents.LogWindSpeed, shade=True, ax=axs[1]);

Counts

# 是否发生某件事情
roadway_features = ["Amenity", "Bump", "Crossing", "GiveWay",
    "Junction", "NoExit", "Railway", "Roundabout", "Station", "Stop",
    "TrafficCalming", "TrafficSignal"]
accidents["RoadwayFeatures"] = accidents[roadway_features].sum(axis=1)

# 是否包含某种配方
components = [ "Cement", "BlastFurnaceSlag", "FlyAsh", "Water",
               "Superplasticizer", "CoarseAggregate", "FineAggregate"]
concrete["Components"] = concrete[components].gt(0).sum(axis=1)

Building-Up and Breaking-Down Features

Often you'll have complex strings that can usefully be broken into simpler pieces

customer[["Type", "Level"]] = (  # Create two new features
    customer["Policy"]           # from the Policy feature
    .str                         # through the string accessor
    .split(" ", expand=True)     # by splitting on " "
                                 # and expanding the result into separate columns
)

Group Transforms

customer["AverageIncome"] = (
    customer.groupby("State")  # for each state
    ["Income"]                 # select the income
    .transform("mean")         # and compute its mean
)

创建特征的技巧

在创建特征时,最好牢记模型自身的优势和劣势。 以下是一些准则:

  • 线性模型自然地学习和与差,但无法学习任何更复杂的东西。
  • 对于大多数模型来说,比率似乎很难学习。 比率组合通常会导致一些简单的性能提升。
  • 线性模型和神经网络通常在归一化特征方面做得更好。 神经网络尤其需要将特征缩放到离 0 不太远的值。基于树的模型(如随机森林和 XGBoost)有时可以从归一化中受益,但通常情况下要少得多。
  • 树模型可以学习近似任何特征组合,但当组合特别重要时,它们仍然可以从显式创建它中受益,尤其是在数据有限的情况下。
  • 计数对于树模型特别有用,因为这些模型没有一种自然的方式来同时聚合许多特征的信息。
# One-hot encode BldgType. Use `prefix="Bldg"` in `get_dummies`

X_2 = pd.get_dummies(df.BldgType, prefix='Bldg') 

# Multiply
X_2 = X_2.mul(df.GrLivArea, axis=0)

# split string
X_4['MSClass'] = df.MSSubClass.str.split('_', n=1, expand=True)[0]

Learn Tutorial

Feature Engineering

Cluster Labels as a Feature

k-Means Clustering

from sklearn.cluster import KMeans
# Create cluster feature
kmeans = KMeans(n_clusters=6)
X["Cluster"] = kmeans.fit_predict(X)
X["Cluster"] = X["Cluster"].astype("category")

sns.relplot(
    x="Longitude", y="Latitude", hue="Cluster", data=X, height=6,
);

X["MedHouseVal"] = df["MedHouseVal"]
sns.catplot(x="MedHouseVal", y="Cluster", data=X, kind="boxen", height=6);

k-means 算法对尺度敏感。 这意味着我们需要考虑如何以及是否重新缩放我们的特征,因为根据我们的选择,我们可能会得到非常不同的结果。 根据经验,如果这些特征已经可以直接比较(比如不同时间的测试结果),那么你就不想重新缩放。 另一方面,不在可比尺度上的特征(如身高和体重)通常会受益于重新缩放。 有时,选择并不明确。 在这种情况下,您应该尝试使用常识,记住具有较大值的特征将被赋予更大的权重。

Consider the following sets of features. For each, decide whether:

  • they definitely should be rescaled,
  • they definitely should not be rescaled, or
  • either might be reasonable

Features:

  1. Latitude and Longitude of cities in California
  2. Lot Area and Living Area of houses in Ames, Iowa
  3. Number of Doors and Horsepower of a 1989 model car

Principal Component Analysis

Discover new features by analyzing variation.

Kaggle intruduction

理解PCA

Target Encoding

Boost any categorical feature with this powerful technique.

Time Series

Linear Regression With Time Series

预测的基本对象是时间序列,它是随时间记录的一组观测值。 在预测应用程序中,观察结果通常以固定频率记录,例如每天或每月。

Time-step features

from sklearn.linear_model import LinearRegression

df = average_sales.to_frame()

# YOUR CODE HERE: Create a time dummy
time = np.arange(len(df.index))

df['time'] = time 

# YOUR CODE HERE: Create training data
X = df.loc[:, ['time']]
y = df.loc[:, 'sales']

# Train the model
model = LinearRegression()
model.fit(X, y)

# Store the fitted values as a time series with the same time index as
# the training data
y_pred = pd.Series(model.predict(X), index=X.index)

Lag features

df = average_sales.to_frame()

# YOUR CODE HERE: Create a lag feature from the target 'sales'
lag_1 = df['sales'].shift(1)

df['lag_1'] = lag_1  # add to dataframe

X = df.loc[:, ['lag_1']].dropna()  # features
y = df.loc[:, 'sales']  # target
y, X = y.align(X, join='inner')  # drop corresponding values in target

# YOUR CODE HERE: Create a LinearRegression instance and fit it to X and y.
model = LinearRegression()
model.fit(X, y)

# YOUR CODE HERE: Create Store the fitted values as a time series with
# the same time index as the training data
y_pred = pd.Series(model.predict(X), index=X.index)

Trend

时间序列的趋势成分表示序列均值的持续、长期变化。 趋势是一系列中变化最慢的部分,代表最重要的时间尺度的部分。

moving average plot

trend = food_sales.rolling(
    window=12,
    center=True,
    min_periods=6,
).mean()

# Make a plot
ax = food_sales.plot(**plot_params, alpha=0.5)
ax = trend.plot(ax=ax, linewidth=3)

Create a Trend Feature

from statsmodels.tsa.deterministic import DeterministicProcess

y = average_sales.copy()  # the target

# YOUR CODE HERE: Instantiate `DeterministicProcess` with arguments
# appropriate for a cubic trend model
dp = DeterministicProcess(
    index=y.index,  # dates from the training data
    order=3,
)

# YOUR CODE HERE: Create the feature set for the dates given in y.index
X = dp.in_sample()

# YOUR CODE HERE: Create features for a 90-day forecast.
X_fore = dp.out_of_sample(steps=90)

# Draw plot
model = LinearRegression()
model.fit(X, y)

y_pred = pd.Series(model.predict(X), index=X.index)
y_fore = pd.Series(model.predict(X_fore), index=X_fore.index)

ax = y.plot(**plot_params, alpha=0.5, title="Average Sales", ylabel="items sold")
ax = y_pred.plot(ax=ax, linewidth=3, label="Trend", color='C0')
ax = y_fore.plot(ax=ax, linewidth=3, label="Trend Forecast", color='C3')
ax.legend();

Seasonality

...

Intro to Deep Learning

Use TensorFlow and Keras to build and train neural networks for structured data.

A Single Neuron

from tensorflow import keras
from tensorflow.keras import layers

# Create a network with 1 linear unit
# units=1 表示结果数量
# input_shape=[3] 表示 3 个维度
model = keras.Sequential([
    layers.Dense(units=1, input_shape=[3])
])

Deep Neural Networks

Add hidden layers to your network to uncover complex relationships.

The Activation Function

ReLU:𝑚𝑎𝑥(0,𝑥)

Building Sequential Models

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    # the hidden ReLU layers
    layers.Dense(units=4, activation='relu', input_shape=[2]),
    layers.Dense(units=3, activation='relu'),
    # the linear output layer 
    layers.Dense(units=1),
])

查看类似激活函数图形

# YOUR CODE HERE: Change 'relu' to 'elu', 'selu', 'swish'... or something else
activation_layer = layers.Activation('swish')

x = tf.linspace(-3.0, 3.0, 100)
y = activation_layer(x) # once created, a layer is callable just like a function

plt.figure(dpi=100)
plt.plot(x, y)
plt.xlim(-3, 3)
plt.xlabel("Input")
plt.ylabel("Output")
plt.show()

Stochastic Gradient Descent

Use Keras and Tensorflow to train your first neural network.

训练数据需要做的事情:

  • A "loss function" that measures how good the network's predictions are.
  • An "optimizer" that can tell the network how to change its weights.

损失函数衡量目标的真实值与模型预测值之间的差距。优化器是一种调整权重以最小化损失的算法。

随机梯度下降一个步骤是这样的:

  • 对一些训练数据进行采样并在网络中运行以进行预测。
  • 测量预测值和真实值之间的损失。
  • 最后,向使损失更小的方向调整权重。

Learning Rate and Batch Size

学习率和小批量的大小是对 SGD 训练如何进行影响最大的两个参数。 它们的相互作用通常很微妙,这些参数的正确选择并不总是显而易见的。

幸运的是,对于大多数工作而言,无需进行广泛的超参数搜索即可获得满意的结果。 Adam 是一种 SGD 算法,具有自适应学习率,使其适用于大多数问题,无需任何参数调整(从某种意义上说,它是“自调整”)。 Adam 是一个很棒的通用优化器。

model.compile(
    optimizer="adam",
    loss="mae",
)

history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=256,
    epochs=10,
)

把迭代过程画出:

import pandas as pd

# convert the training history to a dataframe
history_df = pd.DataFrame(history.history)
# use Pandas native plot method
history_df['loss'].plot();
# 数据转换
# 对于数字类型,标准化
# 对于 category,做 OneHotEncoder
preprocessor = make_column_transformer(
    (StandardScaler(),
     make_column_selector(dtype_include=np.number)),
    (OneHotEncoder(sparse=False),
     make_column_selector(dtype_include=object)),
)

X = preprocessor.fit_transform(X)

通过不同参数画图来发现参数对于训练过程的影响

learning_rate batch_size num_examples
0.05 32 256
0.05 2 256
0.05 128 256
0.02 32 256
0.2 32 256
1.0 32 256
0.9 4096 8192
0.99 4096 8192
learning_rate = 0.02
batch_size = 32
num_examples = 256

animate_sgd(
    learning_rate=learning_rate,
    batch_size=batch_size,
    num_examples=num_examples,
    # You can also change these, if you like
    steps=50, # total training steps (batches seen)
    true_w=3.0, # the slope of the data
    true_b=2.0, # the bias of the data
)
  • learning_rate:越大,波动越大,收敛速度越快;太大,无法收敛,横跳
  • batch_size:越小,波动越大;越大,收敛速度慢,但是稳定

Overfitting and Underfitting

Improve performance with extra capacity or early stopping.

训练集欠拟合是指损失没有尽可能低,因为模型没有学到足够的信号(signal)。 过度拟合训练集是指损失没有达到应有的低,因为模型学习了太多噪声(noise)。 训练深度学习模型的诀窍是在两者之间找到最佳平衡。

Capacity

模型的容量是指它能够学习的模式的大小和复杂性。 对于神经网络,这在很大程度上取决于它有多少个神经元以及它们如何连接在一起。 如果您的网络似乎对数据欠拟合,您应该尝试增加其容量。

您可以通过使其更宽(对现有层添加更多单元)或使其更深(添加更多层)来增加网络的容量。 更宽的网络更容易学习更多的线性关系,而更深的网络更喜欢非线性关系。 哪个更好只取决于数据集。

Early Stopping

当模型过于急切地学习噪声时,验证损失可能会在训练期间开始增加。 为了防止这种情况,只要验证损失似乎不再减少,我们就可以简单地停止训练。 以这种方式中断训练称为提前停止。

from tensorflow.keras.callbacks import EarlyStopping

early_stopping = EarlyStopping(
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=20, # how many epochs to wait before stopping
    restore_best_weights=True,
)
history = model.fit(
    X_train, y_train,
    validation_data=(X_valid, y_valid),
    batch_size=256,
    epochs=500,
    callbacks=[early_stopping], # put your callbacks in a list
    verbose=0,  # turn off training log
)

history_df = pd.DataFrame(history.history)
history_df.loc[:, ['loss', 'val_loss']].plot();
print("Minimum validation loss: {}".format(history_df['val_loss'].min()))

学习数据化分:https://www.kaggle.com/code/jinxinc/exercise-overfitting-and-underfitting/edit

从曲线图分析是过拟合还是欠拟合

Dropout and Batch Normalization

Add these special layers to prevent overfitting and stabilize training.

Dropout

在训练的每一步随机丢弃一部分层的输入单元,使网络更难学习训练数据中的那些虚假模式。 相反,它必须搜索广泛的、通用的模式,其权重模式往往更稳健。

keras.Sequential([
    # ...
    layers.Dropout(rate=0.3), # apply 30% dropout to the next layer
    layers.Dense(16),
    # ...
])

Batch Normalization

SGD 将根据数据产生的激活大小按比例移动网络权重。 不同大小的激活的特征可能会导致不稳定的训练行为。

批归一化层会在每个批次进入时查看它,首先使用其自身的均值和标准差对批次进行归一化,然后使用两个可训练的重新缩放参数将数据置于新的尺度上。

layers.Dense(16, activation='relu'),
layers.BatchNormalization(),

如果您将它添加为网络的第一层,它可以充当一种自适应预处理器,代表 Sci-Kit Learn 的 StandardScaler 之类的东西。

Binary Classification

准确性(以及大多数其他分类指标)的问题在于它不能用作损失函数。 SGD 需要一个平滑变化的损失函数,但作为计数比率的准确度会“跳跃”变化。 所以,我们必须选择一个替代品来充当损失函数。 这个替代品是交叉熵函数。以 1.0 的概率预测正确的类别。 预测概率离 1.0 越远,交叉熵损失就越大。

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(4, activation='relu', input_shape=[33]),
    layers.Dense(4, activation='relu'),    
    layers.Dense(1, activation='sigmoid'),
])

model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['binary_accuracy'],
)

查看一些数据处理:https://www.kaggle.com/code/jinxinc/exercise-binary-classification/edit

# 处理数据映射
X['arrival_date_month'] = \
    X['arrival_date_month'].map(
        {'January':1, 'February': 2, 'March':3,
         'April':4, 'May':5, 'June':6, 'July':7,
         'August':8, 'September':9, 'October':10,
         'November':11, 'December':12}
    )

transformer_num = make_pipeline(
    SimpleImputer(strategy="constant"), # there are a few missing values
    StandardScaler(),
)
transformer_cat = make_pipeline(
    SimpleImputer(strategy="constant", fill_value="NA"),
    OneHotEncoder(handle_unknown='ignore'),
)

preprocessor = make_column_transformer(
    (transformer_num, features_num),
    (transformer_cat, features_cat),
)

Computer Vision

Build convolutional neural networks with TensorFlow and Keras.

最擅长此任务的神经网络称为卷积神经网络( convolutional neural networks)(有时我们会说 convnet 或 CNN。)卷积是赋予 convnet 各层独特结构的数学运算。 在以后的课程中,您将了解为什么这种结构在解决计算机视觉问题方面如此有效。

基用于从图像中提取特征。 它主要由执行卷积运算的层组成,但通常也包括其他类型的层。 (您将在下一课中了解这些内容。)

头部用于确定图像的类别。 它主要由致密层组成,但可能包括其他层,如 dropout。

The Convolutional Classifier

Create your first computer vision model with Keras.

Training the Classifier

训练期间网络的目标是学习两件事:

  1. 从图像中提取哪些特征(base)
  2. 哪个班级有什么特点(head)

如今,卷积神经网络很少从头开始训练。 更多时候,我们重用预训练模型的基础,然后,我们将一个未经训练的 head 连接到预训练的base。 换句话说,我们重用已经学会做的网络部分 1. 提取特征,并附加一些新的层来学习 2. Classify

重用预训练模型是一种称为迁移学习的技术。 它是如此有效,以至于现在几乎每个图像分类器都会使用它。

# step 1, load data

# step 2, define pretrained base
pretrained_base = tf.keras.models.load_model(
    '../input/cv-course-models/cv-course-models/vgg16-pretrained-base',
)
pretrained_base.trainable = False

# step 3, attach head
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    pretrained_base,
    # transforms the two dimensional outputs of the base into the one dimensional inputs needed by the head.
    layers.Flatten(),
    # head
    layers.Dense(6, activation='relu'),
    layers.Dense(1, activation='sigmoid'),
])

# step 4, train
# Since this is a two-class problem, we'll use the binary versions of crossentropy and accuracy
model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['binary_accuracy'],
)

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=30,
    verbose=0,
)

训练神经网络时,检查损失和度量图始终是个好主意。 历史对象在字典 history.history 中包含此信息。 我们可以使用 Pandas 将此字典转换为数据框并使用内置方法绘制它。

import pandas as pd

history_frame = pd.DataFrame(history.history)
history_frame.loc[:, ['loss', 'val_loss']].plot()
history_frame.loc[:, ['binary_accuracy', 'val_binary_accuracy']].plot();

这是深度神经网络相对于传统机器学习模型的一大优势:给定正确的网络结构,深度神经网络可以学习如何设计解决问题所需的特征。

训练损失和验证损失保持相当接近的证据表明该模型不仅仅是记住训练数据,而是学习这两个类的一般属性。 但是,由于该模型在比 VGG16 模型更大的损失下收敛,它可能欠拟合一些,并且可以从一些额外的容量中获益。

Convolution and ReLU

Discover how convnets create features with convolutional layers.

base 执行的特征提取包括三个基本操作:

  1. 针对特定特征过滤图像(卷积)
  2. 在过滤后的图像中检测该特征 (ReLU)
  3. 压缩图像以增强特征(最大池化)
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Conv2D(filters=64, kernel_size=3, activation='relu'), # activation is None
    # More layers follow
])

convnet 在训练期间学习的权重主要包含在其卷积层中。 我们称这些权重为 kernel。

使用 filters 参数,您可以告诉卷积层您希望它创建多少个特征映射作为输出。

example

# 1. filtering step
import tensorflow as tf

kernel = tf.constant([
    [-1, -1, -1],
    [-1,  8, -1],
    [-1, -1, -1],
])

plt.figure(figsize=(3, 3))
show_kernel(kernel)
image_filter = tf.nn.conv2d(
    input=image,
    filters=kernel,
    # we'll talk about these two in lesson 4!
    strides=1,
    padding='SAME',
)

plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_filter))
plt.axis('off')
plt.show();
# 2. detection step
image_detect = tf.nn.relu(image_filter)

plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_detect))
plt.axis('off')
plt.show();

现在我们已经创建了一个特征图! 这些图像是 head 用来解决其分类问题的图像。 我们可以想象,某些特征可能更具有汽车的特征,而其他特征可能更具有卡车的特征。 训练期间卷积网络的任务是创建可以找到这些特征的 Kernal。

the first two steps a convnet uses to perform feature extraction: filter with Conv2D layers and detect with relu activation.

这里有不少步骤(图片的变换)不知道在干嘛,以后再研究一下

最后有用 metrics 代替 image 来直观的展示 filter 和 detect 后的结果

Maximum Pooling

Learn more about feature extraction with maximum pooling.

请注意,在应用 ReLU 函数(检测)后,特征图最终会出现大量“死区”,即仅包含 0 的大区域(图像中的黑色区域)。 在整个网络中携带这些 0 激活会增加模型的大小,且不会添加太多有用的信息。 我们希望压缩特征图以仅保留最有用的部分——特征本身。

这实际上就是最大池化的作用。 最大池化在原始特征图中获取激活补丁,并用该补丁中的最大激活替换它们。

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Conv2D(filters=64, kernel_size=3), # activation is None
    layers.MaxPool2D(pool_size=2),
    # More layers follow
])
import tensorflow as tf

image_condense = tf.nn.pool(
    input=image_detect, # image in the Detect step above
    window_shape=(2, 2),
    pooling_type='MAX',
    # we'll see what these do in the next lesson!
    strides=(2, 2),
    padding='SAME',
)

plt.figure(figsize=(6, 6))
plt.imshow(tf.squeeze(image_condense))
plt.axis('off')
plt.show();

Translation Invariance

当 MaxPool2D 移除其中一些像素时,它会移除特征图中的一些位置信息。 这为卷积网络提供了一种称为平移不变性的属性。 这意味着具有最大池化的卷积网络往往不会根据图像中的位置来区分特征。

这种对特征位置微小差异的不变性对于图像分类器来说是一个很好的特性。 仅仅因为视角或框架的不同,相同类型的特征可能位于原始图像的不同部分,但我们仍然希望分类器能够识别它们是相同的。 因为这种不变性内置于网络中,我们可以使用更少的数据进行训练:我们不再需要教它忽略这种差异。 这使卷积网络比只有密集层的网络具有更大的效率优势。

Global Average Pooling

model = keras.Sequential([
    pretrained_base,
    layers.GlobalAvgPool2D(),
    layers.Dense(1, activation='sigmoid'),
])

我们不再有 Flatten 层,它通常位于 base 之后,用于将 2D 特征数据转换为分类器所需的 1D 数据。 现在 GlobalAvgPool2D 层正在提供这个功能。 但是,它不是“取消堆叠”特征(如 Flatten),而是简单地用其平均值替换整个特征图。 虽然非常具有破坏性,但它通常工作得很好并且具有减少模型中参数数量的优势。

假设有 8 个 5x5 的 feature map,通过 global pooling 之后,变成了 (1, 8),节省了 25 倍的 feature

通常,VGG16 会为每张图像生成 512 个特征图。 如果您愿意,GlobalAvgPool2D 层将这些中的每一个都减少到一个值,一个“平均像素”。

VGG16 基础生成 512 个特征图。 我们可以将每个特征图视为代表原始图像中的一些高级视觉特征——可能是轮子或窗户。 汇集一张地图给我们一个单一的数字,我们可以将其视为该特征的分数:如果该特征存在则大,如果不存在则小。 汽车往往在一组特征上得分高,而卡车在另一组特征上得分高。 现在,无需尝试将原始特征映射到类,head 只需处理 GlobalAvgPool2D 生成的这些分数,这是一个更容易解决的问题。

现代卷积网络中经常使用全局平均池化。 一个很大的优势是它大大减少了模型中的参数数量,同时仍然告诉您图像中是否存在某些特征——这对于分类通常是最重要的。 如果您正在创建一个卷积分类器,那么值得一试!

The Sliding Window

Explore two important parameters: stride and padding.

strides 参数表示窗口在每一步应该移动多远,padding 参数描述我们如何处理输入边缘的像素。

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Conv2D(filters=64,
                  kernel_size=3,
                  strides=1,
                  padding='same',
                  activation='relu'),
    layers.MaxPool2D(pool_size=2,
                     strides=1,
                     padding='same')
    # More layers follow
])

每当任一方向的步幅大于 1 时,滑动窗口将在每一步跳过输入中的一些像素。

因为我们想要高质量的特征用于分类,所以卷积层的步幅通常为 (1, 1)。 增加步幅意味着我们在摘要中错过了潜在有价值的信息。 然而,最大池化层几乎总是具有大于 1 的步幅值,如 (2, 2) 或 (3, 3),但不会大于窗口本身。

Growing the Receptive Field

不太明白(输入输出):https://www.kaggle.com/code/jinxinc/exercise-the-sliding-window/edit

也可以参考这篇:https://zhuanlan.zhihu.com/p/366184485

One-Dimensional Convolution

# kernel
detrend = tf.constant([-1, 1], dtype=tf.float32)
average = tf.constant([0.2, 0.2, 0.2, 0.2, 0.2], dtype=tf.float32)
spencer = tf.constant([-3, -6, -5, 3, 21, 46, 67, 74, 67, 46, 32, 3, -5, -6, -3], dtype=tf.float32) / 320
# UNCOMMENT ONE
kernel = spencer
# kernel = average
# kernel = spencer

# Reformat for TensorFlow
ts_data = machinelearning.to_numpy()
ts_data = tf.expand_dims(ts_data, axis=0)
ts_data = tf.cast(ts_data, dtype=tf.float32)
kern = tf.reshape(kernel, shape=(*kernel.shape, 1, 1))

ts_filter = tf.nn.conv1d(
    input=ts_data,
    filters=kern,
    stride=1,
    padding='VALID',
)

# Format as Pandas Series
machinelearning_filtered = pd.Series(tf.squeeze(ts_filter).numpy())

machinelearning_filtered.plot();

Custom Convnets

Design your own convnet.

# step 1, load data

# step 2, define cnn
from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([

    # First Convolutional Block
    layers.Conv2D(filters=32, kernel_size=5, activation="relu", padding='same',
                  # give the input dimensions in the first layer
                  # [height, width, color channels(RGB)]
                  input_shape=[128, 128, 3]),
    layers.MaxPool2D(),

    # Second Convolutional Block
    layers.Conv2D(filters=64, kernel_size=3, activation="relu", padding='same'),
    layers.MaxPool2D(),

    # Third Convolutional Block
    layers.Conv2D(filters=128, kernel_size=3, activation="relu", padding='same'),
    layers.MaxPool2D(),

    # Classifier Head
    layers.Flatten(),
    layers.Dense(units=6, activation="relu"),
    layers.Dense(units=1, activation="sigmoid"),
])
model.summary()

# step 3, train
model.compile(
    optimizer=tf.keras.optimizers.Adam(epsilon=0.01),
    loss='binary_crossentropy',
    metrics=['binary_accuracy']
)

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=40,
    verbose=0,
)

Data Augmentation

Boost performance by creating extra training data.

提高机器学习模型性能的最佳方法是在更多数据上对其进行训练。 模型需要学习的示例越多,它就越能识别图像中哪些差异重要,哪些不重要。 更多数据有助于模型更好地泛化。

获取更多数据的一种简单方法是使用您已有的数据。 如果我们可以以保留类别的方式转换数据集中的图像,我们就可以教我们的分类器忽略这些类型的转换。 例如,照片中的汽车是朝左还是朝右都不会改变它是汽车而不是卡车的事实。 所以,如果我们用翻转的图像来增强我们的训练数据,我们的分类器就会知道“左或右”是它应该忽略的差异。

每次在训练期间使用图像时,都会应用新的随机变换。 这样,模型总是看到与以前看到的有些不同的东西。 训练数据中的这种额外差异有助于在新数据上建立模型。

重要的是要记住,并非每个转换都对给定的问题有用。 最重要的是,无论您使用什么转换,都不应该混淆这些类。 例如,如果您正在训练数字识别器,则旋转图像会混淆“9”和“6”。 最后,找到好的增强的最佳方法与大多数 ML 问题相同:试试看!

Keras 允许您以两种方式扩充数据。 第一种方法是将其包含在数据管道中,并使用类似 ImageDataGenerator 的函数。 第二种方法是使用 Keras 的预处理层将其包含在模型定义中。

# step 1, load data
# step 2, Define model
from tensorflow import keras
from tensorflow.keras import layers
# these are a new feature in TF 2.2
from tensorflow.keras.layers.experimental import preprocessing


pretrained_base = tf.keras.models.load_model(
    '../input/cv-course-models/cv-course-models/vgg16-pretrained-base',
)
pretrained_base.trainable = False

model = keras.Sequential([
    # Preprocessing
    preprocessing.RandomFlip('horizontal'), # flip left-to-right
    preprocessing.RandomContrast(0.5), # contrast change by up to 50%
    # Base
    pretrained_base,
    # Head
    layers.Flatten(),
    layers.Dense(6, activation='relu'),
    layers.Dense(1, activation='sigmoid'),
])

# step 3, train and evaluate
model.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['binary_accuracy'],
)

history = model.fit(
    ds_train,
    validation_data=ds_valid,
    epochs=30,
    verbose=0,
)

模型的训练和验证曲线发散得相当快,表明它可以从一些正则化中获益。 该模型的学习曲线能够靠得更近,我们在验证损失和准确性方面取得了一些适度的改进。 这表明数据集确实从扩充中受益。

preprocessing image

# all of the "factor" parameters indicate a percent-change
augment = keras.Sequential([
    preprocessing.RandomContrast(factor=0.5),
    # preprocessing.RandomFlip(mode='horizontal'), # meaning, left-to-right
    # preprocessing.RandomFlip(mode='vertical'), # meaning, top-to-bottom
    # preprocessing.RandomWidth(factor=0.15), # horizontal stretch
    # preprocessing.RandomRotation(factor=0.20),
    preprocessing.RandomTranslation(height_factor=0.1, width_factor=0.1),
])


ex = next(iter(ds_train.unbatch().map(lambda x, y: x).batch(1)))

plt.figure(figsize=(10,10))
for i in range(16):
    image = augment(ex, training=True)
    plt.subplot(4, 4, i+1)
    plt.imshow(tf.squeeze(image))
    plt.axis('off')
plt.show()

数据增强是一种强大且常用的改进模型训练的工具,不仅适用于卷积网络,也适用于许多其他类型的神经网络模型。 无论您遇到什么问题,原则都是一样的:您可以通过添加“虚假”数据来弥补数据的不足。 试验增强是了解您的数据可以走多远的好方法!

Machine Learning Explainability

Extract human-understandable insights from any model.

Permutation Importance

What features does your model think are important?

核心思想:如果一个 feature 对模型很重要,那么对于原始数据集,打乱这个 feature 的值之后再进行预测,得到的 loss 会很大。对于每一个 feature 都进行这样的处理和计算,之后就能得到影响最大的 feature。

the process is as follows:

  1. Get a trained model.
  2. Shuffle the values in a single column, make predictions using the resulting dataset. Use these predictions and the true target values to calculate how much the loss function suffered from shuffling. That performance deterioration measures the importance of the variable you just shuffled.
  3. Return the data to the original order (undoing the shuffle from step 2). Now repeat step 2 with the next column in the dataset, until you have calculated the importance of each column.
import eli5
from eli5.sklearn import PermutationImportance

perm = PermutationImportance(my_model, random_state=1).fit(val_X, val_y)
eli5.show_weights(perm, feature_names = val_X.columns.tolist())

每行中的第一个数字显示随机改组后模型性能下降了多少(在这种情况下,使用“准确性”作为性能指标)。

与数据科学中的大多数事情一样,对列进行改组的确切性能变化存在一些随机性。 我们通过多次洗牌重复该过程来测量排列重要性计算中的随机性。 ± 后面的数字衡量性能从一次改组到下一次改组的变化情况。

偶尔会看到排列重要性的负值。 在这些情况下,对打乱(或嘈杂)数据的预测恰好比真实数据更准确。 当特征无关紧要(重要性应该接近 0)时会发生这种情况,但随机机会导致对混洗数据的预测更加准确。 这在小型数据集(如本例中的数据集)中更为常见,因为运气/机会的空间更大。

出租车示例

大多数地方不会根据乘客人数改变票价。但是在接触一个模型之前,不能假设纽约市是一样的,必须要根据实际情况来。

重点思考从结果如何分析可能性(下面第 2、3 条):

  1. 旅行的纬度距离可能比经度距离大。 如果经度值通常靠得更近,那么将它们改组就没有那么重要了。 2. 城市的不同地区可能有不同的定价规则(例如每英里的价格),并且定价规则因纬度而不是经度而异。 3. 向北<->向南(纬度变化)的道路收费可能高于向东<->向西(经度变化)的道路。 因此,纬度会对预测产生更大的影响,因为它反映了通行费的数量。

思考一下这几个问题:https://www.kaggle.com/code/jinxinc/exercise-permutation-importance/edit

Partial Plots

How does each feature affect your predictions?

While feature importance shows what variables most affect predictions, partial dependence plots show how a feature affects predictions.

要了解 Partial Plots 如何分离出每个特征的影响,我们首先考虑单行数据。 例如,该行数据可能代表一支球队有 50% 的控球时间、传球 100 次、射门 10 次并打进 1 球。

我们将使用拟合模型来预测我们的结果(他们的球员赢得“比赛最佳球员”的概率)。 但是我们反复更改一个变量的值以进行一系列预测。 如果球队只有 40% 的时间控球,我们就可以预测结果。 然后我们预测他们有 50% 的时间控球。 然后再次预测 60%。 等等。 当我们从控球率的小值移动到大值(在水平轴上)时,我们追踪预测结果(在垂直轴上)。

在这个描述中,我们只使用了一行数据。 特征之间的相互作用可能导致单行图不典型。 因此,我们用原始数据集中的多行重复该心理实验,并在垂直轴上绘制平均预测结果。

from matplotlib import pyplot as plt
from pdpbox import pdp, get_dataset, info_plots

# Create the data that we will plot
pdp_goals = pdp.pdp_isolate(model=tree_model, dataset=val_X, model_features=feature_names, feature='Goal Scored')

# plot it
pdp.pdp_plot(pdp_goals, 'Goal Scored')
plt.show()
# Similar to previous PDP plot except we use pdp_interact instead of pdp_isolate and pdp_interact_plot instead of pdp_isolate_plot
features_to_plot = ['Goal Scored', 'Distance Covered (Kms)']
inter1  =  pdp.pdp_interact(model=tree_model, dataset=val_X, model_features=feature_names, features=features_to_plot)

pdp.pdp_interact_plot(pdp_interact_out=inter1, feature_names=features_to_plot, plot_type='contour')
plt.show()

考虑一个场景,你只有 2 个预测特征,我们称之为 feat_A 和 feat_B。 这两个特征的最小值为 -1,最大值为 1。feat_A 的部分依赖图在其整个范围内急剧增加,而特征 B 的部分依赖图在其整个范围内以较慢的速度(不太陡峭)增加。

这是否保证 feat_A 的排列重要性高于 feat_B。 为什么或者为什么不?

不,这并不能保证 feat_a 更重要。 例如,feat_a 在变化的情况下可能会产生很大影响,但在 99% 的情况下可能只有一个值。 在那种情况下,置换 feat_a 并不重要,因为大多数值都不会改变。

重新理解一下:https://www.kaggle.com/code/jinxinc/exercise-partial-plots/edit

SHAP Values

Understand individual predictions

使用场景:

  • 一个模型说银行不应该借钱给某人,并且法律要求银行解释每笔贷款拒绝的依据
  • 医疗保健提供者想要确定哪些因素导致每位患者患某种疾病的风险,以便他们可以通过有针对性的健康干预措施直接解决这些风险因素
import shap  # package used to calculate Shap values

# Create object that can calculate shap values
explainer = shap.TreeExplainer(my_model)

# Calculate Shap values
shap_values = explainer.shap_values(data_for_prediction)

shap.initjs()
shap.force_plot(explainer.expected_value[1], shap_values[1], data_for_prediction)
  • shap.DeepExplainer works with Deep Learning models.
  • shap.KernelExplainer works with all models, though it is slower than other Explainers and it offers an approximation rather than exact Shap values.
# use Kernel SHAP to explain test set predictions
k_explainer = shap.KernelExplainer(my_model.predict_proba, train_X)
k_shap_values = k_explainer.shap_values(data_for_prediction)
shap.force_plot(k_explainer.expected_value[1], k_shap_values[1], data_for_prediction)

参考:

了解 3 个方法的关系:https://www.kaggle.com/code/jinxinc/exercise-shap-values/edit

Advanced Uses of SHAP Values

Aggregate SHAP values for even more detailed model insights

Summary Plots

Permutation importance 非常重要,因为它创建了简单的数字度量来查看哪些特征对模型很重要。 这有助于我们轻松地对功能进行比较,并且您可以将生成的图表展示给非技术人员。

但它并没有告诉您每个功能的重要性。 如果一个特征具有中等排列重要性,那可能意味着它有

  • 对一些预测有很大影响,但总体上没有影响,或者
  • 所有预测的中等效果。

SHAP 摘要图为我们提供了特征重要性及其驱动因素的鸟瞰图。

import shap  # package used to calculate Shap values

# Create object that can calculate shap values
explainer = shap.TreeExplainer(my_model)

# calculate shap values. This is what we will plot.
# Calculate shap_values for all of val_X rather than a single row, to have more data for plot.
shap_values = explainer.shap_values(val_X)

# Make plot. Index of [1] is explained in text below.
shap.summary_plot(shap_values[1], val_X)
  • 绘图时,我们调用 shap_values[1]。 对于分类问题,每个可能的结果都有一个单独的 SHAP 值数组。 在这种情况下,我们索引以获得预测“真”的 SHAP 值。
  • 计算 SHAP 值可能很慢。 这在这里不是问题,因为这个数据集很小。 但是在运行这些以使用合理大小的数据集进行绘图时,您需要小心。 例外情况是使用 xgboost 模型时,SHAP 对其进行了一些优化,因此速度更快。

SHAP Dependence Contribution Plots

Summary Plots 提供了模型的一个很好的概述,但我们可能想深入研究一个功能。 这就是 SHAP dependence contribution plots 发挥作用的地方。

分析异常点:

  1. 控球时间的增加并没有导致 SHAP 增加,可以将其解释为一般来说,拥有球会增加球队让其球员赢得奖项的机会。 但如果他们只进了一个球,那么这种趋势就会逆转,如果他们进得那么少,评委可能会因为他们控球太多而对他们进行处罚。
import shap  # package used to calculate Shap values

# Create object that can calculate shap values
explainer = shap.TreeExplainer(my_model)

# calculate shap values. This is what we will plot.
shap_values = explainer.shap_values(X)

# make plot.
shap.dependence_plot('Ball Possession %', shap_values[1], X, interaction_index="Goal Scored")

思考这几个问题:https://www.kaggle.com/code/jinxinc/exercise-advanced-uses-of-shap-values/edit

由于效果范围对异常值非常敏感,因此排列重要性可以更好地衡量对模型通常重要的内容。

特征的高值和低值都可能对预测产生正面和负面影响。 对这种“混乱”效果的最可能解释是变量(在本例中为 num_lab_procedures)与其他变量有交互作用

Data Cleaning

Master efficient workflows for cleaning real-world, messy data.

Handling Missing Values

Drop missing values, or fill them in with an automated workflow.

有多少数据缺失值?

  1. 每个 field 有多少数据没有值?df.isnull().sum()
  2. 没有值的数据占比多少?df.isnull().sum().sum()/np.product(df.shape)*100

找出数据缺失的原因

  1. 数据确实不存在(比如没有小孩,就没有小孩的升高数据)-> 保持 NA 或者添加一个其他的值代表
  2. 数据没有收集。-> imputation

阅读数据说明文档,了解数据很重要!

粗暴的解决方案:

  • 丢掉有缺失值的行:df.drnpa()
  • 丢掉有缺失值的列:df.dropna(axis=1)
  • 用特定值填充:df.fillna(0)
  • 用后面一条数据的值填充:df.fillna(method='bfill', axis=0).fillna(0)

Scaling and Normalization

Transform numeric variables to have helpful properties.

  • in scaling, you're changing the range of your data, while

  • in normalization, you're changing the shape of the distribution of your data.

  • 缩放数据:minmax_scaling(original_data, columns=[0])

  • 使用 boxcox 正则化数据:stats.boxcox(df)

Parsing Dates

Help Python recognize dates as composed of day, month, and year.

参考格式:https://strftime.org

  1. 使用固定格式:pd.to_datetime(landslides['date'], format="%m/%d/%y")
  2. 让 pd 自动推导:pd.to_datetime(landslides['Date'], infer_datetime_format=True)
    1. 并不是所有的时候都能成功
    2. 速度比指定格式慢
  3. 获取 day:landslides['date_parsed'].dt.day

在处理时间栏位之前,可以先检查一下时间栏位的长度来判断是否有不同的格式:earthquakes.Date.str.len().value_counts()

Character Encodings

Avoid UnicoodeDecodeErrors when loading CSV files.

可以在编码的时候把不支持的字符自动替换,不会出错但是丢失信息:after = before.encode("ascii", errors = "replace")

当我们不知道编码的时候,两种方法:1、尝试多种编码;2、chardet automatically guess(不是 100% 准确)

通常情况下,我们只需要扫描档案的前面一部分数据:

with open("../input/kickstarter-projects/ks-projects-201801.csv", 'rb') as rawdata:
    result = chardet.detect(rawdata.read(10000))

Inconsistent Data Entry

Efficiently fix typos in your data.

  1. 统一大小写(' Germany', and 'germany')
  2. 删除前后空格(strip())
  3. 使用 fuzzywuzzy 来计算相似度
    1. fuzzywuzzy.process.extract("south korea", countries, limit=10, scorer=fuzzywuzzy.fuzz.token_sort_ratio)

Intro to AI Ethics

Explore practical tools to guide the moral design of AI systems.

  1. 理清用户的需求,定义问题
  2. 询问 AI 是否为任何潜在解决方案增加了价值
    1. 有好的产出?
    2. 非人工智能系统比 AI 效率低的多?
    3. 替换无聊重复的任务?
    4. AI 方案已被证明比其他方案更好?
  3. 考虑人工智能系统可能造成的潜在危害
    1. 比如作文打分系统,可以让学生摸索出一些特定的得高分的模式
  4. 从非人工智能解决方案开始先定义好原型,及早获得反馈和改善
  5. 提供人们挑战系统的途径,不断改善
  6. 建立安全措施

Identifying Bias in AI

Bias can creep in at any stage in the pipeline. Investigate a simple model that identifies toxic text.

  1. 历史偏差
  2. 表示偏差(训练数据不足)
  3. 测量偏差(当数据的准确性因组而异时,就会出现测量偏差。比如黑人看病贵)
  4. 聚合偏差(群体组合不当时)
  5. 评价偏差(如果基准数据不代表模型将服务的人群,面部识别用白人图片,来识别黑人)
  6. 部署偏差(当模型旨在解决的问题与其实际使用方式不同时)

这些偏差通常在 ML workflow 的不同步骤出现:https://www.kaggle.com/code/alexisbcook/identifying-bias-in-ai/tutorial

测试你的理解:https://www.kaggle.com/code/jinxinc/exercise-identifying-bias-in-ai/edit

Explore practical tools to guide the moral design of AI systems.

AI Fairness

Learn about four different types of fairness. Assess a toy model trained to judge credit card applications.

4 个标准:

  1. 人口统计平等(男女各一半)
  2. 机会均等(
  3. 等精度
  4. 不知情的公平

Intro to Game AI and Reinforcement Learning

Build your own video game bots, using classic and cutting-edge algorithms.

  1. 从横向、纵向、斜向找到可以赢的位置,自己下或者阻止对方下
  2. 启发式,考虑后面 1 步棋,遍历所有可能的下棋位置,算出对应分数
    1. 连 4 得 100000 分
    2. 连活 3 得 1 分
    3. 对方活 4 得 -100 分
  3. 启发式,考虑后面 3 步棋,考虑对手最优位置,利用 minmax 来计算最优解
  4. cnn,定义 loss function,让 cnn 自动优化 weight

有一点要小心,如果在只考虑 1 步的情形下,算出来的分数,下了棋之后,可能会让对手赢(对方正好形成活 4)

⚠️ **GitHub.com Fallback** ⚠️