CNN:计算机真的能看见吗?
卷积神经网络讲解!
卷积神经网络(CNN 或 ConvNet)是一类深度学习,受人类视觉系统的启发,专门从图像、文本和音频等复杂输入中提取高级特征。
事实上,与手工设计特征的经典神经网络不同,CNN 获取输入的原始数据,自动区分有意义的模式,并基于这些特征而不是原始像素进行学习。这就是为什么 CNN 是图像分析中经常使用的神经网络[1]。
但是计算机如何分析图像呢?
基本上,卷积神经网络主要包括:
- 输入图层
- 卷积层
- 激活功能层
- 汇集层
- 展平全连通图层
我们先从 CNN 的输入层开始,来了解计算机是如何看到一个图像的。
输入层:
图像通常表示为像素值的三维(3D)矩阵:
- 高度和宽度取决于输入图像的尺寸。
- 深度一般是三通道 RGB(红绿蓝)对于每个像素的颜色值。
*作者的图像:*图像表示的示例
卷积层:
卷积运算是 Y. Bengio 和 Yann Lecun 发明的 CNN 的基本组成部分[2],它包括对输入图像应用滤波器以检测与每一类相关的特征。
*图片作者:*9 像素的红色通道图片
滤波器(固定大小)由随机初始化的权重组成,这些权重将通过每个输入的反向传播来更新。
滤镜以步长(卷积中跳过的像素数)垂直和水平滑动图像,将图像的“像素”值乘以滤镜的值。然后,将所有这些乘法相加得到一个数,该数构成特征图的一个像素。
*图片作者:*水平滑动操作
*图片作者:*垂直滑动操作
在卷积过程结束时,所获得的特征图表示包含输入图像的检测模式的较小矩阵。
显然,我们对图像应用的过滤器越多,提取的特征就越多,网络在检测图像模式方面就变得越好。
最后,卷积层由相同大小的多个滤波器组成,这些滤波器从图像的 3D 通道表示的输入输出各种特征图。下图对此进行了总结:
作者图片:步长=1、滤波器大小=33 的 99 像素输入图像的卷积层
ReLU 的非线性:
考虑到真实世界数据的非线性,我们必须在每个卷积层之后引入一层激活函数,因为卷积是线性运算(乘法和加法)。
事实上,通过增加网络的非线性,我们创建了一个复杂的网络,使我们能够检测和区分输入图像的许多模式。
该任务最常用的激活函数是 ReLU 16。数学上,它被定义为:
作者图片
由于它的数学特性,它是一种元素式操作(在我们的例子中应用于每个像素),在特征图中用零替换负像素的值。
池层:
类似于卷积层,池层用于独立地进一步降低先前矩阵的维度(维度降低),以显著降低数据处理所需的参数数量和计算能力。
此外,该操作从输入中提取主导特征,同时保持有效训练模型的过程,因为网络对于输入图像的小变换和平移变得不变。
作者图片:使用最大池化方法,使用步长 2 和大小 33 的过滤器,对 77 像素的输入图像进行池化图层
可以通过多种方法完成汇集:最大汇集、最小汇集、平均汇集和平均汇集。最常用的方法是最大池化。
展平和完全连接的层:
卷积层和池层的组合从输入图像中提取主要特征到一个数量的矩阵,然后 flatten 将其转换为一个一维数组,创建一个适合于全连接层的输入的单一长特征向量。
全连接层完成分类的任务,它代表一个多层感知器,主要具有 softmax 激活功能。然后,网络将能够学习高级特征的非线性组合,并区分每个图像规格。
*作者图片:*展平并完全连接的图层示例
总而言之,CNN 架构执行两个主要任务:
- 特征提取:卷积层+池层
- 分类:全连接层
这张图片展示了 CNN 的完整架构:
*图片作者:CNN 架构概要以 99 像素输入为例
一般来说,卷积层数越多,模型能够识别的特征就越多。
参考资料:
[1] Maria Valueva,Nikolay Nagornov,Pavel Lyakhov,G.V. Valuev,和 N.I.Chervyakov .应用剩余数系统减少卷积神经网络实现的硬件成本数学和计算机模拟,177,05 2020。
[2] Y .本吉奥和扬·勒昆。图像、语音和时间序列的卷积网络。11 1997.
[3]田畑秀则·伊德。还有栗田泷雄。稀疏正则化对 relu 激活的 cnn 学习的改进。IEEE,2017 年 07 月。
基于 CNN-LSTM 的多并行输入多步预报模型
针对多个时间序列和多步预测用例的不同神经网络方法,以及多步预测的真实实践
时间序列预测是机器学习的一个非常热门的领域。这背后的原因是时间序列在日常生活中几乎每个领域的广泛使用。深入时间序列预测的细节,我们会遇到许多不同种类的子领域和方法。在本文中,我将关注通过接收多个并行时间序列来执行多步预测的特定子域,并提及在时间序列预测中应考虑的基本要点。请注意,预测模型在不同点上与预测模型不同。
法鲁克·凯马克在 Unsplash 上拍摄的照片
-问题定义
让我们想象一下,大量网络设备分布在广阔的地理区域内,流量不断地流经这些设备。另一个例子可能是关于连续测量不同位置的天气温度的许多不同温度设备,或者另一个例子可能是计算系统中许多设备的能量消耗。我们可以很容易地扩展这些例子。目标很简单;预测接下来的多个时间步;在我们的例子中,这对应于分别预测流量值、温度或许多设备的能耗。
首先想到的当然是分别对每个器件建模。我想我们可能会得到最高的预测结果。如果有超过 100 种甚至更多的不同设备呢?这意味着设计 100 种不同的模型。考虑到部署、监控和维护成本,它并不太适用。因此,我们的目标是用一个单一的模型来涵盖整个问题。我认为它仍然是时间序列预测的一个非常受欢迎和搜索的领域,尽管时间序列预测已经摆在桌面上很久了。我在这个领域遇到了很多不同的学术研究。
这个问题也可以定义为 seq2seq 预测。特别是在语音识别和翻译中,这是非常常见的情况。 LSTM 对于这类问题非常方便。 CNN 也可以认为是另一种类型的神经网络,常用于图像处理任务。通常,它也用于特征提取和时间序列预测。我将提到 LSTM 和 CNN 在多个并行输入和多步预测情况下对时间序列预测的应用。对 LSTM 和 CNN 的解释超出了本文的范围。
为了更清楚,我在下面描绘了一个简单的数据示例。这是一个通过查看前 3 个小时的时隙来预测未来 2 个小时 3 个不同设备的流量值的示例。
作者图片—图 1
-数据集描述
在本文中,我将利用由 15 分钟时间间隔内 288 台不同服务器的 CPU 使用情况组成的数据集。为简单起见,我将把范围缩小到 3 台服务器。
数据集示例,按作者分类的图像—图 2
-预建模步骤
预建模在神经网络实现中非常关键。你通常不能简单地直接向神经网络提供原始数据,需要一个简单的转换。然而,在转换之前,我们应该对原始数据应用一些额外的步骤。
在我们的例子中,下面是旋转原始数据。
df_cpu_pivot = pd.pivot_table(df, values=’CPUUSED’,
index=[‘DATETIME’], columns=[‘ID’])
以下是对数据集中缺失值的插值。在时间序列中输入空值本身是非常重要的,也是一项具有挑战性的任务。这个数据集中没有很多空值,输入空值超出了本文的范围,因此我执行了一个简单的实现。
for i in range(0, len(df_cpu_pivot.columns)):
df_cpu_pivot.iloc[:,i].interpolate(inplace = True)
在进入建模阶段之前的第一件事,在时间序列预测的数据预处理步骤的最开始,在我看来是绘制时间序列。让我们看看数据告诉了我们什么。正如我之前提到的,为了简单起见,我只选择了 3 个不同的服务器。可以看出,它们在不同的尺度上都遵循非常相似的模式。
import plotly
import plotly.express as px
import plotly.graph_objects as godf_cpu_pivot.reset_index(inplace=True)
df_cpu_pivot['DATETIME'] = pd.to_datetime(df_cpu_pivot['DATETIME'])trace1 = go.Scatter(
x = df_cpu_pivot[‘DATETIME’],
y = df_cpu_pivot[‘HSSFE-hssahlk01CPU-0’],
mode = ‘lines’,
name = ‘cpu_1’
)
trace2 = go.Scatter(
x = df_cpu_pivot[‘DATETIME’],
y = df_cpu_pivot[‘HSSFE-hssumrk03CPU-29’],
mode = ‘lines’,
name = ‘cpu_2’
)
trace3 = go.Scatter(
x = df_cpu_pivot[‘DATETIME’],
y = df_cpu_pivot[‘HSSFE-hssumrk03CPU-4’],
mode = ‘lines’,
name = ‘cpu_3’
)layout = go.Layout(
title = “CPU Usage”,
xaxis = {‘title’ : “Date”},
yaxis = {‘title’ : “Cpu Usage”}
)
fig = go.Figure(data=[trace1, trace2, trace3], layout=layout)
fig.show()
Cpu 使用情况—图 3
下一步是将数据集分成训练集和测试集。它在时间序列上与传统的机器学习实现略有不同。我们可以直观地确定分离数据集的拆分日期。
from datetime import datetime
train_test_split = datetime.strptime(‘20.04.2020 00:00:00’, ‘%d.%m.%Y %H:%M:%S’)
df_train = df_cpu_pivot.loc[df_cpu_pivot[‘DATETIME’] < train_test_split]
df_test = df_cpu_pivot.loc[df_cpu_pivot[‘DATETIME’] >= train_test_split]
由于其敏感性,我们还在将数据输入任何神经网络模型之前对其进行归一化。
from sklearn.preprocessing import MinMaxScaler
cpu_list = [i for i in df_cpu_pivot.columns if i != ‘DATETIME’]
scaler = MinMaxScaler()
scaled_train = scaler.fit_transform(df_train[cpu_list])
scaled_test = scaler.transform(df_test[cpu_list])
最后一步是将训练集和测试集转换成神经网络可接受的格式。可以实现以下方法来转换数据。除了序列本身,它只需要两个参数,分别是时滞(回顾的步骤)和预测范围。还可以看看 Keras 中定义的 TimeSeriesGenerator 类来转换数据集。
def split_sequence(sequence, look_back, forecast_horizon):
X, y = list(), list()
for i in range(len(sequence)):
lag_end = i + look_back
forecast_end = lag_end + forecast_horizon
if forecast_end > len(sequence):
break
seq_x, seq_y = sequence[i:lag_end], sequence[lag_end:forecast_end]
X.append(seq_x)
y.append(seq_y)
return np.array(X), np.array(y)
LSTM 模型期望数据具有以下形状:*【样本,时间步长,特征】。*同样,CNN 也期望 3D 数据为 LSTMs。
# Take into consideration last 6 hours, and perform forecasting for next 1 hour
LOOK_BACK = 24
FORECAST_RANGE = 4
n_features = len(cpu_list)X_train, y_train = split_sequence(scaled_train, look_back=LOOK_BACK, forecast_horizon=FORECAST_RANGE)
X_test, y_test = split_sequence(scaled_test, look_back=LOOK_BACK, forecast_horizon=FORECAST_RANGE)print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)(4869, 24, 3)
(4869, 4, 3)
(1029, 24, 3)
(1029, 4, 3)
补充说明
我还想提一下时间序列预测的额外预建模步骤。这些不是本文的直接范围,但值得了解。
平稳对于时间序列来说是一个非常重要的问题,大多数预测算法如 ARIMA 都期望时间序列是平稳的。平稳时间序列基本上在一段时间内保持非常相似的均值、方差值,不包括季节性和趋势。要使时间序列平稳,最直接的方法是取序列中后续值的差。如果方差与均值相比波动很大,取序列的对数使其平稳也是一个好主意。与大多数其他预测算法不同,LSTMs 能够学习序列中的非线性和长期相关性。因此,静态是 LSTMs 不太关心的问题。尽管如此,让时间序列保持平稳并稍微提高 LSTMs 的性能是一个很好的实践。静态测试有很多,最著名的是 增强的 Dicky-Fuller 测试 ,在 python 中有现成的实现。
这里有一篇很优秀的文章,简单的设计了一个模型来预测一个随机游走过程产生的时间序列,评价准确率非常高。事实上,预测随机行走过程是不可能的。但是,如果您直接使用原始数据而不是静态差异数据,可能会出现这种误导性的推断。
关于时间序列要提到的另一件事是绘制 ACF 和PACF图,并研究时间序列相对于不同历史滞后值的相关性。这肯定会让你深入了解你正在处理的时间序列。
-基线模型
拥有一个基线模型来衡量你的模型的相对性能总是一个好主意。基线模型应该简单、快速且可重复。建立基线模型最常用的方法是持久性模型。它有一个非常简单的工作原理,只是预测下一个时间步为前一步,换句话说 t+1 与 t 相同。对于多步预测,可能将预测 t+1,t+2,t+3 修改为 t ,整个预测范围将是相同的。在我看来,那不太合理。相反,我更喜欢将预测范围内的每个时间步长预测为相同设备之前相同时间的平均值。下面是一个简单的代码片段。
df[‘DATETIME’] = pd.to_datetime(df[‘DATETIME’])
df[‘hour’] = df[‘DATETIME’].apply(lambda x: x.hour)
df[‘minute’] = df[‘DATETIME’].apply(lambda x: x.minute)train_test_split = datetime.strptime(‘20.04.2020 00:00:00’, ‘%d.%m.%Y %H:%M:%S’)
df_train_pers = df.loc[df[‘DATETIME’] < train_test_split]
df_test_pers = df.loc[df[‘DATETIME’] >= train_test_split]df_cpu_mean = df_train_pers.groupby([‘ID’, ‘hour’, ‘minute’]).mean(‘CPUUSED’).round(2)df_cpu_mean.reset_index(inplace=True)
df_cpu_mean = df_cpu_mean.rename(columns={“CPUUSED”: “CPUUSED_PRED”})df_test_pers = df_test_pers.merge(df_cpu_mean, on=[‘ID’,’hour’, ‘minute’], how=’inner’)# the method explanation is at the next section
evaluate_forecast(df_test_pers[‘CPUUSED’], df_test_pers[‘CPUUSED_PRED’])mae: 355.13
mse: 370617.18
mape: 16.56
可以看出,我们的基线模型预测误差约为 16.56%。我将在模型部分的评估中详细介绍评估指标。让我们看看我们是否能超过这个结果。
-不同的模型示例
我将提到用于*多个并行输入和多步预测的不同的基于神经网络的模型。*在描述模型之前,让我分享一些常见的东西和代码片段,比如 Keras 回调、应用逆变换以及评估结果。
编译模型时使用的回调如下。model check point是以一定的频率保存模型(权重)。 提前停止 用于在监控的评估指标不再提高时停止进度。ReduceLROnPlateau用于在监控指标停止改善时降低学习率。
checkpoint_filepath = ‘path_to_checkpoint_filepath’
checkpoint_callback = ModelCheckpoint(
filepath=checkpoint_filepath,
save_weights_only=False,
monitor=’val_loss’,
mode=’min’,
save_best_only=True)early_stopping_callback = EarlyStopping(
monitor=”val_loss”,
min_delta=0.005,
patience=10,
mode=”min”
)rlrop_callback = ReduceLROnPlateau(monitor=’val_loss’, factor=0.2, mode=’min’, patience=3, min_lr=0.001)
由于我们在将数据输入模型之前对其进行了规范化,因此我们应该将其转换回原始比例以评估预测。我们可以简单地利用下面的方法。在对数据进行差分以使其稳定的情况下,您应该首先反转缩放,然后依次反转差分。预测的顺序与此相反,即首先应用差异,然后归一化数据。为了反演差异数据,简单的方法是将差异预测累加到最后的累积观测值上。
def inverse_transform(y_test, yhat):
y_test_reshaped = y_test.reshape(-1, y_test.shape[-1])
yhat_reshaped = yhat.reshape(-1, yhat.shape[-1]) yhat_inverse = scaler.inverse_transform(yhat_reshaped)
y_test_inverse = scaler.inverse_transform(y_test_reshaped)
return yhat_inverse, y_test_inverse
为了评估预测,我简单地分别考虑了均方误差(mse)、平均绝对误差(mae)、和平均绝对百分比误差(mape) 。您可以扩展评估指标。注意,均方根误差(rmse)和 mae 给出的误差与变量本身的单位相同,并被广泛使用。在本文中,我将根据 mape 来比较这些模型。
def evaluate_forecast(y_test_inverse, yhat_inverse):
mse_ = tf.keras.losses.MeanSquaredError()
mae_ = tf.keras.losses.MeanAbsoluteError()
mape_ = tf.keras.losses.MeanAbsolutePercentageError() mae = mae_(y_test_inverse,yhat_inverse)
print('mae:', mae)
mse = mse_(y_test_inverse,yhat_inverse)
print('mse:', mse)
mape = mape_(y_test_inverse,yhat_inverse)
print('mape:', mape)
常见的导入包如下。
from tensorflow.keras import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout, TimeDistributed, Conv1D, MaxPooling1D, Flatten, Bidirectional, Input, Flatten, Activation, Reshape, RepeatVector, Concatenate
from tensorflow.keras.models import Modelfrom tensorflow.keras.utils import plot_modelfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint
在这一步,我认为在 Keras 中提及 时间分布 和 重复向量 层是有益的。这些不是经常使用的层,但是,它们在一些特定的情况下可能非常有用,比如我们的例子。
简而言之, TimeDistributed 层是一种包装器,并期望另一层作为参数。它将该层应用于输入的每个时间片,因此允许构建具有一对多、多对多架构的模型。类似地,它期望输入至少是三维的。我知道这对于初学者来说不是很清楚,你可以在这里找到有用的讨论。
重复矢量基本上重复输入 n 次。换句话说,它将输出形状的维度增加了 1。重复向量 在这里有很好的解释和图解,看看吧。
epochs = 50
batch_size = 32
validation = 0.1
以上是为编译模型而定义的。
编解码器型号
model_enc_dec = Sequential()
model_enc_dec.add(LSTM(100, activation=’relu’, input_shape=(LOOK_BACK, n_features)))
model_enc_dec.add(RepeatVector(FORECAST_RANGE))
model_enc_dec.add(LSTM(100, activation=’relu’, return_sequences=True))
model_enc_dec.add(TimeDistributed(Dense(n_features)))
model_enc_dec.compile(optimizer=’adam’, loss=’mse’)plot_model(model=model_enc_dec, show_shapes=True)history = model_enc_dec.fit(X_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=validation,callbacks=[early_stopping_callback, checkpoint_callback, rlrop_callback])yhat = model_enc_dec.predict(X_test, verbose=0)yhat_inverse, y_test_inverse = inverse_transform(y_test, yhat)evaluate_forecast(y_test_inverse, yhat_inverse)mae: 145.95
mse: 49972.53
mape: 7.40
编码器-解码器模型—图 4
编码器-解码器架构是序列到序列学习的典型解决方案。该架构包含至少两个 RNN/lstm,其中一个用作编码器,而另一个用作解码器。编码器主要负责读取和解释输入。编码器部分将输入压缩成原始输入的小型表示(固定长度的向量),并将该上下文向量作为输入提供给解码器部分进行解释和执行预测。一个 RepeatVector 层用于重复我们从编码器部分获得的上下文向量。它会根据您想要预测的未来步骤数进行重复,并输入到解码器部分。就每个时间步长而言,从解码器接收的输出被混合。一个完全连接的密集层通过时间分布包装器被应用于每个时间步长,从而分离每个时间步长的输出。在每个编码器和解码器中,可以使用不同种类的架构。下一部分给出了一个例子,其中 CNN 被用作编码器中的特征提取器。
CNN-LSTM 编解码器型号
以下模型是编码器-解码器架构的扩展,其中编码器部分由 Conv1D 层组成,与之前的模型不同。首先在开头放置两个后续的 Conv1D 层提取特征,然后在汇集 *Conv1D 的结果后将其展平。*架构的其余部分与之前的模型非常相似。
为了简单起见,我只是不分享绘图,模型的拟合,测试集的预测,以及逆向转换步骤,这些将与模型的其余部分完全相同。
model_enc_dec_cnn = Sequential()
model_enc_dec_cnn.add(Conv1D(filters=64, kernel_size=9, activation=’relu’, input_shape=(LOOK_BACK, n_features)))
model_enc_dec_cnn.add(Conv1D(filters=64, kernel_size=11, activation=’relu’))
model_enc_dec_cnn.add(MaxPooling1D(pool_size=2))
model_enc_dec_cnn.add(Flatten())
model_enc_dec_cnn.add(RepeatVector(FORECAST_RANGE))
model_enc_dec_cnn.add(LSTM(200, activation=’relu’, return_sequences=True))
model_enc_dec_cnn.add(TimeDistributed(Dense(100, activation=’relu’)))
model_enc_dec_cnn.add(TimeDistributed(Dense(n_features)))
model_enc_dec_cnn.compile(loss=’mse’, optimizer=’adam’)mae: 131.89
mse: 50962.38
mape: 7.01
CNN 编码器-解码器模型—图 5
矢量输出模式
与上面提到的模型相比,这种架构可能被认为是更常见的架构,但是,它不太适合我们的情况。不过,我分享一个例子来说明一下。与编码器-解码器架构不同,既不存在重复向量也不存在时间分布层。重点是用 FORECAST_RANGE*n_features 节点添加一个 Dense 图层,然后在下一层做相应的整形。你也可以用 RepeatVector 层代替 Reshape 层来设计一个类似的架构。
在这种结构中,每个序列的时间步长将被展平,并且在训练和预测期间,必须将每个输出解释为特定序列的特定时间步长。这意味着我们也可以将标注集调整为二维而不是三维,并相应地解释输出图层中的结果,而无需使用调整图层。为了简单起见,我没有改变标签集的形状,只是记住这种替代方式。在架构的开始,我还利用了 Conv1D 层。
这种结构也可以称为多通道模型。不要高估名字。在处理多个时间序列时,传统上使用多通道的细胞神经网络。在这种结构中,每个通道对应于单个时间序列,并且类似地为每个时间序列分别提取卷积特征。由于所有提取的特征在输入到 LSTM 图层之前会被合并,因此每个时间序列的一些典型特征可能会丢失。
input_layer = Input(shape=(LOOK_BACK, n_features))
conv = Conv1D(filters=4, kernel_size=7, activation=’relu’)(input_layer)
conv = Conv1D(filters=6, kernel_size=11, activation=’relu’)(conv)lstm = LSTM(100, return_sequences=True, activation=’relu’)(conv)
dropout = Dropout(0.2)(lstm)
lstm = LSTM(100, activation=’relu’)(dropout)
dense = Dense(FORECAST_RANGE*n_features, activation=’relu’)(lstm)
output_layer = Reshape((FORECAST_RANGE,n_features))(dense)model_vector_output = Model([input_layer], [output_layer])
model_vector_output.compile(optimizer=’adam’, loss=’mse’)mae: 185.95
mse: 92596.76
mape: 9.49
CNN 的矢量输出模型—图 6
多头 CNN-LSTM 模型
这个架构和上面提到的型号有点不一样。在对卡尼佐的研究中已经解释得很清楚了。多头结构使用多个一维 CNN 层来处理每个时间序列,并从每个时间序列中提取独立的卷积特征。这些独立的 CNN 被称为“头”,在馈入 LSTM 层之前分别被展平、连接和整形。总之,多头结构利用多个 CNN,而不是像多通道结构那样只有一个 CNN。因此,他们可能更成功地保留每个时间序列的重要特征,并在这个意义上做出更好的预测。
input_layer = Input(shape=(LOOK_BACK, n_features))
head_list = []
for i in range(0, n_features):
conv_layer_head = Conv1D(filters=4, kernel_size=7, activation=’relu’)(input_layer)
conv_layer_head_2 = Conv1D(filters=6, kernel_size=11, activation=’relu’)(conv_layer_head)
conv_layer_flatten = Flatten()(conv_layer_head_2)
head_list.append(conv_layer_flatten)
concat_cnn = Concatenate(axis=1)(head_list)
reshape = Reshape((head_list[0].shape[1], n_features))(concat_cnn)lstm = LSTM(100, activation=’relu’)(reshape)
repeat = RepeatVector(FORECAST_RANGE)(lstm)
lstm_2 = LSTM(100, activation=’relu’, return_sequences=True)(repeat)
dropout = Dropout(0.2)(lstm_2)
dense = Dense(n_features, activation=’linear’)(dropout)multi_head_cnn_lstm_model = Model(inputs=input_layer, outputs=dense)mae: 149.88
mse: 65214.09
mape: 8.03
多头 CNN-LSTM —图 7
-模型评估
评估基本上与任何预测建模方法相同,模型的一般性能可以用我在前面部分分享的 evaluate_forecast 方法来计算。然而,在我们的案例中有 2 个不同的点,把它们考虑进去也是有益的。第一,我们正在执行多步预测,因此我们可能希望分别分析每个时间步的预测准确性。这将有助于选择准确的预测范围。第二,我们正在对多个平行的时间序列进行预测。因此,观察每个时间序列预测的结果也是有益的。对于特定的时间序列,该模型的效果可能比其他时间序列差得多。
您可以简单地利用不同种类的评估指标,我更喜欢本文中的平均绝对百分比误差 ( mape) 来处理不同的时间序列尺度。
考虑到模型的随机性,的良好做法是多次评估给定的模型,并报告测试数据集的平均性能。为了简单起见,在本文中我只运行它们一次。
关于每个时间步的输出,我只分享一个简单的代码片段和图表,它代表了每个时间步的预测的 mape 值。不出所料, mape 随着预测范围的增加而增加。该图代表多头 CNN-LSTM 架构,并且可以直接应用于我上面提到的其他架构。如果您观察到 mape 急剧增加,您可能会减少您的预测范围,并将其设置为急剧增加之前的点。
y_test_inverse_time_step = y_test_inverse.reshape(int(y_test_inverse.shape[0]/FORECAST_RANGE), FORECAST_RANGE, y_test_inverse.shape[-1])yhat_inverse_time_step = yhat_inverse.reshape(int(yhat_inverse.shape[0]/FORECAST_RANGE), FORECAST_RANGE, yhat_inverse.shape[-1])# yhat_inverse_time_step and y_test_inverse_time_step are both same dimension.
time_step_list_yhat = [[] for i in range(FORECAST_RANGE)]
time_step_list_y_test = [[] for i in range(FORECAST_RANGE)]for i in range(0, yhat_inverse_time_step.shape[0]):
for j in range(0, yhat_inverse_time_step.shape[1]):
time_step_list_yhat[j].append(list(yhat_inverse_time_step[i][j]))
time_step_list_y_test[j].append(list(y_test_inverse_time_step[i][j]))yhat_time_step = np.array(time_step_list_yhat)
yhat_time_step = yhat_time_step.reshape(yhat_time_step.shape[0], -1)
y_test_time_step = np.array(time_step_list_y_test)
y_test_time_step = y_test_time_step.reshape(y_test_time_step.shape[0], -1)# plotting
mape_list = []
for i in range(0, FORECAST_RANGE):
mape = mape_(y_test_time_step[i], yhat_time_step[i])
mape_list.append(mape)plt.plot(range(0, FORECAST_RANGE), mape_list, marker=’o’)
plt.xticks((range(0, FORECAST_RANGE)))
plt.xlabel(‘Forecast Range’)
plt.ylabel(‘MAPE’)
预测范围与 MAPE —图 8
以下代码片段可用于分析不同输入时间序列的模型性能。与基线模型的整体结果相比,该模型对所有 CPU 的预测性能都更好。尽管第二个 CPU 的 mae 与其他 CPU 相比明显较低,但其 mape 明显高于其他 CPU。事实上,这也是我在本文中使用 mape 作为评估标准的原因之一。每个 CPU 使用率值的行为类似,但规模完全不同。老实说,这是我观点的一个很好的例子。为什么第二个 CPU 的错误率这么高?这种情况下我该怎么办?将整个时间序列分成子部分,并为每个子部分开发单独的模型可能是一种选择。还有什么?我真的很感激在评论中读到任何有价值的方法。
尽管对于我们的情况来说,绘制每个时间序列的性能直方图没有太大的意义,但是对于包含更多并行时间序列的数据集来说,绘制直方图还是很有意义的。
for i in range(0, n_features):
print(‘->‘, i)
mae = mae_(y_test_inverse[:,i],yhat_inverse[:,i])
print('mae:', mae)
mse = mse_(y_test_inverse[:,i],yhat_inverse[:,i])
print('mse:', mse)
mape = mape_(y_test_inverse[:,i],yhat_inverse[:,i])
print('mape:', mape)-> 0
mae: 126.53
mse: 32139.92
mape: 5.44
-> 1
mae: 42.03
mse: 3149.85
mape: 13.18
-> 2
mae: 281.08
mse: 160352.55
mape: 5.46
-最后的话
在结束这篇文章之前,我想谈谈现实生活中时间序列预测的几个重要问题。首先,机器学习中用于模型评估的传统方法在时间序列预测中大多不成立。这是因为它们没有考虑时间序列的时间依赖性。
这里提到了 3 种不同的方法。最直接的方法是确定一个分割点,将数据集分成训练集和测试集,而不像本文中所做的那样进行洗牌。然而,在现实生活中,它并不能提供对模型性能的可靠洞察。
另一种是多次重复相同的策略,即多次列车测试拆分。在这种方法中,您可以创建多个训练集和测试集以及多个模型。您应该考虑保持测试集大小不变,以便正确地比较模型的性能。您也可以通过只考虑最新数据的固定长度来保持训练集的大小不变。请注意, sklearn 中有一个名为 TimeSeriesSplit 的包来执行这种方法。
最后一个最可靠的方法是向前行走验证,这是时间序列世界的 k 倍交叉验证。在这种方法中,通过将新的已知值包括到训练集中,在每次预测之后创建新的模型。它通过滑动窗口方法不断重复,并考虑最小数量的观察值来训练模型。这是最稳健的方法,但显然有成本。为特别大量的数据创建许多模型可能很麻烦。
除了传统的 ML 方法,时间序列预测模型应该更频繁地更新,以捕捉变化的趋势行为。然而,在我看来,无论何时你想要生成一个新的预测,模型都不需要重新训练,如这里所说的。如果时间序列不以非常频繁和剧烈的方式变化,这将是非常昂贵和不必要的。我完全同意上面的文章,准确定义预测的置信区间与预测本身一样重要,在考虑异常检测用例的现实场景中甚至更重要。它值得成为另一篇文章的主题。
最后但并非最不重要的是,在生产中运行多步预测模型与传统的机器学习方法截然不同。有几个选项,最常见的是递归和直接策略。在 递归策略 中,在每一个预测步骤中,模型被用来预测前一步,然后从预测中获得的值被馈入同一个模型来预测下一步。每个预测都使用相同的模型。但是,在这种策略下,预测误差会如您所料沿着预测范围传播。这可能是一种负担,尤其是对于长期预测来说。另一方面,在直接策略中,为每个预测范围设计了单独的模型。很明显,随着预测范围的不断扩大,它将不堪重负,这意味着模型数量的不断增加。此外,它没有考虑预测之间的统计相关性,因为每个模型都是相互独立的。作为另一个策略,你也可以设计一个模型,像我们在本文中所做的那样,能够一次执行多步预测。
在本文中,我将重点关注时间序列预测的一个非常具体的用例,但同时也是现实生活场景中的一个常见用例。此外,我提到了在实现预测模型时应该考虑的几个一般要点。
当您遇到多个时间序列,并且应该对每个时间序列执行多步预测时,首先尝试创建单独的模型以获得最佳结果。然而,时间序列的数量在现实生活中可能会非常多,在这种情况下,您也应该考虑使用上面提到的单一模型架构。您也可以利用不同种类的层,如遵循架构的双向、 ConvLSTM ,并通过调整参数获得更好的结果。我提到的用例大多由相同的单位时间序列组成,如流经每个设备的流量值或分布在一个大区域的不同设备的温度值。观察不同时间序列的结果也会很有趣。例如,一次性预测温度、湿度和压力的单一模型方法。我相信这仍然是一个开放的研究领域,因为在这个领域有很多不同的学术研究。从这个意义上说,我很高兴在评论中听到不同的方法。
有用的链接
https://www.sciencedirect.com/science/article/abs/pii/S0925231219309877 https://link.springer.com/chapter/10.1007/978-981-15-3357-0_14 https://ieeexplore.ieee.org/document/8292737 https://machinelearningmastery.com/how-to-develop-lstm-models-for-multi-step-time-series-forecasting-of-household-power-consumption/ https://machinelearningmastery.com/how-to-develop-lstm-models-for-time-series-forecasting/ https://irosyadi.netlify.app/research/time-series-forecasting/
用于音频分类的 CNN
使用张量流进行音频分类的深度学习入门
作者图片
卷积神经网络
CNN 或卷积神经网络是一种深度学习算法,在学习图像方面做得非常好。
那是因为他们可以学习到 平移不变 且具有 空间层次 的模式(F. Chollet,2018)。
作者图片
也就是说如果如果 CNN 学习了上图左角的狗,那么它就可以识别出另外两张被移动过的图片中的狗( 平移不变性 )。
如果 CNN 从上图的左上角学习这只狗,它会在另外两张图片中识别出原始图像的部分,因为它已经学习了她患有异色症的眼睛的边缘是什么样子,她狼一样的鼻子和她时尚耳机的形状( 空间层次 )。
这些属性使 CNN 成为强大的图像学习者,因为真实世界并不总是看起来完全像训练数据。
我能把这个用于音频吗?
是的。你可以提取看起来像 T21 图像的特征,并以某种方式塑造它们,以便将它们输入 CNN。
本文解释了如何训练 CNN 根据音频信息对物种进行分类。
这个例子的数据是来自 Kaggle 竞赛雨林连接物种音频检测的鸟和青蛙的录音。
作者图片
首先,加载必要的输入:
import pandas as pd
import os
import librosa
import librosa.display
import matplotlib.pyplot as plt
from sklearn.preprocessing import normalize
import warnings
warnings.filterwarnings('ignore')
import numpy as np
import pickle
import joblib
from sklearn.model_selection import train_test_split
from tensorflow.keras import models, layers
import tensorflow as tf
然后是数据帧:
os.chdir('/kaggle/input/rfcx-species-audio-detection')
df = pd.read_csv('train_tp.csv')
该数据集是一个 csv 文件,音频文件的名称列在 recording_id 下,标签列在 species_id 下,音频样本的开始/结束列在 t_min 和 t_max 下:
df.head()
使用 librosa 包加载并显示一个音频文件,如下所示:
sample_num=3 #pick a file to display
#get the filename
filename=df.recording_id[sample_num]+str('.flac')
#define the beginning time of the signal
tstart = df.t_min[sample_num]
tend = df.t_max[sample_num] #define the end time of the signal
y,sr=librosa.load('train/'+str(filename)) #load the file
librosa.display.waveplot(y,sr=sr, x_axis='time', color='cyan')
棘手的部分
CNN 期待一个图像:
- 灰度图像(1 个通道)
- 具有三个通道的彩色图像:红色、绿色和蓝色(RGB)
作者图片
所以你必须让你的音频特征看起来像图像。
- 为灰度图像(一个要素)选择 1D,或为彩色图像(表示多个要素)选择 3D。
- 缩放和填充音频功能,使每个“通道”大小相同。
#This code was adapted from Nicolas Gervais on [https://stackoverflow.com/questions/59241216/padding-numpy-arrays-to-a-specific-size](https://stackoverflow.com/questions/59241216/padding-numpy-arrays-to-a-specific-size) on 1/10/2021def padding(array, xx, yy):
"""
:param array: numpy array
:param xx: desired height
:param yy: desirex width
:return: padded array
"""h = array.shape[0]
w = array.shape[1]a = max((xx - h) // 2,0)
aa = max(0,xx - a - h)b = max(0,(yy - w) // 2)
bb = max(yy - b - w,0)return np.pad(array, pad_width=((a, aa), (b, bb)), mode='constant')
难道我不能把我的音频特征分成三等份,重新塑造成 3D 形状吗?
它们毕竟只是数字。
号它必须使视觉感知。垃圾进,垃圾出。
作者图片
建模的特征
Librosa 有关于如何提取特征的很棒的教程在这里。
对于这个例子,我将计算:
输入到 CNN 的 3D 图像是 4D 张量
第一个轴是音频文件 id,代表 tensorflow-speak 中的批处理。在这个例子中,第二轴是光谱带宽、质心和色谱图,其被重复、填充并适合第三轴(stft)和第四轴(MFCCs)的形状。
#The eventual shape of the features
print(X_train.shape,X_test.shape)
第一轴 1226 是批量大小,128 是高度,1000 是宽度(由下面代码中的 max_size 设置), 3 是训练数据中的通道数。如果我有 1226 个音频文件,那么批量大小是 1226。如果我们只提取 dataframe.head()图中所示的 5 个音频文件的特征,则输入的形状将是 5×128×1000×3。如果您想在训练时使用更少的内存,您可以减小批量大小。对于这个例子,批量大小被设置为音频文件的数量。
def generate_features(y_cut):
**max_size**=1000 #my max audio file feature width
stft = padding(np.abs(librosa.stft(y_cut, n_fft=255, hop_length = 512)), 128, max_size)
MFCCs = padding(librosa.feature.mfcc(y_cut, n_fft=n_fft, hop_length=hop_length,n_mfcc=128),128,max_size)
spec_centroid = librosa.feature.spectral_centroid(y=y_cut, sr=sr)
chroma_stft = librosa.feature.chroma_stft(y=y_cut, sr=sr)
spec_bw = librosa.feature.spectral_bandwidth(y=y_cut, sr=sr) #Now the padding part
image = np.array([padding(normalize(spec_bw),1, max_size)]).reshape(1,max_size)
image = np.append(image,padding(normalize(spec_centroid),1, max_size), axis=0) #repeat the padded spec_bw,spec_centroid and chroma stft until they are stft and MFCC-sized
for i in range(0,9):
image = np.append(image,padding(normalize(spec_bw),1, max_size), axis=0)
image = np.append(image, padding(normalize(spec_centroid),1, max_size), axis=0)
image = np.append(image, padding(normalize(chroma_stft),12, max_size), axis=0)
image=np.dstack((image,np.abs(stft)))
image=np.dstack((image,MFCCs))
return image
以下三个特征被挤压、填充和重复…
…进入以下轴:
第二轴
最后两个轴被设计成相同的形状:
stft
MFCCs
我必须计算这些完全相同的特征吗?
否。只要你把它们垫成同样的形状,就用建模中效果最好的。
X=df.drop('species_id',axis=1)
y=df.species_id
提取训练集、测试集和验证集
#Split once to get the test and training set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=123, stratify=y)
print(X_train.shape,X_test.shape)
#Split twice to get the validation set
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=123)
print(X_train.shape, X_test.shape, X_val.shape, len(y_train), len(y_test), len(y_val))
为每个音频文件计算这些特征,并存储为特征和标签:
**def** get_features(df_in):
features=[]
labels = [] *#empty array to store labels*
*#For each species, determine how many augmentations are needed
* df_in=df_in.reset_index()
**for** i **in** df_in.species_id.unique():
print('species_id:',i)
*#all the file indices with the same species_id*
filelist = df_in.loc[df_in.species_id == i].index
**for** j **in** range(0,len(filelist)):
filename = df_in.iloc[filelist[j]].recording_id
+str('.flac') *#get the filename*
*#define the beginning time of the signal*
tstart = df_in.iloc[filelist[j]].t_min
tend = df_in.iloc[filelist[j]].t_max *#end of signal
* recording_id = df_in.iloc[filelist[j]].recording_id
species_id = i
songtype_id = df_in.iloc[filelist[j]].songtype_id
*#Load the file
* y, sr = librosa.load(filename,sr=28000)
*#cut the file to signal start and end*
y_cut=y[int(round(tstart*sr)):int(round(tend*sr))]
*#generate features & output numpy* *array*
data = generate_features(y_cut)
features.append(data[np.newaxis,...])
labels.append(species_id)
output=np.concatenate(features,axis=0)
**return**(np.array(output), labels)#use get_features to calculate and store the features
test_features, test_labels = get_features(pd.concat([X_test,y_test],axis=1))
train_features, train_labels = get_features_noOS(pd.concat([X_train,y_train],axis=1))
将数据规范化并转换为 numpy 数组
X_train = np.array((X_train-np.min(X_train))/(np.max(X_train)-np.min(X_train)))
X_test = np.array((X_test-np.min(X_test))/(np.max(X_test)-np.min(X_test)))
X_train = X_train/np.std(X_train)
X_test = X_test/np.std(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)
创建一个 CNN
在下面的示例模型中,2D 卷积层 (Conv2D)单元是学习平移不变空间模式及其空间层次的部分。
最大池 图层通过将特征地图缩减采样至窗口内的最大值,将特征地图的大小减半。为什么要缩减采样?因为否则它会导致一个巨大数量的参数,你的计算机会崩溃,毕竟,模型会大规模地过度拟合数据。这种神奇的层是 CNN 能够处理图像中大量数据的原因。最大池对模型有好处。
剔除 层通过将一部分数据的权重随机设置为零来防止过度拟合,而密集单元包含与模型必须尝试拟合数据的自由度相关的隐藏层。数据越复杂,模型需要的自由度就越多。注意 不要添加一堆这样的东西,否则会过度拟合数据。
展平层将所有特征地图信息压缩成一列,以便输入到密集层,最后一层输出模型应该将音频记录分类到的 24 个种类。
CNN 模型架构示例
作者图片
在 tensorflow 中,您可以像这样创建上面的模型
input_shape=(128,1000,3)
CNNmodel = models.Sequential()
CNNmodel.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
CNNmodel.add(layers.MaxPooling2D((2, 2)))
CNNmodel.add(layers.Dropout(0.2))
CNNmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))
CNNmodel.add(layers.MaxPooling2D((2, 2)))
CNNmodel.add(layers.Dropout(0.2))
CNNmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))
CNNmodel.add(layers.Flatten())
CNNmodel.add(layers.Dense(64, activation='relu'))
CNNmodel.add(layers.Dropout(0.2))
CNNmodel.add(layers.Dense(32, activation='relu'))
CNNmodel.add(layers.Dense(24, activation='softmax'))
激活功能赋予模型向模型添加非线性的能力。这里使用了 relu 函数,它将负权重清零。你可以在这里阅读其他激活功能,但这是一个很好的开始。最后一个密集层的激活函数类型是 softmax ,它为每个类输出一个概率。
编译模型
CNNmodel.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),metrics=['accuracy'])
Adam 优化器为您管理学习率, loss 函数用于评估预测数据和实际数据的差异,并对预测不佳的模型进行惩罚。在这个例子中,损失函数是SparseCategoricalCrossentropy,当每个样本属于一个标签时使用,而不是一个以上,和它不是二元分类。这是一个合适的选择,因为每个音频样本属于一个物种,而它们有 24 个。.)
符合模型
history = CNNmodel.fit(X_train, y_train, epochs=20, validation_data= (X_val, y_val))
为了避免过度拟合,从最简单的模型开始,一步步向上
这是因为如果模型过于复杂,它将准确地学习你的训练数据,而无法推广到看不见的数据。
试试这个:
input_shape=(128,1000,3)
CNNmodel = models.Sequential()
CNNmodel.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
CNNmodel.add(layers.MaxPooling2D((2, 2)))
CNNmodel.add(layers.Flatten())
CNNmodel.add(layers.Dense(32, activation='relu'))
CNNmodel.add(layers.Dense(24, activation='softmax'))
CNNmodel.summary()
注意:这个模型太简单了,根本无法预测数据*(如个位数精度)。*
接下来,添加层,直到你的模型已经开始适应数据。
评估您的模型训练和验证集
- 注意训练集和测试集之间的性能差异。如果训练集表现明显更好,它不会很好地推广到看不见的数据。
- 如果验证集的性能开始下降,停止迭代。
#Adapted from Deep Learning with Python by Francois Chollet, 2018
history_dict=history.history
loss_values=history_dict['loss']
acc_values=history_dict['accuracy']
val_loss_values = history_dict['val_loss']
val_acc_values=history_dict['val_accuracy']
epochs=range(1,21)
fig,(ax1,ax2)=plt.subplots(1,2,figsize=(15,5))
ax1.plot(epochs,loss_values,'bo',label='Training Loss')
ax1.plot(epochs,val_loss_values,'orange', label='Validation Loss')
ax1.set_title('Training and validation loss')
ax1.set_xlabel('Epochs')
ax1.set_ylabel('Loss')
ax1.legend()
ax2.plot(epochs,acc_values,'bo', label='Training accuracy')
ax2.plot(epochs,val_acc_values,'orange',label='Validation accuracy')
ax2.set_title('Training and validation accuracy')
ax2.set_xlabel('Epochs')
ax2.set_ylabel('Accuracy')
ax2.legend()
plt.show()
结束语
现在,您知道了如何创建用于音频分类的 CNN。从简单的模型开始,然后添加层,直到您开始看到训练数据的表现优于测试数据的迹象。添加 Dropout 和 Max 池层以防止过度拟合。最后,当您注意到与训练数据相比,验证数据的性能下降时,停止迭代。
快乐造型!
来源
萨卡尔,迪潘坚 (2021)个人通信。
Chollet,F. 用 Python 进行深度学习(2018),v. 361,纽约州:曼宁。
Gervias,Nicolas, (2021) 代码摘自https://stack overflow . com/questions/59241216/padding-numpy-arrays-to-a-specific-size,2021 年 1 月 10 日检索。
frenzykryger(2021)https://data science . stack exchange . com/questions/41921/sparse-category-cross entropy-vs-category-cross entropy-keras-accuracy #:~:text = Use % 20 sparse % 20 category % 20 cross entropy % 20 when,0.5%2C%200.3%2C%200.2%5D ,2021 年 2 月 21 日检索
美国有线电视新闻网预测过程故障
作者的“盒子里的猫”图片
原型——在单个图像中堆叠多个时间片并分类:正常、警告或故障
这是一个探索应用 CNN 预测过程中系统故障可能性的原型。目标不是对故障进行分类,而是将一组当前和过去的时间片分类为未来故障的指示。
在我开始之前,请注意,这是作为一个概念/原型提出的,以测试 CNN 模型是否能够合理地预测工业系统中即将发生的故障。我确实将它应用于造纸机故障数据集,我将在下一篇文章中讨论。这不是“成为全部,结束全部”或最先进的人工智能应用程序。我在这里展示它是为了启发他人,给数据科学的新手提供另一个“项目”来修补,并可能从经验丰富的从业者那里激发一些想法。
我第一次想到这一点是在一次使用时间 CNN (TCN)模型的 meetup(深度学习研究金)会议上讨论一篇论文时(白、J 科尔特和弗拉德伦科尔顿,“序列建模的一般卷积和递归网络的实证评估”,arXiv:1803.01271,2018)。那篇论文评估了一个通用的 TCN 来回顾过去并预测未来或下一个状态。
我的申请更简单。目标是将几个时间片的数据整理成图像,即过去和当前状态的快照,并假设故障前几个时间段的过程偏差不同于正常操作,从而发出警告—黄灯。目的不是对故障和正常情况进行分类,而是对“即将发生的故障”进行分类。警告可能有几种类型。(参考下面的“盒子里的猫”,警告可以是在猫跳出盒子之前竖起耳朵、爪子或尾巴。)
为此,每个时间片被转换成图像中的一行像素,多个时间由不同的像素行表示。第一幅图像的时间段为 0 到 n,下一幅图像的时间段为 1 到 n+1,依此类推。如果没有显著的偏差发生,那么每个图像将是相似的,只是有一些变化(噪声)。如果流程连续偏离故障点,图像可能会改变,从而提供即将发生故障的警告。想想“盒子里的杰克”或“盒子里的猫”。在猫跳出来之前,我们能看到它的耳朵从盒子里伸出来吗?
作者图片
为什么要这么做?工业系统依靠过程控制运行。这些使系统在参数范围内运行。然而,系统关闭了。排除其他因素,如手动关闭或设备故障,扰乱仍会发生。识别即将发生的故障可以给操作人员留出时间来防止故障。此外,以这种方式分析一个过程可以提供对为什么或什么样的事件组合会导致不良事件的洞察。
综合数据准备
我从 Excel 开始,做了 10 个流程变量。每个变量都有一个正常的设定点和一个围绕这个设定点的随机方差。大多数变量会在故障点之前和故障点处偏离。这些是根据故障在未来多长时间内发生而定的。请记住,我是在创建它,只是在某个随机的时间将一个失败标志设置为 1,然后从那里返回一个小于 1 的值。正常操作为 0。
这是我用来创建轨迹的参数。每个点随机变化,从-0.5 到+0.5 倍的范围值加上故障位移乘以导致故障的故障规模(如下)。一些轨道不随故障而改变,而其他轨道以不同的百分比改变。在故障之前,范围偏移和故障偏移的组合值并不总是在正常范围之外,因为这些值可能具有相反的符号。如果它们都是正的或都是负的,则过程值可能会在正常范围的边缘或外部。
合成数据参数-作者图片
400+离散时间的随机生成的合成数据如下所示。它可能看起来是大幅度波动的高频,但那是每个轨迹图上的小范围。系统故障点是底部轨道中的尖峰(特征 Y)。
训练集轨迹值和故障点(特性 Y)如下所示。测试集是在不同时间失败的 Excel 模型的另一个随机实现。它是不同的,但在相同的参数定义内。
要素 A 至 J 和故障点(要素 Y)的数据轨迹-按作者分类的图像
准备数据和图像
在之前的试验中,我只是使用了位置数据,然后添加了一个导数(值的变化率,例如速度),最后合并了一个二阶导数,这样就相当于位置、速度和加速度的轨迹值。速度和加速度表是通过计算单位时间的差值来创建的。在故障为 1 和故障为 2 之前,我将正常状态标记为 0,5 时间片。
图像准备包括将数据缩放到 0 到 1 的范围内,并将前 6 个周期(0–5)的数据移动到一个 3-D Numpy 数组中,从而将它们分配给一幅图像。在每个图像中,位置、速度和加速度时间片值被堆叠在一起。对于 18x10 像素的图像,图像行为:0 至 5-位置、6 至 11-速度和 12 至 17-加速度。时间段 1-6 填充了第二个图像,依此类推。每个图像通过对应于该图像中最后一个时间片的标签进行分类。一旦故障时间片成为图像中的最后一行,就通过从故障时间片之后的下 6 个时间段开始构建下一个图像来重复该过程。
接下来,他们被重塑,并通过一个 CNN 模型进行训练。对我们来说,它看起来不像猫,也不像猫耳朵,但 CNN 模型可以区分这些图像。以下是这些图像序列的摘录。
具有六个时间段的示例图像—按作者分类的图像
培养
训练类似于 MNIST 手写数字或时尚 MNIST。我使用了一个顺序 CNN 模型,其中有 Conv2D 、 MaxPooling 、 Flatten layers 馈入一个三层128–64–3 网络和一个漏层。详情可以在 Github [这里](http://Process-Fault-Identification-with-CNN/Simulated Process Fault Prediction with Vel and Accel-3Class.ipynb at main · dvbckle/Process-Fault-Identification-with-CNN · GitHub)找到。
CNN 模型训练—作者图片
结果
测试结果如下图所示。实际类标签显示在顶部,预测类显示在中间,以便与其他两个进行比较。
作者图片
下一个图表在顶部显示预测,在中间显示类别标签,在底部显示警告或故障类别的概率,用于将概率与类别标签进行比较。
作者图片
这表明有足够的希望将这种方法应用到造纸机的实际数据集,这将是另一篇文章的主题。要探索的一个变化是只在正常和警告类上训练,因为识别故障或停止为时已晚,不需要。目标是防止停工。
此处包含的方法的使用或应用由读者自行承担风险。作者对读者的申请不负任何责任。
欢迎大家的评论。
#数据科学# CNN #机器学习#预测#原型#过程失败
R 中的粗化精确匹配
由 Geran de Klerk 在 Unsplash 拍摄的照片
数据科学基础
匹配的因果推理
我们不是都听过“相关性并不意味着因果关系”这句话,并想知道“那么,什么意味着因果关系”?嗯,因果推断。因果推理使我们能够得出关于因果影响的结论,从而做出重要的决策,并提供有价值的数据驱动的见解。因此,了解因果推断的基础知识对于数据科学家和分析师来说是一项巨大的投资。粗化精确匹配(CEM)是一种从观察数据进行因果推断的简单而直观的方法。这篇文章通过一个在 r 中使用MatchIt
库的例子展示了 CEM 背后的基本直觉。
redcharlie 在 Unsplash 上的照片
🔍 1.关于 CEM 的一点点
想象一下,我们想要了解治疗对感兴趣的结果的因果影响。我们能做的最简单的事情就是比较治疗组和未治疗组的平均结果。然而,这种比较可能不能给我们一个准确的估计,因为即使在没有治疗的情况下,治疗组和未治疗组的数据也不具有可比性。解决这个问题的一个方法是尝试将这两个组进行比较。这就是 CEM 等匹配技术的用武之地。
在我们开始讨论 CEM 之前,让我们从一种叫做精确匹配(EM) 的匹配技术开始。对于 EM,我们匹配处理过的和未处理的记录,这些记录在其协变量中具有完全相同的值。换句话说,这些匹配的记录将具有相同的特征,除了它们的治疗状态。一旦我们完成了所有可能的匹配并丢弃了不匹配的记录,那么匹配数据中的治疗组与未治疗组现在将更具可比性,我们可以分析组均值的差异来推断因果影响。
Neil 和 Zulma Scott 在 Unsplash 上的照片
然而,由于在进行 EM 时没有匹配,许多记录可能被排除在分析之外。例如,如果有许多数字协变量,就很难找到精确的匹配。在这方面,CEM 提供了一个很好的选择。做 CEM 时,有三个主要步骤:
- 粗化数据以降低粒度级别。这意味着宁滨数值和/或分组类别值。
- 对粗化的数据应用精确匹配,以找到可比较的对照组和治疗组。这意味着找到至少有一个对照和一个处理记录的协变量的所有组合,并保留属于这些组合的记录,丢弃其余的记录。每个组合被称为地层。
- 使用匹配的数据估计因果影响。
了解了 CEM 背后的基本直觉后,我们可以看到它的名字是多么有信息量。让我们看一个简单的例子来更好地理解这项技术。
📍 2.R 中带有 MatchIt 的 CEM 示例
让我们导入必要的库并加载数据集。我们将使用 Lalonde 数据集的一个小子集来保持事情的易管理性和易监控性。
library("dplyr")
library("MatchIt")
library("lmtest")
library("sandwich")
options(scipen = 100, digits=4)# Prepare sample data --------------------
data("lalonde")
set.seed(42)
(df <- lalonde %>%
select(treat, educ, race, re78) %>%
sample_n(30))
对于 30 个随机选择的记录,我们有以下变量:
◼️ 协变量: educ
受教育年限和race
◼️ 治疗: treat
治疗状态
◼️ 结果:re78
1978 年实际收入
让我们假设我们想要理解treat
对re78
的因果影响。
我们可以通过指定method = 'cem’
来用matchit
执行 CEM:
# Perform CEM --------------------
matching1 <- matchit(treat ~ educ + race, data = df,
method = 'cem', estimand = 'ATE')
summary(matching1, un=FALSE)
仅部分输出
我们可以看到,有 22 条质控记录可用,但只有 5 条匹配,其余 17 条不匹配,将从分析中删除。对照组匹配记录的有效样本量(Matched (ESS)
)为 4.91。治疗组也有相同的总结。
现在,让我们看看 12 条匹配记录的匹配数据:
# Extract matched data --------------------
(matched_df1 <- match.data(matching1) %>% arrange(subclass, treat))
subclass
显示了 3 个地层。虽然我们在这里看不到粗化的数据,但我们可以从原始值中大致猜出粗化的程度。例如,subclass
3 似乎包含有9–10
年教育和black
种族的记录。我们可以看到每条记录都增加了权重。我们先来了解一下这些权重是怎么算出来的。
📍 2.1.CEM 重量
每个层有两个权重:一个权重用于层中的处理记录,另一个用于控制记录。当计算权重时,我们要确保两件事:
◼️在加权后,治疗组和对照组的比例在总体水平上保持在每个阶层内:
◼️加权数等于阶层内未加权数;
根据我们感兴趣的estimand
的类型,该公式可以重新排列并简化为以下形式:
🔷**对被治疗者的平均治疗效果(ATT)——**治疗记录不加权(即权重为 1),对照记录加权:
ATT 公式
🔷**对对照的平均处理效果(ATC)——**ATC 也是如此。质控记录不加权,治疗记录加权:
ATC 公式
🔷**平均治疗效果(ATE)——**两组均加权:
ATE 公式
如果你想了解 ATT,ATC,ATE,查看本帖 中 的 1.5 节。
之前我们明确表示我们有兴趣了解ATE
。使用公式,让我们以子类 1 的重量为例:
我们自己计算了记录PSID376
和NSW153
的权重,以获得与函数返回的权重相同的权重。如果你很热衷,为其他两个类计算权重,巩固你的理解。
我们前面已经看过Matched (ESS)
。如果你想知道它是如何计算的,这里有一个公式:
例如,让我们计算匹配对照组的 ESS:
📍 2.2.估计因果影响
匹配完记录,就该看看预估的ATE
:
# Estimate causal impact - look at ATE --------------------
model1 <- lm(re78 ~ treat, data = matched_df1, weights = weights)
coeftest(model1, vcov. = vcovCL, cluster = ~subclass)
这里可以看到4907
的估计值及其统计意义。该估计值是各组加权平均值之间的差值:
matched_df1 %>% group_by(treat) %>%
summarise(w_mean = weighted.mean(re78, weights))
8255–3348 = 4907
我们还可以检查估计值的置信区间:
coefci(model1, vcov. = vcovCL, cluster = ~subclass)
95%置信区间为-1073
至10887
。这些输出表明,处理对输出没有统计学上的显著影响。这并不奇怪,因为我们使用的是非常小的玩具数据集。
📍 2.3.控制粗化的级别
到目前为止,我们让函数使用其默认的粗化级别:宁滨数值变量使用斯特奇斯方法并保持分类变量不变。然而,在实践中,如果我们能够控制粗化的水平,这将是有用的。我们现在将学习对数字变量使用自定义切割点,对分类变量使用自定义分组。
在应用 CEM 时,为了实现平衡(即,使组具有可比性),删除一些记录,但是删除太多记录是不可取的。在我们的第一次匹配中,超过一半的记录(即 30 个中的 18 个)被遗漏。让我们尝试减少被排除的记录的数量,同时尝试在每个层中映射相似的记录。
# Perform CEM with custom coarsening --------------------
cutpoints <- list(educ = c(8.5, 10.5))
grouping <- list(race = list(c("white", "black"), c("hispan")))
matching2 <- matchit(treat ~ educ + race, data = df,
method = 'cem', estimand = 'ATE',
cutpoints=cutpoints, grouping=grouping)
summary(matching2, un=FALSE)
我们使用了两个分界点为educ
创建了三个箱,并将非西班牙裔种族分组在一起。通过使数据更加粗糙,我们将不匹配记录的数量从 18 个减少到了 3 个。然而,这样做的风险是,在观测值不太可比的同一地层中,包含不太相似的观测值。这意味着我们需要在不排除太多记录和不在层中包含太多不同记录之间找到微妙的平衡。让我们看看匹配的数据,以评估每个地层中的记录有多相似:
# Extract matched data
(matched_df2 <- match.data(matching2) %>% arrange(subclass, treat))
子类中的记录看起来相互之间有可比性吗?这是我们需要评估和必要时重申的,直到我们满意为止。让我们假设我们是快乐的,我们可以继续检查估计:
# Estimate causal impact - look at ATE --------------------
model2 <- lm(re78 ~ treat, data = matched_df2, weights = weights)
coeftest(model2, vcov. = vcovCL, cluster = ~subclass)
coefci(model2, vcov. = vcovCL, cluster = ~subclass)
查看该输出后,前面分析的结论保持不变。
在这篇介绍性的文章中,我们学习了 CEM 的基础知识:算法如何工作,如何控制粗化的程度,以及如何分析因果影响。对于热衷于学习的人来说,这个和这个是非常棒的额外资源。我希望您能够使用这种技术为您的利益相关者提供有价值的见解。✨
照片由 Geran de Klerk 在 Unsplash 上拍摄
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
感谢您阅读这篇文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️ 倾向得分匹配 (因果推断)
◼️ 解释 Scikit-learn 模型与 SHAP
◼️️ K 近邻解释
◼️️ 逻辑回归解释
◼️️ 比较随机森林与梯度推进
◼️️ 决策树是如何建立的?
◼️️ 管道、柱变压器及特性 Union 说明
再见🏃 💨
从代码到生产就绪的机器学习,4 个步骤
我们如何将数据科学代码库转变为数据和模型版本化、实验跟踪的项目,为生产做好准备
TL;速度三角形定位法(dead reckoning)
我们将从 GitHub 获取一个纯代码的机器学习项目,并展示如何添加:
- 使用 DVC 和 DAGsHub 的数据和模型版本控制
- 使用 DAGsHub Logger 以人类可读的格式进行实验跟踪
- 允许任何人试验模型的笔记本
如果你想直接看到结果,请查看 BioBERT DAGsHub repo 。
使用你在网上找到的机器学习项目很难,尤其是如果你想在生产中使用它们。在很大程度上,这是因为您需要将项目包含的所有信息拼凑在一起。你通常从 GitHub 上的一些代码开始。然后,您必须找到对模型进行训练和评估的数据、使用的参数以及模型实现的结果。这通常是在没有明确方法的情况下完成的,即在您自己的示例中尝试该模型,以确保它按预期工作。
直到最近,解决这些问题还是一项艰巨的任务,需要创建者同步多个平台,以使一切触手可及。现在情况不再是这样了。您可以将项目从纯代码项目转变为生产就绪的 ML 项目,使用:
- 数据版本控制
- 模型版本控制
- 实验跟踪
- 交互式推理——加载模型并让您进行实验的笔记本
全部使用开源工具。也许与直觉相反,这真的很容易做到。在这篇文章的最后,我将向你展示我是如何改造这样一个项目的,并且在这个过程中实现了数据浏览、区分和共享、实验可视化,甚至笔记本区分。
一个你永远无法使用的伟大项目
GitHub 上有许多数据科学项目,但当您在寻找可以在项目中使用的东西或想要修改结果时,通常不会找到您需要的所有东西。毕竟,一个完整的数据科学项目不仅包括代码,还包括数据、模型、实验和管道。通常,你最终会花费大量的时间来修补这些组件,并且让事情正常工作变得非常痛苦。这意味着数据科学项目被忽视,甚至更糟,从零开始重新实施。我们有更重要的事情要做。
将所有这些组件都放在一个地方,可以更容易地在所需的上下文中共享我们的数据科学项目,与其他人合作,并提高工作效率。
我们将把我们的项目从目前的状态提升为一个开源的 代码 项目, 到一个 开源数据科学 项目 。
现在,你可能会说:“这当然是我们想要的。我们看不到这种情况发生的原因是,这非常难以实现。”有了今天的工具,那就不再是问题了。
项目背景
我们开始这个项目是作为合作努力的一部分,在 ML 方面,重点是从医学文本中分析和提取信息。目标是了解临床试验是如何进行的。
因此,我们对医学文本的语言模型感兴趣,特别是 NER。我们搜索了互联网,选择了 BioBERT 作为一个好的起点。该模型具有良好的效果,似乎相对容易使用。
当我们找到 GitHub BioBERT 项目时,我们有所有的代码,我们有一个脚本来下载数据,这是使用wget
从一些谷歌文档中完成的,我们有 4 个文件夹,其中 3 个用于模型可以执行的每个任务 done(命名实体识别)、QA(问题回答)和 RE(关系提取)。嵌入本身也有一个文件夹。每个文件夹都包含预处理数据的代码,并为该任务训练模型。每个文件夹中的自述文件包括结果。
不错的开始,但是我们想要更多。
一件更难重现的事情(根据定义),也是我们在这篇文章中不会关注的,是该项目的实验历史。我们希望看到哪些实验没有成功,就像我们希望看到那些成功的实验一样——想象一下,尝试一种方法,然后发现,有人已经尝试过了,但没有成功,但从未被记录下来。获得我们的实验历史的最好方法是从一开始就使用数据&模型版本和实验跟踪,最好添加一个有意义的提交消息来描述你的实验方法。
添加数据版本
第一步是添加要版本化的数据作为项目的一部分。最初,为了获得数据,您必须运行一个脚本来下载数据集。一种方法是将此转换为 DVC 管道步骤,这将使我们能够更改脚本并自动运行。因为我们想以最简单、最直接的方式来做这件事,所以我们只在本地运行脚本。数据下载到我们的系统后,我们添加了 DVC 要跟踪的文件夹。
下载完数据后,我们的datasets/
文件夹看起来是这样的:
$ ./download.sh
$ tree datasets -d
datasets
├── NER
│ ├── BC2GM
│ ├── BC4CHEMD
│ ├── BC5CDR-chem
│ ├── BC5CDR-disease
│ ├── JNLPBA
│ ├── NCBI-disease
│ ├── linnaeus
│ └── s800
├── QA
│ └── BioASQ
└── RE
├── GAD
│ ├── 1
│ ├── 2
│ ⋮
│
└── euadr
├── 1
├── 2
⋮34 directories
对于模型执行的每个任务(NER、QA、RE),我们都有一个文件夹,其中包含每个任务的各种数据集。每个文件夹包含一些文件(依赖于任务),主要是训练集、开发集和测试集。
使用 dvc,我们不需要单独跟踪每个文件,而是可以将整个文件夹视为一个数据集对象,只需在终端中键入:
$ dvc add datasets
接下来,我们有预处理步骤。这三项任务中的每一项所需的预处理步骤都是不同的。因为在这篇文章中,我们关注的是 NER 任务,我们的预处理脚本位于named-entity-recognition/
文件夹中。这个脚本所做的是将.tsv
文件转换成.txt
文件,然后运行preprocess.py
脚本,该脚本将数据标记化并将数据保存到标签旁边的文本文件中。这些预处理数据被保存到我们的preprocessed_datasets/
文件夹中,在适当的任务和数据集文件夹中。在我们这里,那就是NER/
。在预处理步骤完成后,我们可以通过在终端中键入以下命令来添加预处理后的数据,以便由 DVC 进行跟踪:
$ dvc add preprocessed_datasets
当我更改数据时会发生什么
现在,假设您想要为 RE 任务添加预处理数据。我们要做的是运行预处理步骤,然后代替dvc add ...
,我们要做:
$ dvc commit preprocessed_datasets
其次是提交和推送至 Git,然后是 DVC:
$ git add .
$ git commit -m "Updated preprocessed data with RE task"
$ git push origin master
$ dvc push -r origin
定型模型并使其可访问
所以预处理是一个相对“轻量级”的步骤。在这个具体的例子中,我们可以在一台不太强大的计算机上,在合理的时间内完成。当我们开始训练时,情况就不一定了,如果可能的话,我们希望拿出大枪。因为我们希望这个项目可以被社区访问,那些大家伙就是 Google Colab,它给了我们一个免费的 GPU。我们仍然希望从 DAGsHub 中提取代码和数据,并在训练后将它们与模型一起推回。
在我们的例子中,我们创建了这个笔记本,并提交给我们的项目库。它由以下部分组成:
- 使用
git pull
和dvc pull
命令加载代码、数据和模型 - 在相关生物医学数据集上微调模型
- 加载模型,并查看它在一些用户提供的示例上的表现。
- 将所有代码、数据和模型更改提交回我们的 DAGsHub Git 和 DVC 远程。
在最后一节中,我们使用与添加数据相同的命令提交模型:
# If this is the first time adding the output folder $ dvc add outputs # If we changed our model $ dvc commit outputs
轻松添加实验跟踪
我们想补充的最后一点是实验跟踪。正如我在开篇提到的,为历史实验添加这一点很有挑战性,因为如果项目没有从第一天开始记录实验,这些就会丢失。因为我们想让将来的协作更容易,所以我们认为晚添加总比不添加好。
为了做到这一点,我们对运行脚本做了一些小的修改,以便它能够根据自动记录训练期间的所有指标🤗变形金刚库,用于微调模型。 这里可以看到 的变化。这将生成一些保存所有实验上下文的metrics.csv
和params.yaml
文件。然后,我们将这些文件和我们的代码一起推送到 DAGsHub 存储库中。
现在,当我们对一些新数据或不同参数进行实验时,我们将创建一个可以过滤、共享和比较的实验。这也意味着,如果有人想为项目做贡献,他们会更容易理解我们尝试了什么,什么在起作用,什么需要改进。
实验跟踪有助于我们理解测试了哪些方法。来源:作者
模型的交互式推理
我在上面已经提到过,但是我们在笔记本中增加了一个“操场”部分,让任何人都可以加载我们的模型,并在他们可以编辑模型的同一个地方进行测试。在这里自己尝试一下。
看看吧!我们的模型基于用户提供的示例进行预测!来源:谷歌 Colab 作者截图
我们认为这对于任何数据科学项目都很重要,尤其是对于那些您想要分享和协作的项目。每个严肃的 OSS 项目都有一个演示,每个严肃的 OSDS 项目也应该有一个。在 ML 中,这可能需要更多的资源,所以演示笔记本是最好的选择。笔记本还有一个额外的好处,那就是让用户改变模型的某些方面,或者测试他们自己的例子,看看模型在哪里可能不工作。
**另一个好处:**如果您决定对模型进行更改,并希望看到您的结果与原始模型的比较,您可以将您的笔记本提交给 DAGsHub,以使用笔记本差异作为我们数据科学拉取请求的一部分。
DAGsHub 上的笔记本差异。来源:作者
摘要
🥳祝贺你!如果您在这里成功了,那么您已经成功地将一个数据科学代码报告转换为一个生产就绪的数据科学项目——所有这些都有数据和模型版本、实验跟踪,甚至还有一种在 GPU 机器上训练模型并为合作者演示模型的简洁方法。如果你有任何问题,欢迎加入我们的不和谐频道。如果你正在转换一个项目,让我知道,我很乐意帮忙。
用 Knime 进行无代码数据处理
Knime 数据清理和操作简介
Python、SQL、R 和 Julia 是全球数据科学家和分析师在数据分析中使用的一些流行编程语言。有些软件套件,如 Alteryx 和 Knime,有一个 IDE(集成开发环境),数据爱好者和几乎没有编程背景的技术专家可以处理他们的数据,从中提取有意义的信息。这些 IDE 的关键特性称为可视化编程,允许用户可视化从原始信息到经过处理的信息、模型以及最终有意义的输出的数据流。在这篇文章中,我将简要介绍使用来自 Kaggle 的 Fitbit 健康数据使用 Knime 进行可视化编程。
本练习将使用提取→加载→转换方法。下载的数据已经被“提取”。加载和转换将使用 Knime 来完成。
读取和操作数据
简单的数据输入和操作。来源:截图来自 Knime IDE
“CSV reader”节点用于将数据从数据源加载到 Knime 平台。还有 Excel 阅读器、JSON 阅读器、表格阅读器、Web 阅读器等类似的节点。在这篇文章中,我将重点介绍 CSV 阅读器。Knime IDE 中的描述窗口以及 Knime Hub 中的文档有更多关于 Knime 中使用的每个数据输入节点的信息。
要输入数据,右键单击 CSV reader 并从选项中选择“配置”。在打开的“配置”窗口中,您可以选择要从源位置以 CSV 格式导入的文件。
在数据输入过程中过滤列。来源:截图来自 Knime IDE
如果您熟悉这些数据,您可以单击“配置”窗口中的“转换”选项卡,并选择要输入的列。这样,在构建模型等大型数据处理过程中,您就不必处理不必要的信息。在上面的例子中,我只选择了“总步数”、“总距离”和“卡路里”栏,剩下的就不做了。
列筛选器节点。来源:截图来自 Knime IDE
另一种选择列的方法是使用“列过滤器”节点。此处显示了该节点的配置窗口。两种选择柱子的方法都是好的;然而,CSV reader 窗口中的“Transformation”选项卡可以让您深入了解您的数据类型,并允许您移动列,以便以您喜欢的格式排列它们。可以通过右键单击“列过滤器”并选择“过滤的表”来查看最终的表。
列重命名节点。来源:截图来自 Knime IDE
另一个有用的数据输入节点是“列重命名”节点。顾名思义,它允许您为您的模型将输入数据的列名更改为简单的变量名(就像在编程中一样)。这根本不会改变源文件中的列名。这里,我将“总步数”和“总距离”的列名分别更改为“步数”和“距离”。
连接表格。来源:截图来自 Knime IDE
在我的例子中,我使用了两个 CSV 阅读器节点从两个源读取数据。既然输入已经被修改为具有相同的列,那么这两个表就可以连接起来,形成一个输出表,用于我们的数据处理。连接节点用于此目的。您可以选择是否可以跳过表中的重复值或以值作为后缀,或者是否应该失败。其次,您可以选择想要列的交集还是列的并集。通过选择 intersection,您将只看到数据匹配的列,而在 Union of columns 中,所有的数据都被合并在一起,得到一个连接表。
筛选表中的行。来源:截图来自 Knime IDE
现在数据已经按列过滤并合并了,我们要做的最后一个操作是清理数据,删除步骤为 0 的所有行。“行过滤器”节点可用于此目的。筛选器节点有各种选项,可以根据行类型、行号、行值和行 ID 来包含或排除行。我选择了“Steps”作为列,并排除了值为 0 的行。正如您所看到的,您可以使用这个节点来过滤一列中的行。若要筛选多个列,可以使用“基于规则的行筛选器”节点,而不是使用多个行筛选器节点。这将允许您为多个列的过滤编写简单的指令。
来自线性相关节点的相关矩阵。来源:截图来自 Knime IDE
“线性相关”节点是一个可视化节点,它为您提供了数据中不同列之间的相关性度量。这使您可以看到一列中的更改将如何影响另一列的数据或输出。此处显示的相关矩阵是线性相关节点的输出。深蓝色单元格紧密相关,而浅蓝色单元格相关性较小。如果任何单元格是红色的,那么它们在该单元格中的变量(X 和 Y 列)之间具有反向相关性。叉号(X)表示没有相关性。
散点图节点输出。来源:截图来自 Knime IDE
“散点图”节点允许您在一个柱上绘制另一个柱。它不允许有第二个轴。散点图节点的输出如上所示。您可以使用标签、标题和副标题定制绘图,Knime 还允许您选择在 X 和 Y 轴上显示其他列的视图。这样可以更快地查看不同列之间的关系,而不必为每个图表创建单独的节点。
结论
本文旨在简要介绍 Knime 中的数据输入和转换。Knime 是一个强大的可视化编程工具,可以通过它的 IDE 和 Knime hub 提供一个巨大的节点和特性库。几乎不需要编程,Knime 允许用户处理他们的数据,创建模型,并在他们的数据上部署机器学习模型以进行快速处理,而不是必须使用 Python,R 或 SQL 编写所有代码。虽然 Python、R 和 SQL 是数据科学所需的关键技能,但 Knime 为那些不熟悉编程但需要根据模型输出做出决策的人提供了一个极好的选择。
参考资料:
- 克尼姆中心—https://hub.knime.com/
- Knime 课程—【https://knime.learnupon.com/dashboard
- https://www.kaggle.com/
- 来自 Unsplash 的封面图像
傻瓜用无代码机器学习词典
为最激动人心的领域找到正确的术语
知识的诅咒
机器学习已经变得如此受欢迎,以至于它成为人们认为你知道它的一切的话题之一。现在很常见的是使用花哨的术语,如训练/拟合模型、训练集、验证模型、成本函数和许多其他术语,而不考虑人们是否理解它。有时候,感觉你生来就应该知道这些事情…
看看我,漫无边际地谈论机器学习,却不解释它是什么。
今天,我在这里通过解释一些围绕机器学习的最常见的术语来打破这种知识偏见,并且希望你有一些背景知识来理解。
https://ibexorigin.medium.com/membership
获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:
https://alphasignal.ai/?referrer=Bex
什么是机器学习?
机器学习的第一个定义出现在 60 年代末:
机器学习是在没有明确编程的情况下赋予计算机学习能力的研究领域。——阿瑟·塞缪尔
但是没有编程,计算机是怎么学习的?你的笔记本电脑上可能有一千本科学书籍,但这意味着机器知道一些东西吗?你可以很容易地通过问为什么水是湿的来检查,你会得到你的答案。
机器学习最早的应用之一是一个垃圾邮件过滤器。到目前为止,垃圾邮件过滤器已经变得如此之好,我敢打赌,你甚至不记得你最后一次将一封邮件标记为垃圾邮件是什么时候了。
在全面解释机器学习之前,我们先来谈谈如果没有机器学习,你将如何编写一个程序来标记垃圾邮件。
首先,您查看许多垃圾邮件的示例并识别模式。这些词可以是紧急词,如立即行动、立即打电话、尽快结束,或者垃圾邮件发送者经常使用的 188 个词中的任何一个。然后,编写规则来检查这些短语,以检测垃圾邮件。
与此同时,垃圾邮件发送者不会坐以待毙,意识到他们的电子邮件没有通过,所以他们想出了更好的技术来逃避过滤器。随着垃圾邮件模式的变化,您的程序变成了一个更长的复杂规则列表,并且不断扩展。
相比之下,基于机器学习的垃圾邮件过滤器可以检测出与普通电子邮件相比在垃圾邮件中出现异常频繁的单词(也称为“ham”),并开始自动标记它们。
如果垃圾邮件发送者开始使用新的模式,用户开始手动标记它们,基于 ML 的程序会意识到这一点,并开始过滤这些类型的垃圾邮件,而无需您的干预。
基于 ML 的程序的这种能力使它们更容易编码和维护。
机器学习就是在随机数据(数字和文本)的海洋中检测模式。它可以用来从最疯狂的现象中提取有用的信息,比如预测股票价格。
特征和目标
所有的 ML 算法都试图根据现有的数据来预测未来的结果。为了创建垃圾邮件过滤器,成千上万封电子邮件被输入到机器学习算法中。每封电子邮件都有一些质量或属性,如字数、句子数、主题、正文、邮件类型等等。
根据您试图预测的内容,这些属性分为两组:要素和目标。顾名思义,目标属性(ML 工程师也叫目标变量)就是你要预测的值。在我们的例子中,电子邮件的类型(垃圾邮件或垃圾邮件)是目标属性。
相反,特征是帮助预测目标变量的所有属性。如果你试图预测房子的价值,目标是房子的价格和特征,可以是房间数量、地段面积、浴室数量、靠近公共交通等等。
当您将现有数据提供给 ML 算法时,您可以判断哪些属性是特征,哪些是目标。该算法同时查看所有特征并检测模式。换句话说,它学习什么样的特征组合构成特定类型的目标变量。
目标变量的类型决定了使用哪种 ML 算法。通常,试图预测数字目标的算法被称为回归算法,而试图预测某种标签或组的算法被称为分类算法。
比如预测房价,你用回归,预测邮件类型,你用分类。
什么是模型?
你会看到人们互换使用术语机器学习模型和机器学习算法。然而,它们之间有一个关键的区别。
ML 算法是复杂的数学和统计学的结合。没有任何数据和计算机能力,它什么也做不了。你不能用它来预测。
ML 模型是一种算法,已经对数据进行了训练,并准备好预测与训练数据相同类型的新值。
你问培训是什么?嗯,我已经提到过几次了:它是将数据输入算法的过程(也称为拟合模型)。这是实际学习发生的地方。该算法使用其基本公式或规则,从输入数据中检测模式,并将信息存储在其内存中。
一般来说,大多数常见的算法都是使用 Python 这样的编程语言来实现的。Python 提供了标准的应用编程接口(API ),使得用几行代码访问和训练任何数据上的 ML 算法变得容易。
总之,算法只是一套原始的、未经训练的数学规则,而模型是一个经过训练的、可以预测的程序。
训练/测试设备
我希望我们已经达成一致,机器学习就是预测未来的价值。但是我们能说一个模型的预测总是可信的吗?换句话说,我们如何检查它的性能?
考虑到这个目的,ML 工程师将可用数据分为两组:训练集和测试集。正如您所猜测的,该算法在包含所有要素及其标签的训练集上接受训练。
测试集也包含特征和标签,但为了模拟预测过程,您只需将特征提供给训练好的模型,它就会预测它们的目标/标签。
例如,假设你有 3 种玫瑰的 1 万张图片。每张图片都以其物种名称命名或标注。要建立一个将玫瑰分类的模型,首先需要创建一个训练集。通常,您会分离 80%的可用数据来训练您的模型。
为了检查模型的学习效果,你给另外 20%的图像进行预测。只是这一次,你去掉了图像标签。在模型预测了它们的种类之后,你将它们与这 2000 张图片的实际标签进行比较。
如果一个模型的精确度足够高,你就可以安全地用它来对未来的玫瑰图像进行分类。
监督/非监督学习任务
机器学习模型根据训练数据进一步分为两组。
第一种是监督学习。除了相关特征,监督学习算法还需要相应的标签来建立相关的联系。这就像给婴儿看一个苹果,并告诉他这是什么,这样婴儿下次看到或触摸一个圆形的红色物体时就可以说“苹果”。
监督学习模型以同样的方式工作。为了预测一个有 100 平方英尺和 3 个卧室的房子,模型必须已经在具有相似属性的房子的许多实例上训练过,更重要的是,具有它们的给定价格(在这种情况下是标签)。
由于这些标签是手工收集的,这些任务被称为监督,或者换句话说,由人类控制。
然而,在那里很难找到正确标记的整洁数据集。大多数将是无标签和无结构的,就像社交媒体帖子一样。为了处理这种类型的数据,使用无监督学习算法。
这些算法往往更加复杂和强大。程序员只需在训练数据上启动算法,它就会自己找到标签和有意义的见解。一个非常受欢迎的例子是神经网络,它被用于图像和语音识别、自动驾驶、异常检测和销售预测等领域的当今最先进技术中。
结论
不言而喻,机器学习比这里讨论的要多得多。这是一个令人兴奋和非常有趣的领域,吸引了数百万专业人士。我希望这篇文章是对机器学习的一个很好的介绍,并且你有基本的背景知识来理解更复杂的 ML 主题。此外,每当你被 ML 世界中的一些花哨术语绊倒时,我推荐由谷歌开发者创建的 ML 词汇表。再见!
法典:云之间的桥梁?
图片— shutterstock
Codex 可以在 AWS 和 Google Cloud 之间翻译命令吗?
许多企业需要应对多种云环境。AWS、Azure 和 Google Cloud 都有自己的命令集来执行云操作,如设置存储桶、定义服务帐户和其他管理任务。如果能有一种自动化的方法将命令从一个云环境翻译成另一个云环境的等效命令,那就太好了。在这篇文章中,我将继续之前关于 OpenAI 的 Codex 的文章(使用 Codex 在 Keras 和 fastai 之间进行翻译,使用 Codex 将 COBOL 翻译成 JavaScript ),探索 Codex 是否可以帮助应对这一挑战。我将尝试让 Codex 将一系列 AWS 命令翻译成 Google Cloud 的等效命令。
实验 1:创建虚拟机实例
创建虚拟机(VM)实例是一项常见的云任务。我想看看 Codex 是否能把创建 VM 的 AWS 命令翻译成创建 VM 的有效 Google Cloud 命令。我决定从 Codex 示例提示“为库或框架重写代码”开始,如下所示:
// Rewrite this as <TARGET><SOURCE CODE>// <TARGET> version:
从 AWS 文档中用于创建 VM 的示例命令开始,我试图让 Codex 生成等效的 Google Cloud 命令。下面是我在 Codex 中使用的实际提示,带有 AWS VM 创建命令,后跟 Codex 生成的 Google Cloud 代码:
// Rewrite this for Google Cloud
aws opsworks --region us-east-1 create-instance --stack-id 935450cc-61e0-4b03-a3e0-160ac817d2bb --layer-ids 5c8c272a-f2d5-42e3-8245-5bf3927cb65b --hostname myinstance1 --instance-type m1.large --os "Amazon Linux"// Google cloud version:
gcloud compute instances create myinstance1 --zone us-central1-a --machine-type n1-standard-1 --image-project centos-cloud --image centos-7-v20160301 --tags http-server,https-server
我从 Codex 获取输出,并尝试在 Google Cloud 项目的 Cloud Shell 中运行它,命令运行成功:
作者图片
我可以在谷歌云控制台中看到新的虚拟机:
作者图片
Codex 产生了一个可行的谷歌云命令,但它并不完美。特别是,它指定了一个不推荐使用的图像,如以下警告消息所示:
WARNING: Some requests generated warnings:
- The resource 'projects/centos-cloud/global/images/centos-7-v20160301' is deprecated. A suggested replacement is 'projects/centos-cloud/global/images/centos-7-v20160329'.
实验 2:创建一个桶
从 AWS 文档中用于创建 bucket 的示例命令开始,我试图让 Codex 生成等效的 Google Cloud 命令。下面是我在 Codex 中使用的提示,其中带有 AWS bucket creation 命令,后跟 Codex 生成的 Google Cloud 代码:
// Rewrite this for Google Cloud
aws s3api create-bucket --bucket my-bucket-bridge-test --region us-east-1// Google Cloud version:
// gsutil mb -l us-east1 gs://my-bucket-bridge-test
这次,Codex 在输出的开头添加了“//”。我从 Codex 获取输出(去掉注释前缀),并在 Google Cloud Shell 中运行它:
作者图片
我可以在谷歌云控制台上看到新的桶:
作者图片
同样,Codex 从 AWS 输入生成了有效的 Google Cloud 命令。
实验 3:创建安全组/防火墙规则
从 AWS 文档中用于创建安全组的示例命令开始,我试图让 Codex 生成等效的 Google Cloud 命令。下面是我在 Codex 中使用的实际提示,AWS 命令后跟 Codex 生成的 Google Cloud 代码:
// Rewrite this for Google Cloud
aws ec2 create-security-group --group-name my-sg --description "My security group"// Google Cloud version:
gcloud compute firewall-rules create my-sg --description "My security group" --allow tcp:22
我能够在 Google Cloud Shell 中成功运行 Codex 的输出:
作者图片
我可以在谷歌云控制台上看到新的防火墙规则:
作者图片
我承认我无法验证 Codex 生成的 Google Cloud 命令在功能上是否等同于 AWS 输入命令,尽管这个话题表明它至少是在正确的范围内。
结论
本文中的实验非常简单,只是触及了创建和管理云环境所需的全部命令的皮毛。这些基础实验并没有证明 Codex 可以对实际问题做出重大贡献,比如从 AWS 到 Google Cloud 的迁移。然而,有趣的是,Codex 为每个输入 AWS 命令生成了有效的工作 Google Cloud 命令。
OpenAI 的法典,在行动中
为每个编码的人(甚至是不编码的人)提供强大的人工智能驱动的支持。
作者照片
T 何代号是我们这个世界的数字层 DNA。通过掌握代码——它的特征和特性——你建立了我们都生活在其中的数字现实。今天,OpenAI 向我们的 AI 春天揭示了一个新的里程碑(提醒:AI 冬天已经结束),这将使更多的人能够创造:
法典
官博:https://openai.com/blog/openai-codex/
论文:https://arxiv.org/abs/2107.03374
加入候补名单:https://openai.com/join
什么是法典?
OpenAI Codex 是 GPT-3 的后代;它的训练数据包含自然语言和数十亿行公开来源的源代码,包括公共 GitHub 库中的代码。OpenAI Codex 最擅长 Python,但它也精通十几种语言,包括 JavaScript、Go、Perl、PHP、Ruby、Swift 和 TypeScript,甚至 Shell。它有 14KB 的内存用于存储 Python 代码,相比之下,GPT-3 只有 4KB——因此它在执行任何任务时都可以考虑超过 3 倍的上下文信息。[ OpenAI 博客
上个月,你能够见证由 Codex 实现的多种可能性之一——GitHub 与 OpenAI 合作展示了运行在 Codex 上的 CoPilot 。CoPilot 是一个助手,理解你的方法,为你提供例子、提示和适当的代码片段,一个智能自动更正,增强你的编码。
但这仅仅是开始。Codex 是一个强大的变压器驱动系统,可以作为 NLP 模型与 GPT-3 相比较。
就像 GPT 3 号一样,它的使用案例是无穷无尽的。食品法典委员会理解你的任务,并最有效地完成它。
第一步
我们有机会研究法典并尝试它的功能。感觉我们只是在抓表面,我们想分享几个演示,展示与代码交流的新方式。
**但是等等,谁是“我们”?**早在 2020 年,随着 GPT 3 的发布,OpenAI 正在寻找社区大使,他们将帮助和支持不断增长的 GPT 3 社区(后来大约有 6 万名成员)中的开发人员、研究人员、艺术家和作家。他们要求我们中的一些人,论坛中最活跃的用户,来提供帮助——这就是我们, OpenAI 社区大使。我们在开放时间为 GPT-3 用户提供建议,我们集思广益如何增强用户体验,我们还代表大社区与 OpenAI 讨论用户观点。
有时,我们会深入了解 OpenAI 的最新发展,以便更好地向世界传播这些知识。就像法典的情况一样。下面你会看到一些由 OpenAI 社区大使制作的很酷的 Codex 演示。
法典长什么样?
Codex 的当前界面是极简的(并且无疑将会改变,因为 OpenAI 正在继续努力)。
Codex 界面—作者截图
在**字段 1 中,**你可以输入你的任务,用简单的英语(以及几乎所有其他语言,我们将在后面看到)。
字段 2 向您显示由 Codex 生成的代码。
字段 3 预览结果。
做法
你用明文给 Codex 你的指示。生成的代码可用于您的项目——您节省了时间并实现了更高效的工作,您尝试了新的事物,具有创造性,并打破常规进行思考。
当然,编码纯粹主义者可以继续手工编码。法典不会给他们带来挑战或竞争。Codex 使每个人都能够互动地学习和应用代码。法典不会杀死编码员,就像电影不会杀死剧院一样。就像 GPT 3 不会杀作家一样。是的,它改变了我们的工作方式,但它增强了我们的创造力,而不是取代我们。两种方法(人工智能驱动和真正的人类)可以并行存在。Codex 可以让你更有效率、更有效、更有教育意义地编码。
它是如何工作的?就像在 GPT-3 的指令引擎中,你需要输入的所有东西——只要问(礼貌地), Codex 就会完成请求。
你想看看它的实际效果吗?在这个演示中,我们要求 Codex 为一个名为 NTech 的网站创建"一个登录页面",“该页面应该处于黑暗模式,带有一个电子邮件列表,供人们注册”:
由 Abran Maldonado 演示
当然,你必须设置一个电子邮件,并微调其他元素,但你会看到 Codex 如何将你的需求付诸行动。
谈到法典/无障碍方法。
有了一些变通办法,你可以用你的声音控制食品法典委员会:
布拉姆·亚当斯的演示
这不仅是一个易于编码的有价值的功能,它还将使身体残疾的人能够创造和实现他们的想法和梦想。此外,想想孩子们从与机器的对话中可能获得的巨大教育价值(和乐趣)。
另一种非接触式控制 Codex 的方法是使用您的网络摄像头和动作:
由布拉姆·亚当斯演示
用例
在我们第一次接触这个系统的时候,让我们看看 Codex 能做什么。
数学。
这个系统可以做数学运算:
Russell Foltz-Smith 的演示
评估测试
创建评估测试需要功能和知识——Codex 具备这两方面:
由 Abran Maldonado 演示
应用程序?是的,可以。
【倒计时】
在下面的演示中,使用几个控制按钮实现了倒计时功能。简单—只需要简单的文本:
Natalie Pustinovich 的演示
图像处理
使用 Codex,您可以轻松创建一个简单的应用程序来修改图像:
由 Lucas Negritto 演示
盒子外面
Codex 可以与您的浏览器和计算机系统进行交互。
例如,您可以控制您的网络摄像头,并让 Codex 在网络摄像头流的下半部分将语音转换为文本。
Yash Dani 的演示
该系统甚至允许您控制您的浏览器:
布拉姆·亚当斯演示
体验一下!
由 Codex 提供的“maslo occure”首次展示了一种全新的网络体验,在这种体验中,交互、编辑和呈现是实时进行的:
maslo occure的演示(基于 Codex 的平台)由 Russell Foltz-Smith 完成。
其他语言?
法典是全球性的。再也没有语言障碍了。在我的实验中,我尝试了一个简单的任务:用特定的颜色创建和修改一个形状。但是:我是用英语、德语、日语、俄语问的。
如你所见:结果是一样的。法典明白了!不管你对它说什么语言。
作为讲故事工具的抄本?
当然,抄本不是一个作家。它不是为了写精彩的小说而设计的——如果你想拥有一个人工智能驱动的叙事,你最好使用 GPT-3。但是它仍然可以帮助你。
比如:创造模因。
布拉姆·亚当斯演示
它还能写简单的(或有趣的)诗,并把它们翻译成另一种语言:
Vlad Alex 演示(Merzmensch)
结论
Codex OpenAI 提供了巨大的教育价值:
想象一下在学校使用这个——玩着法典,孩子们会爱上代码。我可以向你保证,他们不会把自己变成那些来自瓦力的懒人,他们会研究和接触。
Codex 使不编码的人能够投入进去,尝试一些东西,并实现他们的想法。艺术家、教师、许多其他职业不涉及编程语言的人将创造他们的方法并实现他们的愿景。
它还将帮助编码人员进行短暂的尝试和打破头脑风暴实验,而不必“仅仅为了尝试”而在编程上投入大量时间。
这个系统是人机交互的巨大飞跃。
更新 1:
这是几个小时前 OpenAI 录制的 CODEX 官方演示,包含更多信息和实验:
更新 2:
2021 年 8 月 12 日星期四有一场法典挑战:https://challenge.openai.com报名法典候补:https://openai.com/join
更新 3 (2021.08.24):
看看这些和更多的演示,由 Sandra Kublik 编辑在这个信息丰富的视频中:
https://www.youtube.com/watch?v=66xTYJrOxKk
Codex 将 COBOL 翻译成 JavaScript
图片— shutterstock
Codex 能把各种 COBOL 翻译成 JavaScript 吗?
今年早些时候,OpenAI 发布了 Codex 作为人工智能驱动的环境,用于处理计算机代码。Codex 可以将英语语言描述转换成代码,从代码创建注释,并从一种编程语言翻译成另一种编程语言。我对与 COBOL 语言相关的 Codex 语言翻译能力特别感兴趣,COBOL 是大型机/穿孔卡时代的通用语言。
我已经发表了几篇文章,描述了 Codex 如何从基本的 COBOL 程序和非平凡的 COBOL 程序中为现代语言生成代码。在本文中,我将从优秀文章 7 COBOL 示例及解释中为 Codex 提供一些额外的 COBOL 示例。JavaScript 是本文中描述的实验的目标语言——我在让 Codex 从 COBOL 生成 Python 方面取得了有限的成功,但是 JavaScript 作为目标语言更有前途。让我们看看 Codex 能否处理更复杂的 COBOL 程序,并将其翻译成 JavaScript。
实验 1:从具有各种变量类型的 COBOL 程序中生成 JavaScript
首先,我想回到第二篇文章中的 COBOL 变量示例,但是这次保留整个 COBOL 程序。下面是开始的 COBOL:
下面是 Codex 从这个 COBOL 输入中生成的 JavaScript 输出,经过清理,删除了无关的 Python 风格的注释:
下面是 node.js 中运行的 JavaScript 的输出:
1ST VAR : 000.00
2ND VAR : -123.45
3RD VAR : ABCDEF
4TH VAR : A121$
GROUP VAR : {
subvar1: 337,
subvar2: 'LALALALA',
subvar3: 'LALALA',
subvar4: 'LALALA'
}
下面是原始 COBOL 的输出:
还不错!在没有干预的情况下,Codex 没有被任何 COBOL 阻塞,JavaScript 产生的输出非常接近 COBOL 程序的输出。
实验 2:用条件从 COBOL 程序生成 JavaScript
现在让我们看看 Codex 是否可以处理 COBOL 条件语句。下面是一个 COBOL 程序,来自 7 COBOL 示例和解释,其中包括各种条件语句:
下面是 Codex 从这个 COBOL 输入中生成的 JavaScript:
以下是 JavaScript 的输出:
IN LOOP 1 - IF BLOCK
IN LOOP 2 - ELSE BLOCK
PASSED WITH 65 MARKS.
NUM1 LESS THAN 1000
下面是原始 COBOL 的输出:
相同的结果!这是 Codex 能够高保真地翻译成 JavaScript 的两个 COBOL 程序。
实验 3:从 COBOL 字符串操作程序生成 JavaScript
COBOL 有一些奇特的字符串操作结构。本实验中的示例程序展示了 COBOL 字符串处理。我们来看看 Codex 是怎么处理的。
下面是 Codex 从这个 COBOL 输入中生成的 JavaScript:
以下是 Codex 生成的 JavaScript 的输出:
WS-CNT1 : 20
WS-CNT2 : 6
NEW STRING : XBCDXDXDXDXBVDFDFFXF
WS-STRING : TUTORIALSPOINTWELCOMETO ANDTUTORIALSPOINTXBCDXDXDXDXBVDFDFFXF1
WS-COUNT : 1
WS-STR1 : WELCOME
WS-STR2 : TO
WS-STR3 : TUTORIALSPOINT
这是原始 COBOL 程序的输出:
让我们看看 COBOL 和 JavaScript 输出之间的一些差异:
- WS-CNT1 :在 COBOL 中,这个变量被分配了 25 个字符的大小,尽管它只有 20 个字符长。
- WS-CNT2 :这是 Codex 处理 COBOL 最好的例子之一——它正确地解释了 COBOL 结构检查 WS-STRING 计数 WS-CNT2 的所有‘A’,并在 JavaScript 中实现了一个 FOR 循环,实现了相同的目标。
- 旧字符串 : JavaScript 完全忽略了这个输出
- 新字符串:两个输出相同
- WS-STRING : JavaScript 没有接近这个字符串
- WS-COUNT : JavaScript 初始化了这个变量,但是错过了处理
- WS-STR1,WS-STR2,WS-STR3 : JavaScript 得到了正确的字符串分段,但是打乱了子字符串的输出顺序。
这个实验有一些很好的结果,但总体来说,它表明如果没有人工清理,Codex 无法生成功能上等同于 COBOL 字符串操作代码的 JavaScript。
实验 4:从 COBOL 循环程序生成 JavaScript
COBOL 有一些循环结构,现代语言的程序员会觉得很奇怪。在这个实验中,我们将采用一个具有各种循环设置的 COBOL 程序,看看 Codex 是如何处理它的。
这个程序的 Codex 输出没有产生有效的 JavaScript——它缺少变量定义。注释是在 JavaScript 上执行的,但是在 node.js 中运行时产生了代码错误。
为了尝试获得有效的 JavaScript 输出,我从 COBOL 程序中删除了注释,并重新运行 Codex 翻译以获得以下 JavaScript 输出:
下面是这个 JavaScript 的输出:
In B-PARA-TIMES
In B-PARA-TIMES
In B-PARA-TIMES
WS-CNT : 0
WS-CNT : 1
WS-CNT : 2
In C-PARA-THRU
In C-PARA-THRU
In C-PARA-THRU
In D-PARA-THRU
In D-PARA-THRU
In D-PARA-THRU
In E-PARA-THRU
In E-PARA-THRU
In E-PARA-THRU
In B-PARA 0
In B-PARA 1
In B-PARA 2
In B-PARA 3
In B-PARA 4
这是 COBOL 的输出:
一些循环的开始和结束条件没有被准确地翻译成 JavaScript,JavaScript 完全丢失了 WS-A 的输出。与实验 3 类似,这个实验表明 Codex 可以处理一些非常复杂的 COBOL 输入,但是如果没有人工清理,它无法生成与 COBOL 循环代码功能相当的 JavaScript
实验 5:从编写文件的 COBOL 程序生成 JavaScript
最后,让我们尝试一个写文件的 COBOL 程序。下面是输入 COBOL 程序,它汇编一条记录并将其写入文件:
这是 Codex 从 COBOL 程序中生成的 JavaScript。注意这个例子的 JavaScript 有多紧凑。
下面是 JavaScript 生成的输出文件的内容:
12345,TEST TRANSACTION,000124.34,000177.54,53.2,1234567,JOHN SMITH
以下是 COBOL 生成的输出文件的内容:
12345TEST TRANSACTION 0001243400017754000053200000000
Codex 在 JavaScript 输出中估算 ACCOUNT-ID 和 ACCOUNT-HOLDER 的值,但在其他方面,输出与 COBOL 程序的输出一致。
结论
以下是我从本文描述的实验中得出的总体结论:
- Codex 可以将一系列 COBOL 代码翻译成可用的 JavaScript。事实上,除了实验 4 中第一个版本的 COBOL 循环程序,Codex 总是能够生成有效的 JavaScript。
- 对于某些 COBOL 语法,包括循环结构和条件语句,Codex 无法始终如一地生成功能等同的 JavaScript。
你可以在这个报告中找到本文描述的实验的输出:https://github.com/ryanmark1867/codex_experiment
这里有一个视频,是这篇文章中的一个实验:【https://youtu.be/2dYSMvlwFjg
编码矩阵
我们将实现一个矩阵数据结构,支持像乘积和分解这样的线性代数计算
一种 3×3 矩阵数据结构。图片作者。
通用数组类
矩阵将从一般的类似数组的类继承。array 类可以支持额外的数据结构,如向量和张量。我们希望 array 类支持以下常规属性和方法:
- 以嵌套列表的形式返回数组数据,并计算数组形状。
- 确保数组对象只能用有效的输入数据初始化。
- 支持索引,以便我们可以检索和更新数组的内容。
- 支持加、减、标量乘、标量除等运算符。
数组初始化
数组对象将通过传递包含complex
或float
数字的嵌套数据列表进行初始化。我们将通过检查其形状来验证输入数据是否有效。[1,2,3]
的输入有效,而[1,[2,3]]
的输入无效。一旦输入数据形状得到验证,我们将计算数组形状。
阵列形状
具有 2 行 2 列的矩阵的形状是(2,2)。图片作者。
为了验证数组的形状是否有效,我们可以沿着给定维度的宽度进行迭代,以检查每个元素(将是可迭代的对象)是否具有相同的形状。然后,我们可以使用递归来更深入地遍历数组。停止条件将是当我们到达一个不可迭代的对象(这将是数组元素本身)。
为了计算数组的形状,我们可以假设数据具有有效的数组形状,并递归计算每个维度的长度。
数组索引
设置(左)和获取(右)一个矩阵的元素。图片作者。
我们可以使用 Python 的特殊索引方法来实现数组 getter 和 setter 函数。我们需要确保数组对象有多个维度,这样索引才是允许的。对于 setter,我们需要检查新数组是否具有有效的形状。
数组运算符
添加数组将添加每个数组的相应元素。图片作者。
我们可以利用 Python 的特殊运算符方法来实现加、减、标量乘、标量除等运算。下面是数组加法的实现。
矩阵初始化
要实现一个矩阵类,我们可以从通用数组类继承,并对其形状应用约束。如果输入数据不具有矩阵的形状,则矩阵对象不能被初始化。
矩阵属性
现在我们可以初始化一个矩阵对象,我们可以计算矩阵的各种属性,包括:
- 无论是方阵
- 是否是一个单位矩阵
- 矩阵行列式
- 矩阵轨迹
- 矩阵转置
- 是否是一个对称矩阵
方阵
行数和列数相同的矩阵是正方形。图片作者。
我们可以通过比较矩阵的行和列来检查矩阵是否是正方形的。
单位矩阵
主对角线上为 1 而其他地方为 0 的矩阵是单位矩阵。图片作者。
如果一个矩阵的每个主对角线元素的值都是 1,而其他元素的值都是 0,那么这个矩阵就是单位矩阵。
矩阵行列式
2×2 矩阵的行列式是对角线乘积的差。图片作者。
我们可以用一个拉普拉斯展开来计算矩阵行列式。请注意,还有更有效的算法,如矩阵分解。
矩阵轨迹
矩阵的迹是主对角线元素的和。图片作者。
轨迹可以通过沿着矩阵的主对角线对每个元素求和来计算。我们还需要检查矩阵是否是正方形的。
矩阵转置
矩阵的转置会翻转行和列。图片作者。
要在一行代码中计算矩阵转置,我们可以使用一些 Python 语言的特性;即zip
方法、使用*
操作符的参数解包和列表理解。
对称矩阵
对称矩阵等于它们的转置矩阵。图片作者。
我们可以通过比较一个矩阵与其转置矩阵来检验它是否对称。
包括单元测试在内的整个 matrix 类实现可以在这里找到。
编码训练营——他们是什么样的?
当我参加一个活动时,我经历了什么
马文·迈耶在 Unsplash 上的照片
毕业后,我从一个漫无目的的大学生变成了一个漫无目的的大学毕业生。拥有我的学位的职业并不是我理想中的。但是我决定完成我的本科学业,而不是转到一个自己不感兴趣的专业。一年多过去了,突然我发现了一件我甚至没有想象过我会喜欢的事情——编程!经过学习和实践,我决定进入科技行业,成为一名全职程序员。
但是即使自学了,在网上看了课,我还是觉得没有做好准备。经过大量的研究,我发现了在可预见的未来会改变我职业方向的东西——编码训练营 。
编码训练营?
对于那些不知道的人来说,编码训练营是一个有抱负的程序员为了向业内有经验的人学习而参加的机构或学校。他们被教授在该领域找工作所需的有价值的技能和专业知识。它的主要重点是教授编程概念,以便更好地理解和实际应用。换句话说,学生们被教导如何为这项工作编码。
由 Austin Distel 在 Unsplash 上拍摄的照片
当时,我从未真正了解过它们,它们仍然相对较新(尽管它们可能已经存在了九年)。然而,这个概念立即迷住了我。我立刻开始研究一个编码训练营的评论、经历和成果。
根据我的研究,这些训练营并不便宜。我发现的几个训练营都有很糟糕的评论和经历,这让我很警惕。然而,我确实找到了一些享有盛誉的公司。它们仍然很贵,你可能不得不申请学生贷款,但对我来说,这是值得的。
在训练营之前
就我而言,我决定参加纽约一所相当知名的大学的数据科学项目,该项目也有“退款保证”。这种“退款保证”确实有几个条件,以便有资格获得它。它们的范围从一致编码到网络义务以及介于两者之间的一切。在我看来,条件是艰苦的,但也是合理的。
申请和面试
一旦我知道要参加哪个训练营,我就递交了申请。该应用程序本身包括输入一些基本信息和安排与一名员工的视频面试。面试主要是为了评估我对数据科学项目的兴趣以及我为什么想参加。这是非常基本和随意的——他们只是想更多地了解我。后来,他们决定让我提前入学。
照片由 LinkedIn 销售解决方案在 Unsplash 上拍摄
完成我的录取
下一步是与训练营的一名教练进行第二轮面试。这次面试包括一项编码评估,旨在衡量我的编程技能。一开始有点令人紧张,但我得到了一些编程资源,可以提前热身。面试本身非常简单,编码挑战本身也很简单。导师对我的表现很满意,并同意我参加今年夏天的数据科学项目。
在交了定金以确保我的位置后,我被允许进入学校的在线平台,在那里我被要求通读并“跟着代码”几节入门课。我也获得了更多关于我应该期待什么以及如何为第一天做准备的资源。彻底复习后,我准备好了…
开学第一天
在我的第一天,我遇到了许多来自不同项目的有抱负的程序员。我们被分成我们选择的训练营项目,并被引导到大楼的不同区域。建筑的不同部分和房间容纳了每个项目的参与者。大约有 25 人参加了我的数据科学班,也就是所谓的小组。
当我们到达数据科学区时,我们每个人都被分配到一个个人办公桌,在那里我们可以完成大部分工作。很快安顿下来后,我们被通知到教室集合,正式见面。
老师们
我们的团队配备了一位具有真实世界数据科学经验、热爱教学的主要讲师。我们还有两位数据科学教练,他们是该项目的前学生。在整个项目期间,只要我们需要,这些教练都会帮助我们。
随着时间的推移,我们都是通过几次破冰游戏相互介绍认识的。之后,我们听了一个简短的讲座,内容是我们的课程和日常活动会是什么样子。
课程
我们在整个项目中的学习大部分是在我们自己的电脑上完成的,还有许多讲座和小组项目。训练营有一个强大而全面的在线平台,包含了我们需要学习的所有课程。然而,我们不允许挑选我们想学的。随着我们作为一个团队一起进步,每周都会有一些课程被解开。这样做是为了让我们都在同一页上,一起学习。
位置
训练营的校园位于曼哈顿的金融区。这是一个伟大的地区,有一吨的地方吃午餐休息,并位于水边。训练营本身非常整洁。它有一个开放的布局,各种教室和私人摊位。我会说它有现代、新兴的科技公司的感觉。我觉得这是一个学习数据科学的好地方。
学校正常的一天
每天早上,我们被随机配对进行“结对编程”。在这里,我和我的搭档接受了一个编码挑战,并被告知要在 30 分钟左右的时间内解决它。这些挑战反映了真实世界的编码面试挑战。随着时间的推移,结对编程的难度会增加。
结对编程后,我们会聚集在教室里学习当天的课程。这节课将设定一天或一周的重点,由主讲老师给我们讲。这一课将很快在我们被要求完成的在线平台上为我们解锁。
学习过程
我们在讲台上的学习大部分是我们坐在一起自己完成的。大多数课程遵循这个简单的模式:
- 阅读和学习课文。
- 根据课程内容编写代码。
- 做一个与课程相关的迷你编码项目。
韦斯·希克斯在 Unsplash 上的照片
如果我们发现自己被困在一个问题上,我们被鼓励去找我们的同学或教练。
一整天也有一些讲座。这些讲座与当天或一周的当前课程相关。对于数据科学,它通常涉及统计或编程。
我在训练营的大部分时间里,这个学习过程都是这样进行的。
小组项目
除了学习方面,很多时候我们被召集在一起参与小组项目。通常是三人或更少人一组。其目的是让我们熟悉编程和数据科学环境中的协作和合作。这些项目本身也将为潜在雇主建立我们未来的投资组合。
我们被指示开发一个与我们正在研究的当前数据科学主题相关的项目,并让我们自己决定如何合作。用于小组项目的时间长度从几天到一整周不等。
和小组演示
很多时候这些项目伴随着小组报告。这些演示基于我们项目的幻灯片。我们被教导要把重点放在项目的商业应用上,以更好地模拟现实世界的期望。
这些小组项目为我们每个人独特的编码风格提供了真正的见解。学习如何与他人合作,看看我们每个人是如何处理各种问题的,这是有趣和有益的。
特别活动
雅各布·达尔比约恩在 Unsplash 上的照片
在整个项目过程中,我们会多次举办特别活动。这些活动包括周五下班后在训练营举行的派对,以及在技术领域邀请演讲嘉宾提供食物。这些特殊事件发生的确切时间各不相同。有时是在午餐时间,有时是在下午 6 点以后。
其他时候有每周的活动,我们会在周末聚在一起讨论一周的感受。有时会有团队建设游戏,我们都可以参加。在纽约市的许多地方,我们都被鼓励去参加校外的联谊活动。
最终项目
在数据科学项目的最后几周,我们被分配了一个期末项目。这是我们计划中最伟大的项目。我们会在求职面试中自豪地展示出来。
我们可以为我们的项目选择任何主题,只要我们应用我们新学到的数据科学工具和知识。不再有小组项目——这个项目将由个人完成。我们仍然可以在某些方面寻求建议,但项目的其余部分取决于你。
新环境
为了在最后几周容纳我们,我们搬到了另一栋大楼的共同工作空间。我们将利用这个新空间来建造我们的项目。新的空间也更好,尽管我们与其他公司共用一层楼。其他公司有他们自己的房间,但我们共用公共区域和厨房。如果训练营有科技创业的感觉,这个地方有科技公司的感觉。
也是最后的陈述
马库斯·斯皮斯克在 Unsplash 上的照片
我们在项目的最后三周致力于期末项目。但更像是两个半。在最后一周的中间,我们要向学校的其他学生和任何想看的人展示我们的期末项目。演示是以一种科学博览会的方式进行的,观众们漫步到我们的每一个项目来观察我们的工作。
在做最后一个项目
我们每个人都很快去上班了。集思广益,征求意见。我们的教练和指导员会偶尔检查我们,看看我们做得如何,并确保我们在正确的轨道上。即使在这个项目上花了两个半星期,我们中的许多人仍然觉得时间不够。很多时候,我们中的一些人会发现自己熬夜只是为了完成一件事。就我而言,我几乎总是呆到晚上 8 点。
我想说在我的项目中工作是一个顺利的过程,但不是。我中途转向修复一个自己造成的错误。在整个项目中,我也有了各种各样的认识,这使我回溯了我所做的事情。最后,我还是按时完成了,我为自己的成就感到骄傲。
我的最终项目
如果你好奇的话,我以前的一篇文章实际上涉及了我最后一个项目的一个具体特征:
https://medium.com/swlh/teaching-a-machine-to-trade-stocks-like-warren-buffett-part-i-445849b208c6 [## 我建立了一个机器学习模型,像沃伦·巴菲特一样交易股票(第一部分)
medium.com](https://medium.com/swlh/teaching-a-machine-to-trade-stocks-like-warren-buffett-part-i-445849b208c6)
我的项目的最终演示也涉及到一些其他的机器学习功能。我建立了一个平台,人们可以使用大量的机器学习算法来分析任何公司的股票。我还为我的项目构建了一个前端,使它更有吸引力,这是我花了几天时间编写的。
总的来说,我花在构建项目上的时间极具挑战性和成就感。我很高兴我能按时完成我的项目,尽管有一些障碍迫使我熬夜。
训练营结束后
当我们离项目毕业还有一两周的时候,我们被指派了一名职业教练。这位教练会通过给我们建议和对求职过程的见解来帮助我们毕业后找工作。
如果你想知道更多关于我在训练营之后的时间,请随意阅读我的另一篇文章:
毕业过程非常平淡。没有像大学那样的大型仪式,但我们班更私人。毕业后,我们出去喝了几杯,开始了下一步。
我对新人的建议
如果你想参加编码训练营,这里有一些建议:
- 寻找成熟的编码训练营。
- 你会写很多代码,所以在参加之前先练习一下,这样你就不会感到不知所措了。
- 慢慢来,不要害怕在其他人都回家后呆很久。
- 尽可能多参加活动,带上你的同学。
- 做好独立学习的准备,但是向你的同伴、教练和指导者提问和寻求建议也是可以的。
你应该这样做吗?
我不建议你参加编码训练营,除非你喜欢以这样或那样的方式编码。这次经历绝对是独一无二的,我深深地享受着每一刻。我喜欢我在那里的时光,我会把它推荐给任何想进入科技行业的人!
注:我的经验是 Covid 之前的,所以它可能不能准确反映今天的训练营编码状态。
金融科技的编码语言:JVM 如何让你成功?
Java,Kotlin,Groovy,Scala,Clojure
来源:贝尔软件
BellSoft 正在用金融科技企业的顶级语言来结束 2020 年。无论你是一个正在启动你的第一个 MVP 的初创公司,一个正在崛起的企业,还是一个正在寻找创新优势的老牌公司,这个列表保证满足你所有的 IT 需求。
在这里,我们将解释为什么应该选择 JVM 语言而不是特定于平台的本地语言,看看它们的关键特性和排名。我们将特别关注语言如何应用于用例场景,涵盖从金融和银行到保险的一切。这个列表将帮助你了解每一个提供的优势和机会。在选择最适合您的项目的编程语言时,您可以遵循我们的建议。
介绍
在这项比较研究中,我们从各种来源收集数据,根据不同的参数对语言进行排名:
- TIOBE 编程社区索引,
- 编程语言流行指数(PYPL)、
- JetBrains,Stack Overflow 和 GitHub 开发者调查。
我们的研究仅涵盖 2020 年,因此你可以获得最相关的行业概况——因为在金融科技领域,了解最新动态至关重要!
但是首先,我们想解释一下这篇文章的重点。许多人会说 Python 最适合金融科技公司,因为它对开发人员友好,适应性强。尽管这可能是真的,但对高风险企业来说,它缺乏某些好处。从历史上看,金融机构广泛使用的是 Java。考虑到数据安全性、生产率和稳定性是他们的首要任务,他们经常转向基于 Java 的语言。
1995 年,詹姆斯·高斯林引入 Java 作为高级面向对象编程语言。从一开始,它的一个关键特性就是平台独立性,这是由 Java 虚拟机(JVM)带来的。JVM 从底层物理硬件和操作系统中抽象出来。有了这种高效的程序执行方式,Java 开发人员就不需要关注对象生命周期管理或其他底层的复杂问题。相反,他们能够将全部精力投入到业务逻辑中。
多年来,JVM 在垃圾收集、性能和成熟度方面有了显著的改进。编程语言设计者意识到了这种运行时的潜力。因此,许多著名的、主流的、甚至更新的语言都是用 JVM 提供的特性和巨大的类库开发的。每个企业现在都可以找到满足其需求的解决方案。
当甲骨文在 2018 年 7 月为 JDK 推出基于订阅的许可时,IT 社区内部对 JVM 的状态存在轻微的不确定性。幸运的是,由于 OpenJDK 倡议,JDK 规范仍然是免许可和开源的。一些公司现在提供他们自己的开源 Java SE 实现,包括 BellSoft。其 Liberica JDK 是市场上领先的运行时之一,具有可选的企业支持。
既然我们已经介绍了历史,那么是时候进行我们的抵抗了:金融技术行业的最佳 JVM 语言列表: Java、Kotlin、Groovy、Scala 和 Clojure 。你会发现猜第一个不会太难…
1.Java 语言(一种计算机语言,尤用于创建网站)
Java 是商业应用程序开发的主要选择,也是最主要的语言之一。它是第一个构想并广泛接受“编写一次,在任何地方运行”范式的公司,该范式专注于开发人员的生产力和人体工程学。它为 Python、JS 和 Kotlin 等其他语言的成功铺平了道路。Java 采用了许多实用的概念,如内存模型、中间表示(字节码)、多线程和作为一等公民的处理函数。作为迄今为止最具颠覆性和影响力的编程语言之一,Java 已经永远地改变了软件开发的前景。
让我们看看为什么它现在几乎和 25 年前一样成功:
稳定可靠
N26 ,一家在单一欧元支付区和美国提供服务的德国新银行,使用 Java(确切地说是 RxJava)来构建 Android 应用程序。1 它提供了一个标准工作流来管理应用程序中的所有数据和事件。这就是它在 Android 开发者中日益流行的原因。工程团队实现了关注点的清晰分离,这使得特性更容易在代码中导航,并改进了代码审查。
看一看应用程序功能的一个简短片段,显示用户信用草稿列表:
Flowable<Option<List<CreditDraft>>> getAllCreditDrafts() {
return store.getAll();
}Completable fetchCreditDrafts() {
return creditService.getCreditDrafts()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
// map from raw to safe
.flatMapObservable(Observable::fromIterable)
.map(creditDraftMapper)
.toList()
// put mapped objects in store
.doOnSuccess(store::replaceAll)
.toCompletable();
}
Java 不是为移动开发而构建的?我们不同意。一个银行系统,无论是运行在服务器上还是云中,都必须是健壮的,能够持续工作多年,而不需要做任何调整。在这里,Java 是一种理想的语言,拥有一个大型的、成熟的生态系统和不间断的变化。
曾经流行过
Java 是目前为止企业和后端开发中使用最多的技术。大多数流行的编程语言排名网站都倾向于将它放在首位。
专门评估和跟踪软件质量的 TIOBE 将 Java 评为 2020 年第二大最受欢迎的语言,也是过去 20 年中最受欢迎的两种语言之一!在此期间,它只被 C 语言超越过几次。
来源: TIOBE
对于 2020 年, PYPL (编程语言流行指数),基于谷歌趋势数据,将 Java 列为仅次于 Python 的第二大流行编程语言。这里我们想指出的是,Java 只是在 2018 年失去了领先地位。
来源: PYPL
此外, JetBrains 的第四次年度开发者调查将其排在第二位,仅次于 JavaScript。
来源: JetBrains
裁决
Java 正面临来自 Python 和 JavaScript 的激烈竞争。它可能永远不会拥有曾经在该行业拥有的市场份额。然而,开发人员仍然认为学习 Java 是对未来的安全投资,因为职位空缺的数量和以前一样多。考虑到 Java 的采用量和它最近的许多创新,它将仍然是未来商业软件开发的首选。
2.科特林
最近,Java 在开发人员体验和人机工程学方面受到了很多批评:它冗长,产生样板代码,容易出现意外特性,并且缺少许多现代特性。其他几种语言试图解决这些缺点,努力成为“更好的 Java”我们坚信科特林是其中的佼佼者。
流行的 IntelliJ IDE 背后的公司 JetBrains 在 2016 年发布了 Kotlin。它试图在不影响编译时间的情况下解决 Java 的问题。Kotlin 引入了许多来自其他先进的、高生产率语言的优秀特性。它被认为是 Java 的更简单、更现代、更简洁的替代品。
Android 和许多企业应用支持旧的 LTS 版本的 Java。在这种用例中,Kotlin 为开发人员提供了更强大的现代语言特性,因为 Kotlin 可以面向各种旧的 JDK 版本(如 Java 6 或 7)。
2019 年,当谷歌宣布 Kotlin 为首选 Android 应用程序开发选项时,kot Lin 获得了显著的推动。但为什么增长如此之快呢?
两全其美
万事达卡与 Corda 达成合作伙伴关系,共同开发并试点一种新的基于区块链的跨境支付解决方案。2 它连接由万事达卡运营的清算和结算网络支持的全球快速支付基础设施、方案和银行。Corda 是一个用 Kotlin 编写的开源区块链项目,用于存储、管理和同步各种金融机构之间的金融义务。
这个例子摘自 Corda 项目:
/ Add this import:
import net.corda.core.identity.Party
// Replace TemplateState's definition with:
@BelongsToContract(TemplateContract::class)
class IOUState(val value: Int,
val lender: Party,
val borrower: Party) : ContractState {
override val participants get() = listOf(lender, borrower)
}
如果团队希望一方面利用创新,另一方面利用 JVM 提供的可持续性,Kotlin 是理想的选择。与 Java 相比,这种语言以其进步的特性、平坦的学习曲线和更高的开发速度吸引着许多公司。
在上涨
Kotlin 于 2016 年首次发布,越来越受欢迎,正在成为顶级趋势语言。截至 2020 年 12 月,它在 PYPL 上排名第 13,仅次于 TypeScript 和 Go。看到它在 Ruby(第 14)这样的强手之上,已经是一个相当令人印象深刻的结果了。
Kotlin 专为更好的开发人员人体工程学而设计,在全球范围内广受欢迎。根据 Stack Overflow 2020 开发者调查,对于近 63%的受访者来说,它是第四大最受欢迎的语言,仅次于 Python。
根据 GitHub Octoverse 的数据,2019 年至 2020 年间,它的年同比增长率为 182%,是全球增长最快的编程语言之一。
JetBrains 2020 年开发人员调查表明,Kotlin 是开发人员最想移植和采用的三种主要工具语言之一:
来源: JetBrains
裁决
Kotlin 是少数几个在酷功能和简单性之间取得平衡的例子之一。下一个十年,它肯定会更受欢迎。对于那些想学习一门高产语言或尝试 Android 应用程序开发的好奇者来说,Kotlin 是一个绝佳的选择。一些人甚至声称,在不久的将来,押注科特林将是一个明智之举。你可以在 BellSoft 关于 Kotlin 的两部分系列文章中了解更多关于它的特性以及这种语言对行业的意义。
3.绝妙的
在特定的场景中,从开发速度的角度来看,动态类型语言比静态类型语言有显著的优势。受 Python 和 Ruby 的启发,James Strachen 在 2003 年开始为 JVM 开发动态类型编程。四年后,Groovy 作为同类产品中的第一个问世。它引入了类似 Python 的干净编码和类似 Ruby 的动态性。
Groovy 是一种值得尊敬的语言选择,并被广泛使用,原因如下:
它是可选的类型和多范例(面向对象的、函数式的、命令式的、脚本式的)。
Groovy 带来了许多实用功能:类型推断、多行字符串、闭包、原型扩展。这种方法后来严重影响了其他语言,如科特林。
- 它与 Java 无缝兼容,并拥有庞大的库生态系统。很多流行的框架,比如 Spring,都支持 Groovy。
- 它可以用于特定领域语言(DSL)。它还支持在运行时实现特征。
- 通过元对象协议而不是直接调用方法来调度方法使其具有很高的性能。
- Groovy 现在是 Apache software foundation 的一部分,在业界得到了广泛应用。由于其动态、简洁的特性,它是脚本、工具和开发人员的理想选择。Gradle、Jenkins 和 SoapUI 等流行工具使用 Groovy 作为主要编程语言。处于 DevOps 和架构领域也延长了它的生命周期。
速度是关键
总部位于澳大利亚的 Auto & General Insurance 有限公司需要内部工具来管理其 DevOps 系统。它计划为 Gradle 创建一个类似 Maven 原型的插件,从本地模板生成项目。对于这个其他系统依赖的小规模项目来说,快速开发至关重要。由于 Groovy 的动态特性、对 DSL 的支持以及在 DevOps 领域的广泛采用,它是与公司现有工具进行互操作的最佳选择。
一点点可以走很长的路
Groovy 是一种成熟的编程语言,在 JVM 中提供了类似 Python 的生产力。这种组合证明了它在各种小型任务中的优势:工具、脚本、概念开发的证明。因此,尽管它不是像 Java 或 Kotlin 那样的通用语言,但它还是相对较受欢迎。
2020 年 12 月,Groovy 从第 12 位升至第 11 位。
然而, PYPL 指数同月排名第 23 位:0.45%的市场份额似乎并不值得夸耀。
裁决
可选类型的 Groovy 不适合大规模开发:它的好处在于快速交付和动态性。方法缓存和其他实用特性是出色性能背后的秘密。企业认为 Groove 是一种成熟的语言,无论如何都会有用户。
4.斯卡拉
从事 Java 泛型和当前 Java 编译器 javac 工作的 JVM 老手 Martin Odersky 决定研究 Java 的缺点。2004 年,他发布了 Scala,结合了许多函数式编程特性和面向对象的范例。它成为最早将 JVM 作为运行时平台的语言之一。Scala 成功地加速了技术进步,并直接促进了 Java 的现代化。如果没有这种语言,这个行业就不一样了:在过去的十年中,它在推广函数式编程范例方面发挥了关键作用。
它有什么特点?
惊人的表现
2016 年, PayPal 将 Scala 作为其系统的一部分,以增加其可以接收的交易量。5 基于 Akka(一个运行时和工具包,用于简化在 JVM 上构建应用程序)和 Akka Streams,由 Scala 和 Kafka 提供支持;他们新的开源 squbs 平台展示了令人难以置信的结果。应用程序每天处理超过 10 亿次点击,“每个应用程序只有 8 个虚拟机和 2 个虚拟 CPU。”之前,有了 Spring/Java 组合,公司的业绩几乎是团队所取得成绩的十分之一。
PayPal 对技术堆栈的要求是:
- 水平和垂直可扩展性,
- 近乎实时的性能,
- 高效的资源利用(最有可能用于云部署),以及
- 高爆裂下的弹性。
下面你会看到一个永恒的流,它随着系统而开始和停止。它提供了一个便利的特性,可以帮助编写由系统生命周期控制的流,同时最小化甚至消除消息丢失。它提供了定制钩子和 killSwitch(来自 Akka)来嵌入到流中。
class MyStream extends PerpetualStream[Future[Int]] {
def generator = Iterator.iterate(0) { p =>
if (p == Int.MaxValue) 0 else p + 1
}
val source = Source.fromIterator(generator _)
val ignoreSink = Sink.ignore[Int]
override def streamGraph = RunnableGraph.fromGraph(
GraphDSL.create(ignoreSink) { implicit builder =>
sink =>
import GraphDSL.implicits._
source ~> killSwitch.flow[Int] ~> Sink
ClosedShape
}
)
}
在这里,Scala 非常适合其函数式编程特性以及与 Apache Spark 和 Apache Flink 等主流流媒体平台的潜在互操作性。
总能找到自己的目标
尽管 Scala 发布时被看好,被认为会超越 Java,但它仍然是一种特殊用途的语言。我们看到它的采用在过去五年里趋于平缓。但是在数据密集型应用和流处理领域,Scala 几乎超越了所有其他应用,包括 Java 和 Kotlin。此外,许多广受好评和流行的框架和运行时支持该语言(如 Akka、Play、Finagle、Lagom),证明了它在行业中的强大立足点。
裁决
Scala 在改进 Java 方面有发言权,并影响了许多其他现代语言,包括 Kotlin 但是它还没有得到更广泛的接受。它多年来引入的许多突破性变化在企业中并没有得到很好的接受。它真正擅长的一件事是流处理,上面的 PayPal 用例显示了这一点。最新发布的 Scala 3 最终采用了实用主义特性,成为一种更主流的语言。我们确实希望这个版本有潜力使它成为通用的,并在更大范围内使用。
5.Clojure
Lisp 是最早的高级编程语言之一,发布于 1958 年。很久以后,一位著名的软件工程师 Rich Hickey 致力于创建一种针对 JVM 的动态的、功能性的通用 Lisp 方言,后来成为 Clojure。与结合了面向对象和函数式范例的 Scala 不同,Clojure 是一种纯函数式语言。它有一个 Lisp 宏系统,把代码当作数据,把程序当作模型。Clojure 鼓励不变性和不可变的数据结构,并明确管理身份及其状态。
我们可以把它的主要特点总结如下:
微观分析
Nubank 是拉丁美洲最大的金融科技公司,于 2018 年成为独角兽创业公司,它与 Clojure 开发了一个复式会计系统。该公司声称这是“一项使用了几个世纪的古老技术”,它与这种函数式编程语言有着奇妙的联系。在它的要求中,Nubank 提到语言应该能够并行处理,提供可维护的代码,并管理变量。
这里有一部分代码展示了运动的声明性规则:
(def new-purchase
[{:entry/debit-account :book-account.asset/settled-brazil
:entry/credit-account :book-account.liability/payable-brazil
:entry/amount (comp :amount :purchase)
:entry/post-date (comp time->date :time :purchase)}
{:entry/debit-account :book-account.liability/payable-brazil
:entry/credit-account :book-account.profit-and-loss/interchange-brazil
:entry/amount (comp :interchange :purchase)
:entry/post-date (comp time->date :time :purchase)}
{:entry/debit-account :book-account.liability/current-limit-counterparty
:entry/credit-account :book-account.asset/current-limit
:entry/amount (comp :interchange :purchase)
:entry/post-date (comp time->date :time :purchase)])
这种系统允许通过任何标准行为对特定用户或用户组进行分析。例如,该公司可以预测其客户明年将花费多少。
非常适合绿地
由于其开发速度和干净的代码,Clojure 越来越受到从零开始从事大规模项目的公司的欢迎。对于特定的用例(例如,并发编程、大数据项目),它是一种优秀的语言;缓慢但稳定地,它在行业中获得牵引力。尽管如此,Clojure 还不是一种通用的主流编程语言。
裁决
尽管 Clojure 在它所做的事情上非常优秀,但它缺乏 Kotlin 或 Groovy 的实用主义。企业通用语言既需要面向对象的范例,也需要函数式范例。我们预测 Clojure 不会超出它的范围,仍然是专用的。
摘要
到目前为止,JVM 是使用最广泛的进程虚拟机。它强大,久经沙场,经受住了时间的考验。在本文中,我们解释了金融科技公司如何从 JVM 的多功能性中受益,并总结了 5 种基于 JVM 的顶级语言,每种语言都有其优势和特定的用例。
使用这五个选项中的一个,任何业务任务都是可能的。您可以放心,在任何情况下,您的解决方案都将是高性能的、实施快速的,并且在未来许多年都是适用的。
如果您想进一步了解基于 JVM 的解决方案如何推进您的业务,请联系 BellSoft。该公司的工程师愿意分享他们在 JDK 世界工作十年来收集的最佳实践。他们会很乐意回答您的所有问题,并提供满足您需求的渐进式 Java 运行时。
参考
- n26/n26 androidsamples GitHub
- 万事达卡与 R3 合作开发基于区块链的新型跨境支付解决方案
- 科达 GitHub
- 汽车&通用保险有限公司 GitHub
- PayPal 仅使用 8 台虚拟机,通过 Akka、Scala、Kafka 和 Akka 流,每天就能完成超过 10 亿笔交易
- 建立强大的复式记账系统——卢卡斯·卡瓦尔康蒂
我与BellSoft合作撰写了这篇文章,原文发表于【https://www.bell-sw.com】。
类似文章
* </21-predictions-about-the-software-development-trends-in-2021-600bfa048be> *