如何处理 ML 中的不平衡数据和小训练集
不平衡数据是指每个类的观察值数量分布不均,通常有一个主要类占数据集的比例较大,而次要类没有足够的示例。
按作者分类的图表
小的训练集也苦于没有足够的例子。这两个问题在现实应用中非常普遍,但幸运的是有几种方法可以克服这个问题。本文将通过许多不同的技术和视角来应对不平衡数据。特别是,您将了解到:
- 采样技术(上采样和下采样)
- 加权损失
- 数据扩充技术
- 迁移学习
不平衡的数据如何影响你的模型?
不平衡数据是数据科学中常见的问题。从图像分类到欺诈检测或医疗诊断,数据科学家面临不平衡的数据集。不平衡的数据集会降低模型对少数类的敏感度。让我们用简单的数学来解释一下:
想象一下,你有 10000 张肺部 x 光图像,其中只有 100 张被诊断为肺炎,这是一种传染病,会使一个或两个肺部的气囊发炎,并使它们充满液体。如果你训练一个模型,预测每个例子都是健康的,你会得到 99%的准确率。哇,多棒啊?错了,你刚刚用你的模型杀了很多人。
作者图片
通常,我们通过准确性来衡量模型的表现,但是不平衡的数据会误导我们,就像上面的例子一样。这篇文章的重点是如何处理这些情况,我不会详细介绍如何衡量您的模型,但请记住,要将衡量指标从准确性改为精确度、召回、F1 分数。但是即使他们实际上也没有那么伟大。在处理不平衡数据时,我建议选择: AUC 曲线、 平均精度。这是一个令人惊叹的 github 知识库,它通过谈论一个特定的不平衡数据集示例来深入研究这些指标的细节:信用卡欺诈。
比方说,我们有一个不平衡的数据集,我们无法访问更多的数据。所以我们应该创建自己的数据。下一章将在高抽象层次上介绍这些技术,我还添加了一些用 Python 实现这些技术的参考资料。
取样技术
您可以通过重采样来平衡数据。以下是两种不同的重采样技术:
- 向上采样(增加你的少数类)
- 向下采样(减少多数类)
对于这两者,我们将使用 Sklearn 重采样函数。让我们导入库并将我们的数据定义为df
:
# Importing the libraries
import numpy as np
import pandas as pd
from sklearn.utils import resample# Importing the dataset
# Read dataset
df= pd.read_csv('data.csv')
在本例中,我们有一个二元分类问题,其中多数类表示为 1,少数类表示为 0。让我们把它们分开:
# Separate majority and minority classes
df_majority = df[df.iloc[:,4608]==1]
df_minority = df[df.iloc[:,4608]==0]
我们可以对多数类进行下采样,对少数类进行上采样,或者两者兼而有之。你应该试一试,看看哪一款最适合你。您可以调整的另一个超参数是n_samples
,它是您重新采样的样本数。
# Separate majority and minority classes
df_majority = df[df.iloc[:,4608]==1]
df_minority = df[df.iloc[:,4608]==0]
# Downsample majority class
df_majority_downsampled = resample(df_majority,
replace=False,
n_samples=1000)#Upsample minority class
df_minority_upsampled = resample(df_minority,
replace=True,
n_samples=1000)# Combine minority class with downsampled majority class
df_up_down_sampled = pd.concat([df_majority_downsampled, df_minority_upsampled])
最后显示新的班级人数:
df_downsampled.prediction.value_counts()
恭喜你,你给权力带来了平衡。🎉
编辑:我最近被问到的一个面试问题: 你如何确保你的上采样&下采样数据来自良好的分布/你如何衡量这些方法的性能?
衡量这些方法性能的一个简单方法是获取用这些额外数据训练的新模型的测试结果。大多数情况下,进行上采样时,您可能会先看到性能有所提高,然后趋于平稳,甚至有所下降。我会选择数量最少、性能最高的上采样数据。
但是有时候重采样本身是不够的。本文继续介绍更高级的技术。
加权损失
避免阶级失衡的另一个方法是用不同的方式来衡量损失。要选择权重,首先需要计算类别频率。
*# Count up the number of instances of each class (drop non-class columns from the counts)*
class_counts = df_classes.sum()#print the class frequencies **for** column **in** class_counts.keys():
print(f"The class **{**column**}** has **{**df_classes[column].sum()**}** samples")
通过更改损失函数中的权重,数据科学家可以平衡每个类别的贡献。一种方法是将每个类中的每个例子乘以一个特定于类的权重因子,这样每个类的总体贡献是相同的。
感谢 Sklearn,在大多数 ML 算法中有一个内置的参数 class_weight,它可以帮助你平衡每个类的贡献。例如,在 Sklearn 的 RandomForestClassifier 中,您可以选择 balanced、balanced_subsample,或者您可以手动给每个类一个字典的权重。
#Fitting RandomForestClassifier
from sklearn.ensemble import RandomForestClassifiermodel = RandomForestClassifier(n_estimators=1000, class_weight={0:0.10, 1:0.90})
Amazing🥳,现在你学会了一个非常普通的技术,你可以用每一种最大似然算法应用几乎每一种数据。让我们深入了解更先进的技术。
数据扩充
从现在开始,我将要提到的技术主要适用于计算机视觉和图像。使用图像时,有多种方法可以生成数据。
众所周知,数据扩充是一种非常强大的技术,用于在现有图像中人工创建变化,以扩展现有图像数据集。这从代表可能图像的综合集合的现有图像数据集中创建新的和不同的图像。以下是增加数据集的几种方法。
- 轻弹
- 一款云视频会议软件
- 轮流
- 剪羊毛
- 种植
- 最后用生成性对抗网络生成新图像。
注意:有时候使用这些技术对你的模型有害无益。让我们假设相同的肺部 X 射线数据集情况,其中我们有许多不同的 X 射线。如果你翻转图片,你会在右边看到一颗心,它可以被看作是一个 cist。你又杀了人=(所以要小心使用这些增强技术。
迁移学习
如果您没有足够的数据来概括您的模型,您可以使用预先训练的模型,并针对您自己的任务调整它们。这被称为迁移学习,在计算机视觉领域非常普遍。自从培训以来,庞大的模型需要花费如此多的时间和资源,人们正在获得像 DenseNet 这样的预培训模型并使用它们。方法如下:
- 找到符合你要求的型号
- 重用模型。这可能涉及使用模型的全部或部分或神经网络的第一层。由于要素的复杂性随着层数的增加而增加,因此第一层总是具有更多可以成功使用的通用要素。
- 微调:通过深入,神经网络在任务上变得专业化,所以你可能想要为你自己的任务调整最后几层,这被称为微调。
摘要
我们学习了 4 种不同的技术,您可以将其应用于不平衡的数据/小型训练集。现在,您知道如何通过以下方式提高模型的性能:
- 使用取样技术
- 改变损失函数的类权重
- 使用数据增强技术
- 利用迁移学习
其中最后两个更专门针对计算机视觉。我希望这篇文章能帮助你理解如何用不同的技术克服不平衡数据问题。祝贺你完成这篇文章,感谢你一直以来的阅读。
参考资料:
- https://machine learning mastery . com/resample-interpolate-time-series-data-python/
- https://towards data science . com/data-augmentation-techniques-in-python-f 216 ef 5 eed 69
- https://machine learning mastery . com/transfer-learning-for-deep-learning/
- https://machine learning mastery . com/tactics-to-combat-unbalanced-classes-in-your-machine-learning-dataset/
如何在 Python 中正确处理地图投影
Python 中概念和代码的演练
西蒙·米加吉在 Unsplash 上的照片
如果您曾经尝试叠加地理空间数据,结果发现它们没有正确对齐,那么您很可能遇到了令人烦恼的坐标参考系统问题。在本教程中,我们首先阐明坐标参考系统(CRS)的概念和术语,然后介绍如何使用地理空间数据在 Python 中处理 CRS。
嘿,墨卡托——非洲比北美大
M 无论是纸上的还是屏幕上的,AP 大多是平面的,二维的。然而,地球不是二维的。因此,地图总是会说谎——在某种程度上。为了表现地球的大部分,你必须在大小、角度、形状或方向之间进行权衡。你不可能全部答对。那么在平面上表现地球的最好方式是什么呢?
嗯,看情况吧!这就是为什么我们今天在大多数网络地图上使用墨卡托投影。墨卡托投影保持所有角度的正确形状,这意味着如果您使用该投影测量角度,您将获得真实世界中的正确方向,这对地图导航非常有用。
但是,您不能在 web Mercator 中比较不同国家的大小,因为它不保留大小。非洲大陆比它看起来要大得多,加拿大和俄罗斯占据了很大的面积,而实际上,它们只占地球表面的 5%。
地理与预测
这里有两个密切相关的概念需要澄清。我们有地理坐标系,主要用于全球制图。地理坐标系通常使用纬度和经度。相比之下,有多个局部投影会带来视觉失真,称为投影坐标系。通用横轴墨卡托坐标系、国家平面和罗宾逊投影是最广泛使用的投影。
在地理坐标系中,测量单位是十进制度,这有助于定位地球上的位置。然而,要用米或英尺等其他单位来测量距离,我们需要投影。
带 Geopandas 的 CRS
由于 Geopandas 的存在,只要对坐标参考系统和投影有一个基本的了解,就可以很容易地在 Python 中正确处理它们。让我们阅读三个不同的数据集来说明正确处理投影的重要性。
import geopandas as gpd
import matplotlib.pyplot as plt# Read world Countries
world = gpd.read_file(
gpd.datasets.get_path(“naturalearth_lowres”)
)# Read world cities
cities = gpd.read_file(
gpd.datasets.get_path(“naturalearth_cities”)
)# Read Graticules
graticules = gpd.read_file(
“ne_110m_graticules_10/ne_110m_graticules_10.shp”
)
要知道数据是哪个坐标参考系,Geopandas 有.crs()
,可以提供数据及其参考系的信息。
world.crs
让我们看看并理解这个方法的输出。
<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich
首先,数据位于地理 2D CRS 和世界大地测量系统(WGS84)中。我们通常使用不同坐标系的代码。WGS84 的代码是 EPSG:4326。你可以从 EPSG.io 网站找到这些代码,或者在空间参考组织中搜索。
我们需要检查所有的数据集是否有相同的 CRS,然后将它们绘制在一起。
cities.crs == world.crs == graticules.crs
这将返回 True,因为所有数据集都具有相同的坐标系。因此,让我们继续在地图上绘制数据。
fig, ax = plt.subplots(figsize=(12,10))
world.plot(ax=ax, color=”lightgray”)
cities.plot(ax=ax, color=”black”, markersize=10, marker =”o”)
graticules.plot(ax=ax, color=”lightgray”, linewidth=0.5)
ax.set(xlabel=”Longitude(Degrees)”,
ylabel=”Latitude(Degrees)”,
title=”WGS84 Datum (Degrees)”)plt.show()
WGS84 中的世界地图
还要注意 x 轴和 y 轴,它们有十进制度数。
预测
为了投影任何地理数据,Geopandas 也有采用投影代码的.to_crs()
方法。让我们重新投影数据。让我们从埃克特四号投影开始。
埃克特 IV 投影是一个等面积 伪圆柱地图投影。极线的长度是赤道的一半,经线是半椭圆,或者说是椭圆的一部分。— 维基百科
world_eckert = world.to_crs(“ESRI:54012”)
graticules_eckert = graticules.to_crs(“ESRI:54012”)
现在,让我们打印出这些投影数据集的 CRS。世界埃克特投影数据集具有以下参数。
<Projected CRS: ESRI:54012>
Name: World_Eckert_IV
Axis Info [cartesian]:
- E[east]: Easting (metre)
- N[north]: Northing (metre)
Area of Use:
- name: World
- bounds: (-180.0, -90.0, 180.0, 90.0)
Coordinate Operation:
- name: World_Eckert_IV
- method: Eckert IV
Datum: World Geodetic System 1984
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich
请注意世界数据集和世界埃克特投影数据集之间的差异。后者有投影 CRS,而前者有地理 2D CRS。第一个数据集的轴是以度为计量单位的椭球体,而后一个数据集的轴是以米为计量单位的笛卡尔坐标。
现在,让我们尝试绘制这两个投影数据集和未受保护的城市数据集。由于我们将多次绘制这些地图,所以让我们创建一个函数并绘制它们。
def plot_map(gdf1, gdf2, gdf3, name,unit):
fig, ax = plt.subplots(figsize=(12,10))
gdf1.plot(ax=ax, color=”lightgray”)
gdf2.plot(ax=ax, color=”black”, markersize=10, marker =”o”)
gdf3.plot(ax=ax, color=”lightgray”, linewidth=0.5)
ax.set(xlabel=”X Coordinate -”+unit,
ylabel=”Y Coordinate -” +unit,
title=name
)plt.show()plot_map(world_eckert, cities, graticules_eckert, "Eckert IV - Cities not Projected", "Metre")
城市点数据集在哪里?
不匹配的投影图
这些城市聚集在一个地方。大多数情况下,GIS 世界中的未对齐图层问题是由不匹配的 CRS 和投影造成的。我们可以通过将城市数据集投影到埃克特四投影来解决这个问题。
cities_eckert = cities.to_crs(“ESRI:54012”)
plot_map(world_eckert, cities_eckert, graticules_eckert, “Eckert IV — With projected Cities”, “Metre”)
正确匹配的世界地图-埃克特投影。
最后,让我们展示另一个投影,并展示任何投影之间的差异。让我们用罗宾逊投影。
world_robinson = world.to_crs(“ESRI:54030”)
graticules_robinson = graticules.to_crs(“ESRI:54030”)
cities_robinson = cities.to_crs(“ESRI:54030”)plot_map(world_robinson, cities_robinson, graticules_robinson, "Robinson Projection", "Metre")
世界罗宾逊投影
上面两个投影乍看起来可能是一样的,但它们是不同的。我们可以看到两个投影的重叠图。
埃克特投影(蓝色)和世界罗宾逊投影(红色)
对不同投影进行的任何计算都会产生不同的结果,例如,面积大小或距离。
结论
在本文中,我们解释了地理坐标参考系统(CRS)和投影坐标的基本概念。我们还看到了如何使用 Geopandas 在 Python 中正确处理它们。
如何处理交叉验证中的缺失值
为什么我们不应该用熊猫
处理缺失值是机器学习流水线中一个重要的数据预处理步骤。
Pandas 在检测和处理缺失值方面是通用的。然而,当涉及到交叉验证的模型训练和评估时,有一种更好的方法。
scikit-learn 的估算器以及管道提供了一种更实用的方法来处理交叉验证过程中的缺失值…
在本帖中,我们将首先做几个例子,展示处理熊猫缺失值的不同方法。之后,我将解释为什么我们需要不同的方法来处理交叉验证中的缺失值。
最后,我们将使用 scikit-learn 的缺失值估算器和管道来做一个示例。
先说熊猫吧。这是一个简单的数据框架,有几个缺失值。
import numpy as np
import pandas as pddf = pd.DataFrame(np.random.randint(10, size=(8,5)), columns=list('ABCDE'))df.iloc[[1,4],[0,3]] = np.nan
df.iloc[[3,7],[1,2,4]] = np.nandf
isna 函数返回布尔值,指示缺少值的单元格。isna()。sum()给出了每一列中缺失值的数量。
df.isna().sum()
A 2
B 2
C 2
D 2
E 2
dtype: int64
fillna 函数用于处理缺失值。它提供了许多选项来填写。让我们对每一列使用不同的方法。
df['A'].fillna(df['A'].mean(), inplace=True)df['B'].fillna(df['B'].median(), inplace=True)df['C'].fillna(df['C'].mode()[0], inplace=True)df['D'].fillna(method='ffill', inplace=True)df['E'].fillna(method='bfill', inplace=True)
列 A、B 和 C 中缺少的值分别用该列的平均值、中值和众数填充。对于 D 列,我们使用“ffill”方法,该方法使用该列中的前一个值来填充缺失的值。“bfill”的作用正好相反。
以下是数据框架的更新版本:
我们在 D 列中仍然缺少一个值,因为我们对该列使用了“bfill”方法。使用这种方法,丢失的值应该用后面的值来填充。由于最后一个值是一个缺失值,因此未对其进行更改。
fillna 函数也接受常数值。让我们用一个常量替换最后一个缺失的值。
df['E'].fillna(4, inplace=True)
如您所见,fillna 函数非常灵活。然而,当涉及到训练机器学习模型时,我们需要小心处理丢失的值。
除非我们使用常量值,否则需要在拆分训练集和测试集后处理缺失值。否则,模型将被给予关于导致数据泄漏的测试集的信息。
数据泄露是机器学习中的一个严重问题。不应该给机器学习模型任何关于测试集的信息。测试集中的数据点需要是以前看不见的。
如果我们使用整个数据集的平均值来填充缺失值,我们会将关于测试集的信息泄露给模型。
一种解决方案是在训练测试分割后处理缺失值。这绝对是一种可以接受的方式。如果我们想做交叉验证呢?
交叉验证意味着将数据集划分为子集(即折叠)。然后,使用不同的组合运行许多迭代,以便每个示例都将在训练和测试中使用。
考虑 5 重交叉验证的情况。数据集被分成 5 个子集(即折叠)。在每次迭代中,4 个折叠用于训练,1 个折叠用于测试。经过 5 次迭代后,每个折叠都将用于训练和测试。
我们需要一种实用的方法来处理交叉验证过程中的缺失值,以防止数据泄漏。
一种方法是用 scikit-learn 创建一个管道。管道接受数据预处理功能,并可用于交叉验证过程。
让我们创建一个适合简单线性回归任务的新数据框架。
df = pd.DataFrame(np.random.randint(10, size=(800,5)), columns=list('ABCDE'))df['F'] = 2*df.A + 3*df.B - 1.8*df.C + 1.12*df.D - 0.5df.iloc[np.random.randint(800, size=10),[0,3]] = np.nandf.iloc[np.random.randint(800, size=10),[1,2,4]] = np.nandf.head()
从 A 列到 E 列有 10 个缺失值。F 列是具有附加偏差的其他列的线性组合。
让我们导入任务所需的库。
from sklearn.linear_model import LinearRegressionfrom sklearn.pipeline import Pipelinefrom sklearn.impute import SimpleImputer
简单估算器根据给定的策略填充缺失值。我们可以创建一个包含简单估算对象和线性回归模型的管道。
imputer = SimpleImputer(strategy='mean')regressor = Pipeline(
steps=[('imputer', imputer), ('regressor', LinearRegression())]
)
“回归”管道包含一个简单的估算器,用平均值填充缺失值。线性回归模型完成预测任务。
我们现在可以使用这个管道作为交叉验证的估计量。
X = df.drop('F', axis=1)
y = df['F']scores = cross_val_score(regressor, X, y, cv=4, scoring='r2')scores.mean()
0.9873438657209939
R 平方得分相当高,因为这是一个预先设计的数据集。
这里重要的一点是在分割训练集和测试集之后处理缺失值。如果我们做一个常规的训练测试分割,这在熊猫身上很容易做到。
但是如果要做交叉验证,用熊猫会很繁琐。scikit-learn 库的管道提供了一种更实用、更简单的方法。
管道的范围相当广泛。您还可以在管道中添加其他预处理技术,例如用于数值的缩放器。使用管道可以实现某些任务的自动化,从而优化流程。
感谢您的阅读。如果您有任何反馈,请告诉我。
如何在 Python 中处理缺失值
入门指南
缺失值插补的简明介绍
马库斯·温克勒在 Unsplash 上的照片
数据科学家面临的最大挑战可能是一些听起来很平常,但对任何分析都非常重要的事情——清理脏数据。当您想到脏数据时,您可能会想到不准确或格式错误的数据。但事实是,缺失数据实际上是脏数据最常见的情况。想象一下,试图做一个客户细分分析,但 50%的数据没有地址记录。这将很难或不可能做你的分析,因为分析会显示在某些地区没有客户的偏见。
探索缺失的数据
- **有多少数据丢失了?**您可以运行一个简单的探索性分析,看看您丢失数据的频率。如果百分比很小,比如说 5%或更少,并且数据完全随机丢失,那么您可以考虑忽略并删除这些情况。但是请记住,如果可能的话,分析所有数据总是更好,丢弃数据会引入偏差。因此,最好检查一下分布情况,看看丢失的数据来自哪里。
- 分析数据是如何丢失的 (MCAR,三月,四月)。我们将在下一节中发现不同类型的缺失数据。
缺失数据的类型
有三种缺失数据:
- 数据完全随机丢失(MCAR)
- 数据随机丢失(MAR)
- 非随机数据丢失(MNAR)
在这篇文章中,我将通过例子回顾缺失数据的类型,并分享如何用插补来处理缺失数据。
数据完全随机丢失(MCAR)
当我们说数据是随机缺失的时候,我们的意思是缺失与被研究的人无关。例如,一份问卷可能在邮寄过程中丢失,或者一份血样可能在实验室中被损坏。
数据完全随机缺失的统计优势是分析保持无偏,因为数据缺失不会使估计参数产生偏差。然而,很难证明这些数据是否确实是 MCAR 的。
数据随机丢失(MAR)
当我们说数据随机缺失时,我们假设一个数据点缺失的倾向与缺失数据本身无关,但与一些观察到的数据有关。换句话说,缺失值的概率取决于可观测数据的特征。例如,如果你的暗恋对象拒绝了你,你可以通过观察其他变量,比如“她已经做出承诺了”,或者“她的生活目标与你不同”等,来知道原因。
随机缺失相对容易处理——只需将所有影响缺失概率的变量作为回归输入。不幸的是,我们通常不能确定数据是否真的是随机缺失的,或者缺失是否取决于未观察到的预测值或缺失的数据本身。
数据不是随机丢失 (MNAR)
当我们说数据不是随机丢失时,我们假设丢失的数据中有一种模式会影响您的主要因变量。例如,受教育程度最低的人错过了教育,病情最严重的人最有可能退出研究,或者吸毒者在调查中将药物使用字段留空。这也意味着这些丢失的值不是随机的,而是故意为空的。
如果数据不是随机丢失的,那么我们估算丢失的数据是没有意义的,因为它会使你的分析或模型的预测产生偏差。
诊断机制
- MAR vs. MNAR :区分 MNAR 和 MAR 的唯一真实方法是测量一些缺失的数据。我们可以比较受访者的答案和非受访者的答案。如果有很大的差异,这是数据是 MNAR 的好证据。另外,调查问题越敏感,人们回答的可能性越小。
- MCAR vs .马尔:一种技术是创建虚拟变量,判断某个变量是否缺失。然后,在该变量和数据集中的其他变量之间运行 t 检验和卡方检验,以查看该变量的缺失是否与其他变量的值相关。例如,如果女性真的比男性更不愿意告诉你她们的体重,卡方检验会告诉你女性的体重变量缺失数据的百分比高于男性。那么我们可以断定重量是有标记
数据插补方法
简单插补
用列中的平均值、中值或众数替换缺失值是一种非常基本的插补方法。这种方法速度最快,但对编码的分类要素效果不佳。此外,它没有考虑特征之间的相关性。如果我们必须使用这种简单的插补方法,考虑使用中间值而不是平均值,因为平均值会给分析带来异常值或噪声。
from sklearn.preprocessing import Imputerimputer = Imputer(missing_values='NaN', strategy='median')
transformed_values = imputer.fit_transform(data.values)# notice that imputation strategy can be changed to "mean", “most_frequent”, 'constant'
# read the documentation here: [https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html](https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html)
KNN 插补
KNNImputer 通过使用欧几里德距离矩阵查找 k 个最近邻来帮助估算观测值中存在的缺失值。你可以在这里查看 KNNImputer 是如何工作的。这种方法比简单的插补更准确;然而,它可能计算量很大,并且对异常值很敏感。
import numpy as np
from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=2) #define the k nearest neighbors
imputer.fit_transform(data)# read the documentation here: [https://scikit-learn.org/stable/modules/generated/sklearn.impute.KNNImputer.html](https://scikit-learn.org/stable/modules/generated/sklearn.impute.KNNImputer.html)
多元插补
多元插补通过考虑数据中的其他变量来解决噪音增加的问题。链式方程的基本多重插补(MICE)假设数据随机缺失。我们可以通过查看其他数据样本,对其真实价值做出有根据的猜测。
以下是三个主要步骤:
- 使用带有随机成分的插补流程为缺失值创建 m 组插补。
- 分析每个完整的数据集。每组参数估计值都会略有不同,因为数据略有不同。
- 将 m 个分析结果整合成最终结果。
如果你有兴趣了解它是如何工作的,请看这个视频这里。请注意,当我们对测量因缺失值导致的不确定性不感兴趣时,单变量与多变量插补在预测和分类中的有用性仍是一个未解决的问题。
图片作者 stefvanbuuren
import numpy as np
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
imp = IterativeImputer(max_iter=10, random_state=0)
imp.fit(X_train)
imp.transform(X_test)# read the documentation here: [https://scikit-learn.org/stable/modules/impute.html](https://scikit-learn.org/stable/modules/impute.html)
结论
任何分析都不能忽略缺失数据。作为数据科学家或数据分析师,我们不能简单地丢弃缺失的值。我们需要了解数据是如何丢失的,并相应地处理 NaN 值。
参考
- https://www.statisticssolutions.com/missing-values-in-data/
- https://measuringu.com/handle-missing-data/
- https://www.theanalysisfactor.com/missing-data-mechanism/
- https://www . analyticsvidhya . com/blog/2020/07/knnimputer-a-robust-way-to-imput-missing-values-using-scikit-learn/
- https://scikit-learn.org/stable/modules/impute.html
- https://www4 . stat . ncsu . edu/~ post/suchit/Bayesian-methods-completed . pdf
如果你觉得这很有帮助,请关注我,看看我在❤️的其他博客
下次见,快乐学习!👩🏻💻
举例说明最常见的离散概率分布
towardsdatascience.com](/understanding-and-choosing-the-right-probability-distributions-with-examples-5051b59b5211) [## 作为分析师如何准备商业案例面试?
作为数据分析师或数据科学家,我们不仅需要知道概率和统计,机器学习算法…
towardsdatascience.com](/how-to-prepare-for-business-case-interview-as-an-analyst-6e9d68ce2fd8) [## 为电子商务建立一个产品推荐系统:第一部分——网络搜集
今天,如果我们想到机器学习在商业中最成功和最广泛的应用,推荐者…
medium.com](https://medium.com/@kessiezhang/building-a-product-recommendation-system-for-e-commerce-part-i-web-scraping-798b6251ab51) [## 如何将 Jupyter 笔记本转换成 PDF
用几行代码将 Jupyter 笔记本转换为 pdf(调试“500:内部服务器错误”)
towardsdatascience.com](/how-to-convert-jupyter-notebooks-into-pdf-5accaef3758)
如何处理多类不平衡数据?-对 SMOTE 说不
不需要再打了。
机器学习中的一个常见问题是处理不平衡数据,其中目标类中存在高度不相称的数据。
你好,世界,这是我为数据科学社区写的第二篇博客。在这篇博客中,我们将看到如何处理多类不平衡数据问题。
什么是多类不平衡数据?
当分类问题的目标类(两个或两个以上)不是均匀分布时,那么我们称之为不平衡数据。如果我们不能处理这个问题,那么这个模型将会变成一场灾难,因为使用阶级不平衡数据的模型偏向于大多数阶级。
处理不平衡数据有不同的方法,最常用的方法是过采样和创建合成样本。
什么是 SMOTE?
SMOTE 是一种过采样技术,它从数据集生成合成样本,从而提高少数类的预测能力。尽管没有信息丢失,但它有一些限制。
合成样品
局限性:
- SMOTE 对于高维数据不是很好
- 可能会发生类的重叠,这会给数据带来更多的噪声。
因此,为了跳过这个问题,我们可以用’ class_weight '参数为类手动分配权重。
为什么使用类权重?
类权重通过给具有不同权重的类一个惩罚来直接修改损失函数。它意味着有目的地增加少数阶级的权力,减少多数阶级的权力。因此,它比 SMOTE 给出更好的结果。
概述:
我的目标是让这个博客非常简单。我们有一些最常用的技术来获得数据的权重,这些技术对我不平衡的学习问题有效。
- Sklearn utils。
- 计数到长度。
- 平滑重量。
- 样本权重策略。
1.Sklearn 实用程序:
我们可以使用 sklearn 计算类权重来获得类权重。通过在训练模型时将那些权重添加到少数类,可以在分类类时帮助性能。
from sklearn.utils import class_weightclass_weight = class_weight.compute_class_weight('balanced,
np.unique(target_Y),
target_Y)model = LogisticRegression(class_weight = class_weight)
model.fit(X,target_Y)# ['balanced', 'calculated balanced', 'normalized'] are hyperpaameters whic we can play with.
从逻辑回归到 Catboost,几乎所有的分类算法都有一个 class_weight 参数。但是 XGboost 有针对二元分类的 scale_pos_weight 和针对二元和多类问题的 sample_weights(参考 4)。
2.计数与长度之比:
非常简单直白!将每类的计数除以行数。然后
weights = df[target_Y].value_counts()/len(df)
model = LGBMClassifier(class_weight = weights)
model.fit(X,target_Y)
3.平滑权重技术:
这是选择权重的优选方法之一。
labels_dict 是包含每个类的计数的字典对象。
log 函数平滑不平衡类的权重。
def class_weight(labels_dict,mu=0.15):
total = np.sum(labels_dict.values())
keys = labels_dict.keys()
weight = dict()for i in keys:
score = np.log(mu*total/float(labels_dict[i]))
weight[i] = score if score > 1 else 1return weight# random labels_dict
labels_dict = df[target_Y].value_counts().to_dict()weights = class_weight(labels_dict)model = RandomForestClassifier(class_weight = weights)
model.fit(X,target_Y)
4.样品重量策略:
以下函数不同于 class_weight 参数,该参数用于获取 XGboost 算法的样本权重。它为每个训练样本返回不同的权重。
Sample_weight 是一个与数据长度相同的数组,包含应用于每个样本的模型损失的权重。
def BalancedSampleWeights(y_train,class_weight_coef):
classes = np.unique(y_train, axis = 0)
classes.sort()
class_samples = np.bincount(y_train)
total_samples = class_samples.sum()
n_classes = len(class_samples)
weights = total_samples / (n_classes * class_samples * 1.0)
class_weight_dict = {key : value for (key, value) in zip(classes, weights)}
class_weight_dict[classes[1]] = class_weight_dict[classes[1]] *
class_weight_coef
sample_weights = [class_weight_dict[i] for i in y_train]
return sample_weights#Usage
weight=BalancedSampleWeights(target_Y,class_weight_coef)
model = XGBClassifier(sample_weight = weight)
model.fit(X, target_Y)
类 _ 权重 vs 样本 _ 权重:
sample_weights
用于给出每个训练样本的权重。这意味着您应该传递一个一维数组,其中的元素数量与您的训练样本完全相同。
class_weights
用于为每个目标类赋予权重。这意味着你应该为你要分类的每个类传递一个权重。
结论:
以上是为你的分类器寻找类权重和样本权重的几种方法。我提到了几乎所有对我的项目有效的技术。
我请求读者尝试一下这些可以帮助你的技术,如果不是把它当作学习的话😄下次可能会对你有帮助😜
通过 LinkedIn 联系我😍
不平衡分类问题中 SMOTE 数据的处理
知道陷阱在哪里以及如何避免它们
照片由盖蒂图片社提供
分类问题在数据科学领域非常普遍。无论是欺诈检测、情绪分析还是疾病测试,能够预测特定数据点属于哪个组都是非常强大的。
通常,重点是检测少数群体中的数据点,这可能会出现一些常见问题。通常在这种情况下,您收集的数据是不平衡的,这意味着您感兴趣的目标比其他组的数据量小得多。数据中的这种不平衡会导致你的模型偏向于选择多数群体。在处理不平衡数据集时,有三种常用的技术来平衡数据:
- 欠采样多数类
- 对少数民族阶层进行过度采样
- 多数类欠采样和少数类过采样的组合
这篇博文将介绍一种叫做 SMOTE 方法的过采样技术。
SMOTE(合成少数过采样技术)是一种用于校正组中不平衡的过采样过程。这种技术通过复制现有的少数民族实例并对其进行小的修改来创建少数民族的新数据实例。这使得 SMOTE 非常擅长放大已经存在于少数群体中的信号,但不会为这些群体创造新的信号。
我们来看看一些还没有用 SMOTE 平衡的分类数据。我们将使用 sci-kit 学习库中的乳腺癌数据集。让我们导入必要的包,导入我们的数据,并创建一个可以评估我们的模型的函数。
import pandas as pd
from sklearn import datasets
from sklearn.model_selection import cross_val_score
from sklearn.metrics import confusion_matrix def evaluate_model(X_train, y_train, model): model.fit(X_train, y_train)
preds = model.predict(X_test)
scores = cross_val_score(model, X_train, y_train, cv=3, scoring="accuracy")
diff = scores.mean() - model.score(X_test, y_test)
SD = diff / scores.std()
print(f"Training Score:{model.score(X_train, y_train)}")
print(f"Cross V Score: {scores.mean()} +/- {scores.std()}")
print(f"Testing Score: {model.score(X_test, y_test)}")
print(f"Cross & Test Diff: {diff}")
print(f"Standard Deviations Away: {SD}")
print(confusion_matrix(y_test, preds))cancer = datasets.load_breast_cancer()
X = cancer.data
y = cancer.target
从这里开始,我们将对我们的数据执行训练测试分割,并初始化我们的基本模型。
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegressionX_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)clf = LogisticRegression(random_state=0, solver='newton-cg', max_iter=1000)
提醒:在训练-测试分割函数中设置随机状态非常重要,这样可以确保模型性能的任何变化都是由于您所做的更改,而不是由于随机种子。分层参数根据输入参数分割数据,在本例中是 y 。这意味着每组的训练集和测试集将具有相同的样本百分比。
现在让我们看看我们的基本模型表现如何。
evaluate_model(X_train, y_train, clf)
基本模型结果
总的来说,我们看到我们的基本模型在建模数据方面做得不错,但是让我们看看是否可以使用 SMOTE 来提高性能。
现在,当处理合成数据时,第一条规则是:
不要把合成数据放在你的测试数据里!
我们想在实时数据上实现我们的模型,所以我们想看看我们的模型在真实数据上的表现,而不是我们创建的合成数据。这意味着我们只能将合成数据添加到训练集中。我们可以用下面的代码做到这一点:
from imblearn.over_sampling import SMOTE
smt = SMOTE(random_state=0)
X_train_SMOTE, y_train_SMOTE = smt.fit_sample(X_train, y_train)
从这里,我们可以使用包含 SMOTE 的训练数据来训练我们的模型。
evaluate_model(X_train_SMOTE, y_train_SMOTE, clf)
使用 SMOTE 数据的模型结果
正如我们所看到的,我们的模型能够更准确地预测包含 SMOTE 数据的测试数据。然而,引起关注的一个问题是我们的交叉验证分数。交叉验证分数用于评估有限数据集上的模型,以预测模型在真实世界数据中的表现。理想情况下,我们希望交叉验证分数与测试分数相同或接近。在这种情况下,我们的分数出现了分歧,因为我们违反了处理合成数据的第二条规则,即:
不要把合成数据放在你的验证数据里!
就像我们的测试数据一样,我们希望只使用真实数据来验证我们的模型。这意味着我们只希望我们的 SMOTE 数据在训练折叠中,而不是在验证折叠中。在 sci-kit learn 文档中可以找到如何使用 StratifiedKFold 函数将合成数据添加到每个单独折叠的示例。
幸运的是,有一个不平衡学习模块可以为我们处理所有的数据,即管道模块。只需将 SMOTE 流程和您的模型包含到管道中,模块就会处理剩下的工作。对于此任务,您可以使用 Pipeline 或 make_pipeline 函数。
from imblearn.pipeline import make_pipeline
pipeline = make_pipeline(smt, clf)evaluate_model(X_train, y_train, pipeline)
使用 imblearn 管道模拟性能
正如我们可以看到的,我们的交叉验证分数现在更准确地反映了我们可以从现实世界中的模型中预期的实际性能。希望这篇博客能帮助你在现实世界中实现你的模型。
如何使用模糊查询处理弹性搜索中的错别字
实践教程
使用 Elasticsearch 轻松处理错别字,改善用户体验
由 Ksenia Makagonova 在 Unsplash 上拍摄的照片
错别字是经常发生的事情,会降低用户的体验,幸运的是,Elasticsearch 可以通过模糊查询轻松处理它。
如果你正在用 Elasticsearch 构建一个高级的自动完成系统,处理输入错误是必须的。
如果你想创建一个简单的,你可以阅读我的其他文章“用 Elasticsearch 创建一个简单的自动完成功能”。
什么是模糊逻辑
模糊逻辑是一种数学逻辑,其中变量的真值可以是 0 到 1 之间的任何数字。这与只有真值 0 或 1 的布尔逻辑不同。
在弹性搜索中,模糊查询意味着查询中的术语不必与倒排索引中的术语完全匹配。
为了计算查询之间的距离,Elasticsearch 使用 Levenshtein 距离算法。
如何使用 Levenshtein 距离算法计算距离
用 Levenshtein 距离算法计算距离很容易。
你只需要把第一个和第二个单词一个字符一个字符的比较。
如果字符不同,那么你可以将单词之间的距离加一。
我们来看一个例子,如何计算常见错别字"Gppgle"
与正确字"Google"
的距离。
弹性搜索模糊查询:Levenshtein 距离
在我们用 Levenshtein 距离算法计算出"Gppgle"
和"Google"
之间的距离后,我们可以看到距离为 2。
弹性搜索中的模糊查询
使用模糊查询处理 Elasticsearch 中的输入错误也很简单。
让我们以错别字"Gppgle"
为例。
当我们使用普通匹配查询时,Elasticsearch 将在搜索到 Elasticsearch 之前首先分析查询"gppgle"
。
倒排索引中唯一的术语是“google”
,它与术语"gppgle"
不匹配。因此,Elasticsearch 不会返回任何结果。
现在,让我们在匹配查询中尝试 Elasticsearch 的 fuzzy。
如你所见,使用 fuzzy,Elasticsearch 返回了一个响应。
我们以前学过"gppgle"
和"google"
的距离是 2。
在查询中,我们插入了"fuzziness":"AUTO"
而不是一个数字。为什么会起作用?
如果我们在"fuzziness"
字段中使用"AUTO"
值,Elasticsearch 将确定什么样的模糊距离是合适的。
对于 6 个字符,Elasticsearch 默认情况下将允许 2 个编辑距离。
模糊性更好,但是如果你愿意,你可以用一个精确的数字来调整它。
现在,让我们用一个确切的数字来证明"gppgle"
和"google"
的距离为 2。
当我们使用"fuzziness":"1"
时,Elasticsearch 没有返回任何结果。
不过,使用"fuzziness":"2"
,Elasticsearch 返回了文档"google"
。
这证明了我们之前用 Levenshtein 距离算法对"gppgle"
和"google"
的距离计算,结果是 2。
弹性搜索中的两种模糊查询
在前面的例子中,我们使用模糊查询作为匹配查询中的参数。
但是还有另一种方法来使用模糊特性,即模糊查询。
好像是一样的!那么,它们有什么区别呢?
模糊查询
模糊查询的工作方式类似于术语查询,对 Elasticsearch 的查询不经过分析,也不用于搜索倒排索引。
例如,让我们再索引一个文档"Hong Kong"
。
让我们看看分析器用 Elasticsearch 的 Analyze API 产生了哪些术语。
如您所见,standard_analyzer
产生了两个术语,"hong"
和"kong"
。
如果你读了我的另一篇文章“elastic search:Text vs . Keyword”,你就会知道如果我们使用一个术语查询来搜索"Hong Kong"
,那么我们不会得到任何结果。
这是因为在 Elasticsearch 中没有与"Hong Kong"
的编辑距离小于 2 的术语。
现在,让我们用"Hpng"
试试模糊查询。
查询中的术语"Hpng"
和弹性搜索中的术语"hong"
的距离为 2。
请记住,被查询的术语和倒排索引中的术语是区分大小写的,距离“2”来自于"Hp"
和"ho"
之间的差值。
用模糊性参数匹配查询
带模糊参数的匹配查询比模糊查询更好。查询中的分析器将在将查询搜索到倒排索引之前对其进行分析。
让我们尝试与模糊查询部分相同的查询。
不出所料,两个查询都返回了结果!
第一个查询,"Hpng Kong"
被解析为"hpng"
和"kong"
。术语"hpng"
和"kong"
都存在于倒排索引中。
"hpng"
和"hong"
匹配距离为 1。而"kong"
和"kong"
完美匹配。
如果您计划使用匹配查询,需要注意的一点是查询中的每个术语都允许模糊性。
我们可以尝试使用"fuzziness":2
用"hggg kggg"
查询,它与"Hong Kong"
的编辑距离为 4。
如您所见,Elasticsearch 返回了一个结果。
这是因为分析器将查询"hggg kggg"
分析为术语"hggg"
和"kggg"
。
"hggg"
和"kggg"
在弹性搜索中对"hong"
和"kong"
的编辑距离分别为 2。
弹性搜索中模糊查询的调整
您可以调整模糊查询来匹配您的用例。
在这一节中,我将介绍我们可以在查询中更改的参数。
模糊
模糊性是模糊查询的核心。
我们传递给这个参数的值是允许的最大距离。
我们可以传递两种类型的值,一个是精确最大距离的整数,另一个是"AUTO"
。
"AUTO"
值允许查询中的模糊性是动态的。
我们可以在"AUTO"
值中调 2 个参数,写成"AUTO:[low],[high]"
。如果术语长度低于下限值,查询会将模糊度设置为 0。如果术语长度介于低值和高值之间,查询会将模糊度设置为 1。最后,如果术语长度大于上限值,查询会将模糊度设置为 2。
如果未确定高低值,Elasticsearch 将使用 3 和 6 作为默认值。
让我们以一个文档“Elasticsearch 中的模糊查询允许您处理错别字”为例。
我们可以尝试一些查询来证明我们之前描述的 AUTO 机制。
“tp”
: 1 编辑距离“to”
的距离。“Fyzzy”
: 1 编辑距离“Fuzzy”
的距离。“Fyzyy”
: 2 编辑距离“Fuzzy”
的距离。“Elastissearcc”
: 2 编辑距离“Fuzzy”
的距离。“Elestissearcc”
: 3 编辑距离“Fuzzy”
的距离。
查询之后,这些查询产生了一个结果:
“Fyzzy”
“Elastissearcc”
这些查询不会:
“tp”
“Fyzyy”
“Elestissearcc”
换位
transpositions
将允许您的查询将两个相邻字符(ab - > ba)的换位计算为 1 个距离。
例如,如果我们将transpositions
设置为 true,那么用"leasticsearcc"
查询就会得到一个结果。
但是如果我们将其设置为 false,那么弹性搜索将不会有任何结果。
弹性搜索默认transpositions
设置为真。
我们无法将此设置设置为匹配查询。匹配查询总是将transpositions
计算为 1 距离。
最大扩展
将决定您从查询中获得的最大结果。
如果您将max_expansions
设置为 1,并且在 Elasticsearch 中有 2 个文档适合您的查询,那么 Elasticsearch 将只返回 1。
注意max_expansions
适用于碎片级。因此,如果在 Elasticsearch 中有许多碎片,即使将max_expansion
设置为 1,查询也可能返回更多结果。
max_expansions
的默认值为 50。
前缀长度
prefix_length
是模糊查询中不考虑的前缀字符数。
例如,如果我们将prefix_length
设置为 1,那么查询"llasticsearch"
将不会得到任何结果。
prefix_length 设置默认为 0。
重写
如果您想改变结果的得分,可以改变rewrite
参数。
你可以在弹性搜索文档中找到关于rewrite
参数的更多信息。
结论
处理 Elasticsearch 中的输入错误非常容易,可以改善用户体验。
处理输入错误的最简单方法是在匹配查询中添加"fuzziness":"AUTO"
。
如果您想调优查询,可以更改一些参数,其中"fuzziness"
是最重要的。
谢谢你一直读到最后!
如何在金融领域利用数据科学的力量
简要介绍金融机构可以有效利用数据科学和机器学习技术的某些使用案例
金融世界从来都是关于数据的。人们甚至可以说,金融专业人士甚至在数据科学、机器学习和人工智能出现之前就在日常运营中利用数据了。最重要的证据是 1958 年 FICO 分数的发展。
计算处理能力的进步、获取大数据的便利性以及复杂算法模型的发展,只是推动了金融专业人士对 ML 和 AI 的快速吸收。难怪美国最大的银行和世界第七大银行摩根大通&公司每年在新技术上投资 110 亿美元。
让我们看看数据科学帮助金融专业人士和金融机构变得更加有效和高效的具体使用案例。
欺诈检测和防范
确保客户数据安全并最大限度地减少欺诈性交易对于金融机构的持续运营至关重要,通常由监管机构强制执行和规定。ML 算法可以从历史数据中学习,并识别不寻常的行为、模式或交易。这些算法包括:
洗钱可以帮助金融机构识别:
- 基于真实索赔中发现的历史模式的虚假保险索赔
- 可疑的高价值或高交易量
- 身份盗窃
- 洗钱
- 用相似的 KYC 数据开立的多个账户
风险评估和预测分析
金融机构面临各种风险,可能来自竞争对手、债权人、债务人、监管机构,也可能来自各种市场(资本、商品、外汇等。).可以实施不同的 ML 技术来分析风险驱动因素,并对未来做出预测和/或开发风险模型。
例如:
- 给定特定借款人的历史付款行为和其他特征(年龄、收入、家庭规模、地址等),该借款人对其未来债务违约的可能性有多大。)?
- 在客户或投资组合层面估计和预测违约损失(LGD)
- 分析和预测市场前景
- 投资银行可以开发各种风险模型和场景,以提供可操作的、数据驱动的见解
客户数据管理和分析
金融机构被海量数据(包括结构化和非结构化数据)淹没,后者在管理、处理和洞察方面更具挑战性。
ML 和 AI 工具,如自然语言处理、数据挖掘和文本分析,可以将这种过去繁琐的数据管理练习转变为一个独特的机会,以了解更多有关客户的信息,并确定可操作的见解,从而推动新的收入机会。
聚类和分割算法可用于将相似的客户分割在一起。客户细分将允许有针对性的营销活动,并为具有高流失风险的客户提供额外支持。
客户数据也可用于执行客户终身价值分析(CLV) 。应识别高 CLV 客户,并对其进行适当管理,以从该关系中获得最大的金钱利益和增长。
个性化服务
与前一点有些关系的是,ML 还可以用来为客户提供个性化和定制化的服务,从而确保长期互利的关系。
数据分析还支持创建个性化营销,在正确的时间和正确的设备上为正确的潜在客户提供正确的产品。数据挖掘广泛用于目标选择,以识别新产品的潜在客户。行为、人口统计和历史购买数据用于建立模型,该模型预测客户/潜在客户对促销或报价的响应概率。
推荐引擎(无论是协同、基于内容还是混合)可以分析和过滤用户的活动,向他推荐最相关和最准确的产品或服务。
客户支持
人工智能支持的虚拟助理使金融机构更容易实现渠道无关的一致客户服务体验,使客户能够向虚拟助理请求日常信息、方向或按需援助。这些虚拟助手(也称为聊天机器人)也节省了员工的时间。
算法交易
尽管算法交易有时会遭到反对,但大型金融机构和经纪商正在大规模开展这种交易。这些算法以预编程的方式发出市场订单,同时自动考虑数量、价格和时间变量;并利用计算机的计算处理速度。执行速度被认为对普通交易者不公平,因为他们的交易可能落后于算法交易,使他们处于不利地位。
通过时间序列分析进行预测
时间序列预测不同于常规的最大似然预测,因为它在历史观测值之间增加了一个显式的顺序相关性:一个时间维度。使用历史趋势、季节性和数据中的任何噪声,时间序列预测试图预测在给定的未来时间点的变量值,无论是否有任何其他因变量。
递归神经网络(RNN) ,或者更具体地说,长短期记忆(LSTM)网络通常用于时间序列预测。谈到金融领域,金融专业人士通常利用时间序列预测来预测未来的销售量、股票价格、产品需求等。
结论
金融专业人士对数据科学的使用不仅限于欺诈、风险管理和客户分析。金融机构也可以利用机器学习算法来自动化业务流程并提高安全性。
如果您想讨论任何与数据分析、机器学习、金融或信用分析相关的问题,请随时联系 me 。
下次见,继续!
如何在软件工程中有一个坚实的开端
我的第一个软件开发项目 A-Z 编程体验!
虽然我现在是一名研究人员,但每当我用我的软件工程知识开发我的算法时,我发现自己成为了一名更好的研究人员/科学家/无论什么。在这篇文章中,我将分享我的第一次软件开发/编程经历。这是我们在本科大学(斯里兰卡莫拉图瓦大学)计算机科学与工程系第一学期必须完成的项目。
用我的电子表格程序随机绘制
鉴于我对 JAVA(我在其中做了这个项目)的了解很少,这确实是一个非常具有挑战性的练习。编程语言的选择是自由的,然而,JAVA 是我的首选,因为它比 C/C++更容易。此外,NetBeans 是一个易于使用的 GUI 开发工具。我相信这些天真的选择可能帮助我不费吹灰之力就掌握了编程。我必须感谢Surangika Ranathunga(唯一课程召集人/讲师)博士(夫人)在短短 4 个月(1 个学期)内为许多新生注入如此大量的知识。这很困难,但结果是惊人的。这篇文章中任何有帮助的内容都必须反映出她教导和指导新手的能力。让我们检查一下这个项目!
概述
目标是开发一个具有基本数据类型、单元格引用和将单元格内容标记为数据类型的能力的电子表格程序。完整的实现必须遵循适用的 OOP 概念(继承、抽象、封装和多态)。
第一个任务-字符串标记器
学习编程语言的最好方法之一是在实践中使用语法。此外,作为一名程序员,你必须知道如何使用正则表达式和算法(尽管这是大学里完全不同的课程),你必须做一个好项目。我相信实现一个简单的记号化器和一个算法来简化数学字符串可能是一种立刻学习它们的方法。
- 标记器应识别数据类型;整数、浮点数、字符串、日期/时间、货币。
- 如果字符串是 excel
=500*10/5
中的数学表达式,则值必须计算为1000
。
可以使用字符串中的前缀=
在上述情况之间切换。我在案例 1 中使用的正则表达式如下。
booltype = ".*?(((=?[<>])|(!=)|([<>]=?)|<>|><)|==|=).*?";
currency = "[A-Za-z$]{1,2}[ .]?[0-9][0-9]*[.]?[0-9]*";time12hr = "(1[012]|[1-9]):[0-5][0-9]?[:]?[0-5][0-9]?(am|AM|pm|PM)"; time24hr = "(2[0-4]|1[0-9]|[0-9]):[0-5][0-9]?[:]?[0-5][0-9]?"; integer = "[-]?[0-9]*";
floating = "[-]?[0-9]*[.][0-9]*";dateformatSL = "[0-9]{2,4}[/-](1[012]|0?[0-9])[/-](1[0-9]|0?[0-9]|2[0-9]|3[01])";dateformatINTL = "(1[0-9]|0?[0-9]|2[0-9]|3[01])[/-](1[012]|0?[0-9])[/-][0-9]{2,4}";
我这里有我天真的实现。然而,简单地说,可以用一个静态类来保存函数,这些函数可以解析字符串并返回解析的部分(类型、格式化/评估的内容、原始内容)。请注意,解析后,我们必须保留类似于 excel 的原始内容。
对于情况 2,必须实现算法;调车场这只是将左括号推入堆栈,并在遇到右括号时通过回溯来解决。如果你有一个类似于12*(5+6)
的等式,你可以推栈直到你找到第二个右括号。然后弹出,直到第一个左括号出来,然后简化5+6
并再次推入堆栈。最后,堆栈将没有括号,您可以使用 BODMAS 来简化最终的堆栈。你可以在这里看看我的实现。
现在这两个类都完成了。第一个类将解析条目,如果输入字符串是一个表达式,第二个类将由第一个使用。
计算表达式的单元格
第二个任务-单元类
作为一名学徒,我的单元实现并不完美或合适。然而,理想的方法是做适当的泛型的实现。如果你是新手(像我一样),你可以在单独的类中使用数据类型的字符串。以下是我现在组织课程的方式:
Cell<E> <- used to render cells, a generic class
AbstractDataType <- store shared data (user input string, etc)
DataType extends AbstractDataType <- store data (an example)
FloatType extends AbstractDataType <- floating point data storage
这里 E 可以是解析器找到的单元的数据类型(解析器可以返回泛型中正确数据类型的类)。我们使用继承来共享任何单元格都应该具有的公共属性(用户输入字符串、单元格颜色,如果有的话,以及稍后将讨论的更多内容)。AbstractDataType 类演示了抽象**。你永远不会创建 AbstractDataType 的类,因为它毫无意义。**
在我们的操作中,我们将使用AbstractDatatype dataT = new DataType()
,也就是多态性**。当单元格引用开始起作用时,这将使我们能够增加和减少单元格。单元格中的所有字段都被封装,并且只使用 getters 和 setters 进行变异。**
现在我们已经涵盖了所有主要的 OOP 概念以及如何实现一个算法!
对于任何一个刚接触编程的学生来说,这都不是一个简单的任务,更不用说 JAVA 了。
第三项任务-用户界面
这是一件很难用文字来解释的事情。因此,我将分享我的实现的外观和感觉。但是,NetBeans 是一个简单的工具,可以实现正确的 GUI。我相信在实践中已经不再使用它了,因为我们已经有了类似于 Electron/Qt 的框架。
JAVA 有内置的 GUI 组件,一旦你阅读了文档,它们就非常简单。阅读文档是一项重要的技能,我相信我是从同一门课程中学到的。
电子表格程序的关键 UI 组件
- 工作表视图(单元格板)
- 用于保存、复制、粘贴等的菜单
- 单元格编辑器(您可以在其中看到原始公式或单元格文本)
- 活动单元格指示器(显示您点击的单元格,如 A1)
下面是我的 GUI 实现。请注意,我使用了一个主题(显然是唯一一个在非 windows 平台上能够正确呈现的好主题)。
电子表格程序
单元格引用
引用单元格以红色突出显示
这是我从 MS Excel 程序中抓取的一个特性。相当整洁的功能!
JAVA 有许多库,这些库激励我们在这个特定的项目上更进一步。我加了几张这样的截图,激励我亲爱的读者和未来的工程师们!
绘图(J-free-chart 库)
JFreeChart 库提供了大量的绘图功能。我用了一些来使程序看起来优雅一些。
Y=X 绘图的绘图工具
使用 OpenCSV 保存(序列化)
导出电子表格数据的最常见方式之一是使用 CSV 格式。在这个程序中,我使用 OpenCSV 库来处理 CSV 文件解析。
文件打开
实现特性和有用的数据结构/设计模式
单元格引用
这可以通过多种方式实现。
- 观察者设计模式 —这里的观察者是引用其他单元格的单元格。我们将这样的细胞添加到被观察细胞内的观察细胞阵列中。更改作为更新被推送。请注意,JAVA 有一个可观察的接口,这使得实现非常流畅。
- 中介模式 —在这个实现中,我们有一个单元协调器,负责变更和更新。HashMap 对象可以用来存储可能的引用和参考。
特别注意——寻找循环依赖是很重要的。否则,由于永无止境的引用循环,程序可能会遇到堆栈溢出。
撤消/重做
虽然我没有在我的程序中实现这一点,但这可以通过使用 纪念品设计模式 来实现。这可以实现为链接的对象引用,也可以实现为一堆动作。
对当前时代的最后思考
这个项目是 2014 年 6 年前进行的!。既然时代已经让我们从桌面图形用户界面转移,一个基于网络的项目会更有意义。让我分享几个项目,它们可能有助于一个初露头角的软件工程师建立编程信心。
- 图书馆管理程序
- 办公室使用的投票程序(用于决策)
- 一个基于网络的婴儿监视器(适用于那些喜欢处理图像等的人)
- 一些商品(汽车、房屋等)的买卖程序
希望你喜欢读这篇文章。我展示这个项目的唯一想法是激励年轻人完成这个项目。试一试,并与我分享你的项目。干杯!
试一试吧!
git clone [https://github.com/anuradhawick/SpreadSheet.git](https://github.com/anuradhawick/SpreadSheet.git)
cd SpreadSheet/dist/
java -jar SpreadSheet.jar
😃
在简单的小表格中突出数据
驯服 Matplotlib 表的更多方法
如何突出显示单元格(图片由作者提供)
当显示表格数据时,我们通常希望关注某个特定的单元格。这种关注改善了我们希望从表中获得的视觉支持,并使观众不会被包含在整个值集中的数据的广度所淹没。尽管如此,我们还是希望在整个集合的上下文中呈现关键信息。有了表格,我们可以通过使单元格在大小、粗细、颜色、形状、间距或边框上与其他单元格不同来突出显示所需的单元格。
本文对我之前的文章“使用 Matplotlib 的简单小表格”进行了扩展,提供了一组我们可以用来突出 Matplotlib 表格中的单元格的技术。这些技术包括改变单元格的边框宽度、背景颜色、字体粗细和字体颜色的方法。我们还将看到如何淡化未突出显示的单元格。在这个过程中,我们将发现一些相关的样式技术,比如改变表格网格线的颜色和使用开源调色板。我将注释转换的每一步,以提供对pyplot.table
行为的洞察,我们可能会重用这些行为来完成其他任务,或者让您扩展我正在分享的发现。我会在文章的最后呈现完整的源代码,所以你不需要一行一行的拼凑。
起点
起点是来自“使用 Matplotlib 的简单小表”文章的最终代码。这些技术也应该适用于从pyplot.table
派生的任何可能需要调整的表。
更改调色板
我们要做的第一件事是从继承自pyplot.table
例子的色图中改变调色板。我使用了一个令人愉快的调色板,由 colourlovers.com 的 TaraLynn1221 命名为“Outcomes”。使用来自艺术社区的开源调色板是我们设计困难的程序员可以将至少在某些情况下匹配的颜色放在一起的一种方式。
# colors from "Outcomes" palette by TaraLynn1221
# https://www.colourlovers.com/palette/4751687/Outcomes
cl_outcomes = {
'white':'#FFFFFF',
'gray': '#AAA9AD',
'black':'#313639',
'purple':'#AD688E',
'orange':'#D18F77',
'yellow':'#E8E190',
'ltgreen':'#CCD9C7',
'dkgreen':'#96ABA0',
}
...
# Get some lists of color specs for row and column headers
rcolors = np.full(len(row_headers), cl_outcomes['ltgreen'])
ccolors = np.full(len(column_headers), cl_outcomes['ltgreen'])
我还为我们将要创建的高亮单元格和绘图中的其他组件创建了一些颜色变量。
grid_color = cl_outcomes['dkgreen']
fig_background_color = cl_outcomes['white']
fig_border = cl_outcomes['dkgreen']
label_text_color = cl_outcomes['black']
highlight_text_color = cl_outcomes['yellow']
faded_text_color = cl_outcomes['gray']
highlight_color = cl_outcomes['purple']
highlight_border = cl_outcomes['dkgreen']
title_text_color = cl_outcomes['black']
在此期间,我为文本元素更新并添加了一些变量。在本例中,我们将向图中添加文本注释和副标题。
title_text = 'Loss by Disaster'
subtitle_text = '(In millions of dollars)'
annotation_text = 'The ten-year loss due to floods is $78.0M.'
footer_text = 'July 28, 2020'
更改调色板(图片由作者提供)
突出显示单元格
突出显示是通过设置单元格的填充和边缘(边框)颜色实现的。如果需要,可以对几个单元格重复此过程。
表格对象由单元格对象组成。使用从表格左上角开始的(0,0)
索引来引用单元格。列标题在这个矩阵中,所以(0,0)指的是第一个列标题。行标题确实是这个矩阵的一部分,但是被索引为列-1
。
下面的代码将突出显示第二行第三列中的单元格。记住,我们必须考虑第 0 行是列标题行。行标题的列索引为-1
。最上面一行的标题是(1,-1)
。
为了突出显示,我们从表中检索单元格。然后,我们设置表面颜色,边缘颜色和线宽。为了控制字体样式,我们从单元格中获取文本对象。可以控制的文本属性是有限制的。例如,设置单个单元格的字体大小没有任何效果。数据网格中的所有单元格需要具有相同的字体大小,这是在表格级别控制的。
一旦我们完成了所有想要的高亮样式的改变,我们就调用ax.add_patch()
来传递对单元格的引用。您可能认为简单地更改属性就足以设置样式,但这似乎并没有按 z 顺序重新定位单元格,相邻的单元格样式显示在突出显示的单元格的顶部。将单元格作为补丁添加到 Axes 对象可以解决这个问题。如果你找到了更优雅的方式,请在评论中告诉我们。
# Highlight the cell to draw attention to it
the_cell = the_table[2,2]
the_cell.set_facecolor(highlight_color)
the_cell.set_edgecolor(highlight_border)
the_cell.set_linewidth(2)
the_text = the_cell.get_text()
#the_text.set_weight('bold')
the_text.set_fontstyle('italic')
the_text.set_color(highlight_text_color)
ax.add_patch(the_cell)
突出显示单元格(作者图片)
Cell 对象是 Matplotib 矩形的子类。矩形是面片的子类。这种继承意味着您可以引用 Rectangle 和 Patches 的属性和功能,从而对格式进行更多的控制。
淡化未突出显示的单元格
为了将更多的注意力吸引到突出显示的单元格,我们可以淡化它们。我们将使用类似于高亮显示的技术将它们设置为较浅的颜色。我们可以调用get_children()
来获取单元格列表并遍历它们。表格只包含单元格,因此不需要对元素进行类型检查。对于每个单元格,我们得到它的文本对象。从过程中排除标题就像检查标题标签列表中的单元格文本一样简单。当然,如果您的单元格的值与标签相匹配,您就需要想出另一种方法。这种循环技术也是我们设置表格边框颜色的方式,所以我们在这里添加cell.set_edgecolor(grid_color)
。Table 对象上没有设置该颜色的属性,所以我们用循环的方式来设置。
# Fade the cells
for cell in the_table.get_children():
cell_text = cell.get_text().get_text()
cell.set_edgecolor(grid_color)
if cell_text not in row_headers\
and cell_text not in column_headers:
cell.get_text().set_color(faded_text_color)
else:
cell.get_text().set_weight('bold')
cell.get_text().set_color(label_text_color)
我们可以添加代码来排除突出显示的单元格。不过,更简单的方法是在突出显示之前全部淡入淡出。因此,让我们在流程的前面插入衰落代码例程。
get_children()
的替代物是get_celld()
。当get_children()
返回一个艺术家对象的列表,而这些对象恰好只是这里的单元格时,get_celld()
将返回一个单元格字典,这些单元格的关键字是行和列元组。
print(the_table.get_children())
[<matplotlib.table.CustomCell object at 0x7fb7b430f150>, <matplotlib.table.CustomCell object at 0x7fb7b6bf2890>, <matplotlib.table.CustomCell object at 0x7fb7b6bf26d0>,...
print(the_table.get_celld())
{(1, 0): <matplotlib.table.CustomCell object at 0x7fb7b4313390>, (1, 1): <matplotlib.table.CustomCell object at 0x7fb7b4313e50>, (1, 2): <matplotlib.table.CustomCell object at 0x7fb7b4313150>,...
淡化未突出显示的单元格(图片由作者提供)
提示: get_celld()
可用于生成单元格文本的索引表,用于故障排除或按索引手动引用单元格。
for key, val in the_table.get_celld().items():
# call get_text() on Cell and again on returned Text
print(f'{key}\t{val.get_text().get_text()}')
(1, 0) 66.4
(1, 1) 174.3
(1, 2) 75.1
...
添加注释和副标题
如果我们要在演示或报告中使用我们的表格图像,我们可能希望向它添加文本注释,以帮助读者理解我们为什么要调出单元格值。副标题也能帮助读者理解图表。在我们的例子中,我们没有让读者知道表中的度量单位是什么,这样信息就可以成为一个好的副标题。
有几种方法可以在 Matplotlib 中创建注释。我们在表格周围有大量的空白,所以让我们在图表下面使用一行简单的图形文本。我们也会包括一些造型。
# Add annotation
plt.figtext(0.5, 0.2,
annotation_text,
horizontalalignment='center',
size=9, weight='light',
color=title_text_color
)
Matplotlib 没有给我们一个一流的字幕函数,所以我们也将使用图形文本。不幸的是,这意味着如果我们以后更改标题或整体图形结构,我们可能需要调整它的位置。我们可以使用 heroics 来计算字幕相对于图片和标题的位置,但是我们将保持简单,并根据实验对字幕位置进行硬编码。
# Add subtitle
plt.figtext(0.5, 0.9,
subtitle_text,
horizontalalignment='center',
size=9, style='italic',
color=title_text_color
)
**注意:**记住suptitle()
是在图上设置标题的功能,而不是 sub 标题。不幸的命名。
添加注释和副标题(图片由作者提供)
最终来源
这是最终的源代码。我还在标题和页脚中添加了一些明确的样式。我有一个设计师朋友,他教我平面设计中最好的黑色不是纯黑,所以我们用#313639
代替#000000
。
这是最终产品,你可以随心所欲地裁剪。
import numpy as np
import matplotlib.pyplot as plt
# colors from "Outcomes" palette by TaraLynn1221
# https://www.colourlovers.com/palette/4751687/Outcomes
cl_outcomes = {
'white':'#FFFFFF',
'gray': '#AAA9AD',
'black':'#313639',
'purple':'#AD688E',
'orange':'#D18F77',
'yellow':'#E8E190',
'ltgreen':'#CCD9C7',
'dkgreen':'#96ABA0',
}
title_text = 'Loss by Disaster'
subtitle_text = '(In millions of dollars)'
annotation_text = 'The ten-year loss due to floods is $78.0M.'
footer_text = 'July 28, 2020'
grid_color = cl_outcomes['dkgreen']
fig_background_color = cl_outcomes['white']
fig_border = cl_outcomes['dkgreen']
label_text_color = cl_outcomes['black']
highlight_text_color = cl_outcomes['yellow']
faded_text_color = cl_outcomes['gray']
highlight_color = cl_outcomes['purple']
highlight_border = cl_outcomes['dkgreen']
title_text_color = cl_outcomes['black']
data = [
[ 'Freeze', 'Wind', 'Flood', 'Quake', 'Hail'],
[ '5 year', 66386, 174296, 75131, 577908, 32015],
['10 year', 58230, 381139, 78045, 99308, 160454],
['20 year', 89135, 80552, 152558, 497981, 603535],
['30 year', 78415, 81858, 150656, 193263, 69638],
['40 year', 139361, 331509, 343164, 781380, 52269],
]
# Pop the headers from the data array
column_headers = data.pop(0)
row_headers = [x.pop(0) for x in data]
# Table data needs to be non-numeric text. Format the data
# while I'm at it.
cell_text = []
for row in data:
cell_text.append([f'{x/1000:1.1f}' for x in row])
# Get some lists of color specs for row and column headers
rcolors = np.full(len(row_headers), cl_outcomes['ltgreen'])
ccolors = np.full(len(column_headers), cl_outcomes['ltgreen'])
# Create the figure. Setting a small pad on tight_layout
# seems to better regulate white space. Sometimes experimenting
# with an explicit figsize here can produce better outcome.
plt.figure(linewidth=1,
edgecolor=fig_border,
facecolor=fig_background_color,
tight_layout={'pad':1},
#figsize=(5,3)
)
# Add a table at the bottom of the axes
the_table = plt.table(cellText=cell_text,
rowLabels=row_headers,
rowColours=rcolors,
rowLoc='right',
colColours=ccolors,
colLabels=column_headers,
loc='center')
# Scaling is the only influence we have over top and bottom cell padding.
# Make the rows taller (i.e., make cell y scale larger).
the_table.scale(1, 1.5)
# Hide axes
ax = plt.gca()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# Hide axes border
plt.box(on=None)
# Add title
plt.suptitle(title_text,
weight='bold',
size=14,
color=title_text_color)
# Add subtitle
plt.figtext(0.5, 0.9,
subtitle_text,
horizontalalignment='center',
size=9, style='italic',
color=title_text_color
)
# Add footer
plt.figtext(0.95, 0.05, footer_text,
horizontalalignment='right',
size=6,
weight='light',
color=title_text_color
)
# Add annotation
plt.figtext(0.5, 0.2,
annotation_text,
horizontalalignment='center',
size=9, weight='light',
color=title_text_color
)
# Fade the cells
for cell in the_table.get_children():
cell_text = cell.get_text().get_text()
cell.set_edgecolor(grid_color)
if cell_text not in row_headers\
and cell_text not in column_headers:
cell.get_text().set_color(faded_text_color)
else:
cell.get_text().set_weight('bold')
cell.get_text().set_color(label_text_color)
# Highlight the cell to draw attention to it
the_cell = the_table[2,2]
the_cell.set_facecolor(highlight_color)
the_cell.set_edgecolor(highlight_border)
the_cell.set_linewidth(2)
the_text = the_cell.get_text()
#the_text.set_weight('bold')
the_text.set_fontstyle('italic')
the_text.set_color(highlight_text_color)
ax.add_patch(the_cell)
# Force the figure to update, so backends center objects correctly within the figure.
# Without plt.draw() here, the title will center on the axes and not the figure.
plt.draw()
# Create image. plt.savefig ignores figure edge and face colors, so map them.
fig = plt.gcf()
plt.savefig('pyplot-table-highlight.png',
bbox='tight',
edgecolor=fig.get_edgecolor(),
facecolor=fig.get_facecolor(),
dpi=300
)
结论
我们已经有了第一个小表格,并在单元格中添加了一些突出显示,使它对我们的观众来说更加明显。我们学习了如何从开放的设计网站上获取调色板。我们看到了基于大小、颜色、相对褪色和边框的高亮技术。我们学习了添加注释和副标题的简单方法。Matplotlib 表格是一个灵活而强大的工具,用于显示表格汇总数据。
如何雇佣一名数据科学家
图片来自 Pixabay
今天我写的是我如何通过将数据科学应用到招聘过程中,为我的公司招聘了一名数据科学家。我第一次雇用数据科学家,让我大开眼界,在花了几年时间作为候选人参加面试后,我坐在了桌子的另一边。
我想深入探讨三个要点。
- 定义数据科学角色和职责。确切了解数据科学家将从事的工作。
- 利用自动化测试和评分标准大规模评估候选人,而不是没完没了地查看简历和打招聘经理电话。
- 为漏斗的所有部分创建基于指标的招聘流程。
首先,我们为什么需要数据科学家?
具有讽刺意味的是,一个数据科学家创立的数据科学创业公司需要另一个数据科学家。数据科学家有助于企业通过分析数据来影响产品方向,或者通过大规模实施机器学习来增加像参与度、保留率和收入这样的指标,从而增加收入。
这通常是在大型平台、市场、电子商务上完成的——基本上所有的事情面试查询都不是。作为一个小企业,我们当前开发新功能的首要任务是与我们的客户交谈,因为他们通常对我们应该构建什么有强烈的意见。
我们了不起的首席技术官。
但作为一个数据科学教育企业,似乎有必要将其他人的整个工作(除了我的工作)集中在应用分析和发现有趣的产品见解和功能上。除了提供面向数据科学的教育内容,我还希望将数据科学实际应用到业务中,以提高我们用户的学习目标。
定义数据科学角色
如果你曾经与数据科学经理或招聘人员聊天,你可能听说过招聘过程有多痛苦。他们浏览了成千上万份简历,他们面试的所有候选人都被拒绝了,有人被录用了,但在第一个月内就辞职了——随你挑。
老实说,根据我的经验,这个问题通常可以归结为**职位描述和面试过程中的期望值不一致。**你不能采访一个数据科学家,滔滔不绝地谈论产品见解,然后在 Leetcode 上钻牛角尖。
在为我们的空缺职位撰写职位描述时,我确保列出了他们将参与的几个项目- 改进我们的时事通讯,创建 AB 测试系统等。我非常清楚地说明了为什么我们需要一名数据科学家,以及这个职位需要什么。
这个过程的第二部分包括创建你自己的招聘策略。以下是我多年来学到的一些技巧。
在漏斗的每一步,淘汰 50%的候选人。例如,如果你要招聘一个职位,并想提供两个机会,你可以根据简历或课后练习安排四次现场面试、八次技术筛选和十六次招聘经理面试。这就像一个二叉查找树,目标是优化你的面试过程,在最短的时间内找到最好的候选人。
了解候选人中的技能分布。一旦你为这份工作设定了要求,包括薪水、工作时间、工作风格和技能期望,你很可能会收到一大堆各种各样的候选人。要了解一个好的候选人是什么样子,你也要看看一个坏的候选人是什么样子。
换句话说,在一个被录用的候选人身上定义你的基本要求。对于面试查询,我们需要一名精通产品分析并能独立工作的数据科学实习生。作为雇主,我们的优势在于我们是一家初创公司,我可以直接指导数据科学家,但老实说,我们不确定这对应用程序有多大吸引力。
令人惊讶的是,一周后,我们有超过 500 名候选人申请!太疯狂了。
然后,我们遇到了当今招聘的经典问题——衡量和筛选所有候选人,而不是花数百个小时面试每个人。
我们如何准确地、不带偏见地、大规模地评估候选人?
我们接下来做的是…分配带回家的挑战。
大规模评估候选人
是的。我知道你在想什么。杰伊,你已经写了你如何 讨厌 带回家的挑战。我的天啊。你做了什么?
我承认:我的态度总是倾向于讨厌带回家的挑战,因为我是站在候选人一边面试的。老实说,虽然承认这一点让我很痛苦,但带回家的挑战对雇主来说是很大的,因为它们允许雇主大规模地评估候选人。你可以在同一时间内真实地回顾 50 个带回家的挑战,而不是进行五个单独的技术筛选。
此外,我有动力去寻找被低估的候选人。我认为,在雇佣个人贡献者时,最容易出现误判的情况是雇主过于看重简历和以往的经验,而不是实际技能。当用作过滤和分配机制,同时最小化转化率损失时,带回家的挑战是最好的。例如:
带回家挑战有效性图表。
图表上的 x 轴代表以小时为单位的带回家挑战的长度,垂直轴代表如果带回家的复杂性增加,我们理论上可以获得的数据科学技能的信号。我假设虽然信号可能随着带回家的长度而增加,但在某一点上,它在有效性上处于平稳状态。很多时候,数据科学家也会在带回家的挑战上花费过多的时间,这可能会混淆候选人的比较。
第二行是候选人的转换率,这些候选人会接受的挑战。正如所料,随着挑战时间的增加,完成带回家挑战的候选人数量会减少。
我们的目标是找到这两条线之间的点,最大限度地提高挑战在评估技能方面的有效性,同时保留最有潜力的合格候选人。
鉴于我之前在带回家挑战上的负面经历。我决定,这个最大化的价值应该是一个可以持续一个小时的带回家的东西,并且对于一个合格的候选人来说足够简单。
我们的目标是我们雇佣的候选人对主动性和勇气有所了解。
我在 Typeform 上主持了“带回家”项目,这样我就可以在 Indeed 上把链接发给不同的候选人,并在“带回家”项目中创造了三个不同的问题。在一天结束时,我们在做了 200 多份简历审查后,向 100 名候选人发送了带回家的简历,并收到了 70 份作业,带回家的完成率约为 70%。
来自带回家挑战的整体大图。
建造带回家的房子
你大概可以猜到,70 个带回家的作业仍然是很多考生要复习的。我们的问题是在评估技能时继续筛选候选人。
我们分两部分来处理这个问题,并提出了三个问题,每个问题都有不同的目的。
第一个问题是关于基础分析的。
带回家挑战的第一个问题。
对于任何曾经远程使用过分析的人来说,我认为这个问题是免费的。然而,只有 58%的候选人答对了这个问题。
带回家挑战第一题的结果。
对于那些答错这个问题的人来说,他们剩下的带回家的挑战就被丢弃了。这里的一个错误答案表明,候选人要么不够善于观察,不关心带回家的东西,要么就是不擅长分析。这里需要一种过滤机制来减少候选字段。
带回家挑战的第二个问题。
第二个问题基于 SQL。这个问题旨在测试候选人是否能够使用连接编写一个相对简单的查询。如果他们不能写出正确的 SQL,那么他们就不能从我们的数据库中提取数据。这个问题也相对容易得分。我在采访查询中已经有了示例表。我只需在我们的编辑器中运行他们的解决方案,如果返回正确的结果,那么他们就通过了这一轮 SQL。
唯一的问题是有不同的 SQL 引擎,这意味着许多人答对了问题,但遗漏了一些语法。如果答案大部分都在那里,我就给他们及格,所以大约一半的候选人答对了这部分问题。
带回家挑战的第三个问题。
最后,最后也是最重要的问题是产品分析案例问题。
这个问题让我能够在几个关键方面对候选人进行评估。
- 他们能提出对案例研究有意义的指标和分析吗?
- **他们了解内容业务框架内的分析吗?**这个问题很棒,因为它涉及到一个大家都知道的产品——Youtube——的案例研究,并且是关于一个与采访查询几乎相似的情况。不,我们没有创作者,但我们有很多内容,我想知道候选人会如何看待企业内部的内容。
- 最后,我想了解他们的技术概念沟通水平。沟通和结构都是数据科学家需要了解的最重要的技能。如果我不能和你交流,那我就不能和你一起工作。
这里有一个好答案的例子。候选人描述了他们想要使用的指标,概述并阐明了谁是业余和超级明星创作者,并了解如何建立两个时间表来比较这些指标。
让我们首先指定一个 6 个月到一年的时间段来分析和移除所有那些在该时间段内不活动的通道。然后,让我们将订户数量超过 100,000 的所有频道指定为超级明星 youtubers,其余频道指定为业余爱好者。
指标 1:业余 YouTube 用户在时间段内的平均增加量/时间段开始前的用户数/超级明星 YouTube 用户的平均增加量(时间段内的用户增加量/时间段开始前的用户数)。
第一度量应该优选地高于 1,因为较小的频道比较大的频道更容易增长,但是小于 1 的值表示只有超级明星频道在增长。
指标 2:(比率(建议标签页中的业余频道视频/业余频道视频总数)/比率(建议标签页中的巨星频道视频/巨星频道视频总数))。
这个指标应该更接近于 1,因为这表明 youtube 同等地推荐这两种类型的频道。
指标 3:(比率(通过 Youtube 搜索获得的业余频道观看次数/业余频道观看总次数)/比率(通过 Youtube 搜索获得的超级明星频道视频/超级明星频道观看总次数))。
这个指标也应该接近 1。它指示是否可以通过 youtube 搜索访问较小的频道。
这里有一个不好的答案。候选人基本上什么也没说。什么是趋势视频?什么是类别?我不会带着任何洞察力离开。
首先,我将采用“趋势视频”、“浏览量”和“类别”等指标。通过分析,找出每个类别中业余爱好者和超级明星的数量。如果在一段时间内进行相同的分析,我们就可以确定趋势。
正如你在上面看到的,候选人是否通过产品面试问题的一个主要因素是基于他们的条目的长度。这就是我们想要的!我们需要更多的想法——尽管是好的想法——最终需要有人能够思考这个问题,并找到用数据解决问题的方法。(有关如何获得数据科学案例研究的更多信息,请点击此处查看我们的文章!)
有了这个收获,我们将候选人名单从最初的 100 名候选人缩小到 10 名,在每个后续的面试问题中排除 50%的候选人。我们没有给 100 个不同的候选人打电话,也没有根据经验给前 10 名打电话,而是不与任何人交谈就找到了最合格的候选人。
最终现场数据科学访谈
招聘过程的最后一步是面试每个候选人。对我来说,这可能是最令人惊讶的一步,因为虽然我认为我已经找到了真正合格的候选人,但他们中的许多人并没有那么优秀。(对于数据科学新人,* 下面是 你需要什么才能在数据科学实习面试中取得成功。)*
一些人没有安排面试,因为他们要么找到了另一份实习工作,要么不再感兴趣了。在面对面的面试中,我会根据沟通技巧、对工作的兴趣和案例研究对每位候选人进行评分。此外,我还试图判断候选人本人是否符合从他们带回家的材料中收集的技能评估。
我所问的案例研究是关于改进面试查询每周发送的电子邮件简讯。这与其说是一个真正的面试问题,不如说是数据科学家应该参与的第一个项目。他们在这个面试问题上表现得越好,工作效率就越高。
当我和我最终面试的八个左右的候选人交谈时,他们中的大约一半人都不是很强。他们中的一些人不知道面试查询实际上是做什么的,或者甚至没有注册使用这个网站。其中一个人甚至告诉我,他爸爸帮他做了 SQL 部分。其他弱的候选人只是没有很强的沟通技巧,虽然他们可以在写作部分将想法串在一起,但我意识到面对面的沟通可能更难,因为它需要你在讨论中当场思考。
不过,最终我面试了一位我非常喜欢的候选人,一周后,我给了他机会,他接受了。
注意事项和提示
以下是这一过程的要点。
在招聘时,确保你的时间得到有效利用。
招聘人员和招聘经理把时间浪费在给候选人发电子邮件、安排面试和安排带回家的任务上。重要的是要有一个精简的招聘流程,你可以在未来为每个候选人复制。从现在开始,无论我们何时雇佣任何人,我都将使用这一流程,因为我觉得我最大限度地有效利用了我的时间,并且仍然收到了优秀的候选人。
定义角色并预先设定期望。
发挥你作为雇主的优势。我在面试中告诉每个候选人,与大公司相比,我们不能支付那么多,但他们会得到直接的指导,他们的贡献实际上会影响面试提问。作为一家初创公司,我们的弱点最终也成为了我们的优势,我们得到了一位出色的实习生。
你知道有多少无用的噪音。一开始,我在职位描述的底部添加了一段简单的文字,写道:如果你看到这段文字,请在你的简历旁边的文本框中写下“我阅读了职位描述”。只有五个人最终把它写了进去。许多候选人最终并不在乎他们申请的每一份工作。如果你付出一点点努力,你一定能脱颖而出。
对于雇主来说,如果你有兴趣了解更多关于有效雇用数据科学家的信息,请联系我们,了解更多关于面试查询如何提供帮助的信息。
感谢阅读!
- 如需更多独家面试解说,请查看 面试查询 !
- 查看我的 Youtube 频道 获取更多面试指南,以及解决问题的技巧&。
- 在面试查询博客上找到更多面试指南,如 罗宾汉数据科学家面试 和字节跳动数据科学家面试**。****
原载于 2020 年 11 月 16 日 https://blog.interviewquery.com。**
如何雇佣令人惊叹的数据科学家
数据科学的业务
如何雇佣和留住优秀的数据科学家
在桌子的两边,面试数百名候选人以及被面试后,我得出了我喜欢和不喜欢这个过程的原因。
第一步:知道你需要什么
很多时候,我遇到过不确定自己需要什么的企业或公司。他们想利用数据做些事情,但不清楚他们需要谁或需要什么。这是首先要解决的问题。
就数据而言,清楚地了解自己的成熟度。如果你的公司仍然在使用 excel 电子表格,也许是一个小型数据库,你可能不需要一个具有多年后端经验的深度学习工程师。你可能会从初级数据分析师那里获得很多价值。
知道你需要什么是最重要的,这不仅是为了招聘好员工,也是为了确保你雇佣的人留在你的公司并获得宝贵的经验。招聘是一个耗时且昂贵的过程——所以你想把它做好。
如果你不确定你需要什么,有很多方法可以解决这个问题。你可以得到一个外部评估。做市场调研。采访数据科学家只是为了获取信息——他们可以把你引向正确的方向。
照片由克里斯蒂娜@ wocintechchat.com在 Unsplash 上拍摄
第二步:正确处理流程
这可能有点争议,但我不认为用不相关的脑筋急转弯来测试数据科学家是找到合格候选人的最佳方式。在一个完美的世界中,这个过程应该是这样的:
- 初始屏幕
你想得到这个人的照片,看看他们是否合适。询问他们的背景,兴趣,特长。这些符合贵公司目前的需求吗?
在技术筛选之前,如果你打算问算法问题,或者做一个现场编码评估,**让它相关,并在之前提供“研究领域”。**如果你真的觉得移位和这个角色相关[ 95%的可能性不是],提前让他们知道你的测试包括移位。
向贵公司的技术屏幕发送电子邮件介绍示例。
嗨[候选人]!
我们很高兴在[日期]与您会面并了解您的更多背景。
我们希望您能与[您的面试官]一起完成一次技术面试。
在这次技术面试中,你将被要求对[x]个问题进行编码。我们花时间创造了模拟你日常工作的现实问题,而不是问你一些毫无意义的脑筋急转弯。我们认为重要的是我们的工程师能够批判性地思考,并在我们实际解决的问题上展示他们的技能。
问题可能包括以下特定主题【帮助缓解压力,给你一个候选人的关注点】:
[一些例子]
-如何使用ε贪婪方法训练强化学习算法
-使用您最喜欢的深度学习库创建一个简单的多层感知器
-在你最喜欢的深度学习库中编写自定义损失函数
我们也可能会问一些关于以下库的问题:numpy(数组和造型)、pandas(数据帧、系列)、PyTorch (…)等
期待与你交谈,
令人敬畏和体贴的公司
2.技术屏幕
第二次面试,你深入了解他们最喜欢的算法和工作经历,而不是你的。
他们理解数学吗?他们能描述算法是如何解决问题的吗?他们能从头到尾完成一个项目吗?他们应该有几个例子。
如果您计划进行现场编码评估,请按照上面给出的介绍来做。不要指望一个高级工程师会钻研他们 10 年前学过的每一门算法。给出具体和相关的重点领域,跳过脑筋急转弯。
3.作业
这就是这个过程与今天的标准不同的地方。我非常喜欢这一点,因为它提供了一个展示多种不同技能的候选人。作业应该是开放式的,包括建模部分。这项作业还会向你展示候选人的工作风格和演讲风格。他们检查数据吗?最终的演示或输出是否经过润色?清楚了吗?
这比现场编码评估要好得多,原因如下:
- 白板编码问题(或类似 coderpad 的东西)可能会很紧张。虽然工作中会有压力,但我认为这种形式可能会阻碍找到有才华的工程师
- 在准备这些面试的过程中,我发现自己更多地关注无关的算法理论(已解决的问题),并试图研究不同的脑筋急转弯,而不是让我擅长我所做的事情的实质——主动机器学习研究和实现
为了确保候选人确实做了工作,最后阶段的一次面试应该是工作产品的演示,候选人在演示中回顾他们所做的工作。
4.超级日
超级日是对团队的检查——确保你的高级工程师和管理团队都有机会见到候选人,并对他们感到舒适。这对其他工程师来说是一个“彻底检查”候选人的机会,确保他们能够处理智力辩论,并展示他们的能力。
同样,您希望让候选人实际回顾他们在现场环境中执行的项目。这是为了认可他们为你的公司付出的努力,并了解他们是如何思考问题的。
他们应该能够自如地回答关于他们所选择的方法的问题。
我不喜欢在超级日进行编码评估。尽早完成这一部分。超级日是你的工程师/团队了解这个人的时候,并询问相关的问题。
尽早进行技术筛选。在玩具问题上的糟糕表现可能会分散应聘者的注意力,从而在不相关的面试中造成糟糕的印象。
我敢保证,你的候选人仍在反思,当他们应该批判性地思考你的公司、你的团队、提问、谈论他们的背景等问题时,他们在寻找最接近的回文惊喜问题方面做得不够好。
就是这样。你应该知道这个人是否适合你的公司。到了这一天,你应该很有信心这个人会非常适合这家公司。
希望这能帮助你创建一个伟大的数据科学团队。
感谢阅读!
如果您喜欢这篇文章,您可能也会喜欢:
分解创建您的组织的步骤 AI CoE
medium.com](https://medium.com/swlh/the-3-steps-to-create-a-world-class-artificial-intelligence-center-of-excellence-4faaa6a87dd6)
如何托管自己的 Python 模型
如何设置本地私有服务器并在其上部署端点。
在使用机器学习进行部署的主题下,有许多事情需要考虑,许多不同的选项将为您提供不同的结果。首先,有很多标准的 VPS 和半共享主机可以用来部署你的模型。对于初学者来说,这些通常不是很好的选择,但是在使用什么样的应用程序以及如何安排文件系统方面允许更多的自由。当然,另一个选择是像 AWS 或 Google Cloud 这样的部署解决方案。虽然这两个都是很好的选择,但是它们都不能给你性价比和自己托管服务器的便利性。虽然自己托管服务器当然有缺点,但如果你碰巧有良好可靠的互联网和一台额外的计算机,这肯定是一个很好的选择。
设置
当你运行自己的服务器时,需要考虑的一件非常重要的事情是它实际上要在什么上面运行。您可能不会像许多计算狂人那样在自己的壁橱里放着一台成熟的服务器,但这没关系。对于大多数应用程序,您不太可能需要 128GB 的内存和高得离谱的内核数处理器。例如,如果您希望只部署几个端点,也许是提供一些静态文件,那么您可以选择任何内存超过 1GB 的计算机。
也就是说,你要考虑的另一件事是热量。你住的地方有多热,你有中央空调吗?保持服务器组件冷却很重要,服务器处理器会产生大量热量,需要比普通计算机更多的环境冷却。因此,您甚至可以拥有一台服务器,但由于环境温度过高而不想使用它。
你可能需要考虑的另一件事是功耗。毕竟,如果您没有使用服务器的所有功能,而是运行一个高 TDP 处理器,自己托管它甚至可能不具成本效益——您可能最终要支付比您预想的更多的电费。
当你不需要那么多能量的时候,我有一个很好的建议,那就是使用笔记本电脑。许多人在某个地方都有一台大约 4GB 内存的旧 I-7 或 I-5 笔记本电脑,对于一台可以执行大量操作的简单服务器来说,这是一个非常好的选择,而且非常便宜。与台式机处理器相比,笔记本电脑处理器的 TDP 要低得多,因此它们产生的热量和消耗的电能也少得多。
域、名称服务器和端口转发
为了向万维网提供任何类型的文件,你需要做的第一件事是设置端口转发。端口转发允许您到 internet 服务提供商和网络的本地连接不仅从网络传入,而且传出到网络。网页和网站总是配置为在端口 80 上运行。例如,有时端口 80 充当端口 8000 的套接字端口,这正是您的模型可能使用端口的方式。
默认网关是所有其它设备都将使用的默认设备 IP,以便通过它到达您的 ISP。换句话说,网络的默认网关是路由器的本地 IP 地址。在 Linux 上,您可以使用
**route -n**
在 Windows 上,您首先需要以管理员身份运行命令提示符。接下来,您只需输入
**ipconfig**
进入命令提示符,返回,然后在提供的值列表中搜索默认网关。获取网络的默认网关,并将其粘贴到网络浏览器中。这将把您带到路由器的登录页面,您现在当然需要登录。
登录后,您的路由器设置几乎肯定会发生变化,因此很难解释每台路由器上的端口转发位置。通常,它要么在它自己的选项卡中,要么在“高级”选项卡下。
我不太清楚为什么,但出于某种原因,您的网络可能会请求一个应用程序名称来转发您的端口。这可以是任何东西,应用程序叫什么并不重要。我想这唯一的目的是为了组织。您需要转发端口 60–82 和端口 8000–8030。至于 TCP 与 UDP 的问题,TCP 速度较慢,但占用的带宽要少得多,而 UDP 速度很快,但如果使用不当,会导致不稳定的连接。明确地说,UDP 通常用于需要高 ping 连接的东西,如视频游戏和类似的东西。所以对于托管网站来说,使用 TCP 可能是个好主意。不过,我通常只转发 TCP 和 UDP,因为该协议在这方面并不真正有效。协议是由应用程序决定的,而不是由路由器决定的,所以在这里选择 TCP 或 UDP 只会限制您使用其中一个的能力。
接下来,你当然需要一个域名。这是一个不言自明的过程—
购买域名。
或者,您也可以始终使用服务器的公共 IP 地址作为您的域。接下来你需要做的是把你的域名服务器从你的路由器上移除。这将让域注册表知道将传入的连接发送到哪里。你需要把它放入你选择的域名注册网站的域名服务器中。
设置端点
在开始实际创建和部署端点之前,测试您的服务器以查看它是否真正工作是很重要的。在这篇文章中,我将使用 Ubuntu,因为它绝对统治着服务器市场,而且与 RHEL 或 Arch 服务器相比,它对初学者来说是友好的。将我们的新服务器连接到 wifi 后,我们将需要使用 dig 或 curl 来获取我们的公共地址。dig 的问题在于它通常依赖于域名服务器,这些服务器可能会根据你的硬件地址而不是 IP 地址来识别你,所以我通常会这样做:
curl ifconfig.co
现在我们有了服务器的 IP 地址,将其复制到另一台计算机上。这是一个公共 IP 地址,所以它不能通过本地连接工作。换句话说,我们没有向本地服务器发出请求,所以我们不会得到本地服务器,所以计算机是否在同一个网络上并不重要,如果端口没有正确转发,这将不起作用。现在回到服务器上运行
python -im http.server
这将启动一个开发服务器,它将静态地提供存储在您机器上的文件。现在继续前进,导航到您的另一台计算机上的公共 IP 地址,如果您最终在您的服务器上的~/中,那么恭喜您!
为了设置你的服务器的虚拟部分,你首先需要知道你要做什么。两个最大和最常用的选项是 NGINX 和 Apache。我不久前发表了一篇文章,对这两者进行了比较,如果你想单独了解它们以做出决定的话:
你应该使用哪个网络服务器?
medium.com](https://medium.com/chifi-media/nginx-or-apache-a3bb7ec4ca68)
您还需要使用 Supervisor 并设置一个来运行您的服务器。我不打算在这里包括配置,因为这篇文章更多的是基于网络的,但这里有一些文章将带您了解如何使用 NGINX 和 Supervisor 部署 Gunicorn3 (Python 生产服务器)和 Genie (Julia 生产服务器):
应用程序部署通常会带来意想不到的后果和错误。部署可以是制定或…
towardsdatascience.com](/deploying-flask-with-gunicorn-3-9eaacd0f6eea) [## 带精灵的 A-Z Julia 端点
介绍如何使用 Genie web-framework 的虚拟环境设置。
towardsdatascience.com](/a-z-julia-endpoint-with-genie-a2e0c2f1c884)
如果您想提供静态文件,我也可以满足您的要求:
对于那些使用端点和可执行服务器的人来说,有时可能会注意到一个特定的任务不需要…
medium.com](https://medium.com/@emmettgb/how-to-serve-static-files-with-an-ubuntu-vps-81e8f3a57cc7)
结论
在这个项目中,我要做的最后一步是在两台机器上安装 Openssh
(my daily machine runs Fedora)
sudo dnf install openssh-client(The server runs Ubuntu)
sudo apt-get install openssh-server
这将允许您在服务器没有连接到任何外围设备的情况下连接到服务器。这意味着你将能够登录到它,而不需要实际使用计算机本身,这是非常方便的!另一件很酷的事情是,您还可以使用 SSH 从世界任何地方登录到您的公共 IPV4 地址,只要 SSH 端口(端口 22)也被转发。
我要说的是,根据你的情况,以及你到底想用你的服务器做什么,在你的路由器上运行你自己的服务器可能是一个奇妙的和非常划算的方法。运行您自己的服务器允许您管理自己的硬件,而不是租用它。使用低 TDP 处理器确实可以为您节省一些钱,因为您可能每个月都要花费几分钱来维持网站和终端的运行。需要更多储物空间?买一个更大的硬盘。需要更多内存?多买内存。这很简单,省去了一个通常不受欢迎的中间人,他在幕后操纵你的网站,给你自由和灵活性,让你可以把你的网站带到任何地方!
如何用 Python 识别日本烛台图案
克里斯·利维拉尼在 Unsplash 上的照片
日本烛台是最重要的工具之一,用于自由交易或量化交易。它们是被称为价格行动的特殊交易风格的第一个例子。
让我们看看它们是什么,以及如何在 Python 中使用它们。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
日本的烛台有哪些?
日本烛台是一种特殊的图表类型。对于每个时间段,它们显示最高价、最低价、开盘价和收盘价。
让我们看一个示例图表:
日本烛台图表示例。图片作者。
每一天都用一个叫做蜡烛的符号来代表。每根蜡烛由一个实体、一个上影和一个下影制成。
作者图片
蜡烛有一种颜色。如果收盘价高于开盘价,它们通常是白色、绿色或蓝色的(看涨蜡烛线)。如果收盘价低于开盘价,它们就是黑色或红色的(看跌蜡烛线)。
它们是如何使用的?
这种图表非常有用,因为它在一个简单的符号中给了我们很多信息,但最重要的用途与模式有关。模式是蜡烛线的组合,显示一个特殊的图形形状,它们对发现价格反转很有用。让我们看看其中的一些。
在 Python 中识别模式
下面是最常见模式的列表,Python 代码可以让我们识别它们。
你可以在我的 GitHub 储存库中找到完整的代码:https://GitHub . com/gianlucamalato/machine learning/blob/master/candlesticks . ipynb
首先要安装 yfinance 库,下载市场数据。
!pip install yfinance
然后我们可以导入熊猫和金融。
import pandas as pd
import yfinance
对于这个例子,我们将使用过去 5 个月的标准普尔 500 每日数据。
ticker = yfinance.Ticker("SPY")
df = ticker.history(period = '5mo')
现在,我们将创建与模式一样多的列,每一列都有一个布尔值,如果模式出现则为真,否则为假。
所以,我们必须在历史数据中扫描。我们将使用 for 循环。我们计算真实的身体宽度和烛光范围。
for i in range(2,df.shape[0]):
current = df.iloc[i,:]
prev = df.iloc[i-1,:]
prev_2 = df.iloc[i-2,:] realbody = abs(current['Open'] - current['Close'])
candle_range = current['High'] - current['Low'] idx = df.index[i]
现在让我们看看一些模式及其代码,它们必须包含在循环的中。
看涨摇摆
看涨摆动是一个简单的 3 蜡烛线模式。第二根蜡烛线在三根蜡烛线中最低。蜡烛的颜色无关紧要。这是一个信号,表明价格可能上涨。
作者图片
所以,代码很简单:
df.loc[idx,'Bullish swing'] = current['Low'] > prev['Low'] and prev['Low'] < prev_2['Low']
看跌摇摆
看跌的波动与看涨的波动相反。它由三根蜡烛组成,第二根蜡烛最高。蜡烛的颜色无关紧要。
作者图片
这是代码:
df.loc[idx,'Bearish swing'] = current['High'] < prev['High'] and prev['High'] > prev_2['High']
多头针棒
针条是非常频繁和强大的模式。众所周知,针棒有很长的影子和很小的实体。非常重要的一点是,针棒不仅仅是蜡烛,它还必须从周围的价格活动中突出出来。所以,相对于前一根蜡烛线,一根看涨的针棒线必须有一个更低的低点。
我们可以定义一个“小”的真实物体为宽度小于烛光范围除以 3 的真实物体。一根看涨的针棒将会把真实的主体放在蜡烛的上半部分。蜡烛的颜色无关紧要。
作者图片
下面是多头针棒的代码:
df.loc[idx,'Bullish pinbar'] = realbody <= candle_range/3 and min(current['Open'], current['Close']) > (current['High'] + current['Low'])/2 and current['Low'] < prev['Low']
轴承销杆
看跌的针柱就像看涨的针柱一样,但是真正的主体现在位于蜡烛线的下半部分,并且比之前的蜡烛线高。
作者图片
代码如下:
df.loc[idx,'Bearish pinbar'] = realbody <= candle_range/3 and max(current['Open'] , current['Close']) < (current['High'] + current['Low'])/2 and current['High'] > prev['High']
内部酒吧
酒吧内部是由两根蜡烛组成的图案。第二根蜡烛完全包含在第一根蜡烛的范围内。颜色无关紧要。
这种模式显示了波动性的收缩,这可能是一个强大的方向性爆炸的前奏。
作者图片
代码如下:
df.loc[idx,'Inside bar'] = current['High'] < prev['High'] and current['Low'] > prev['Low']
外部酒吧
外侧杠与内侧杠相反。蜡烛系列完全包括之前的蜡烛。
作者图片
代码如下:
df.loc[idx,'Outside bar'] = current['High'] > prev['High'] and current['Low'] < prev['Low']
看涨吞没
多头吞没是一种强势的多头形态。这是一个外面的酒吧,有一个巨大的、乐观的真实身体。我们可以把“巨大”定义为一个真实的物体,它的宽度占蜡烛线的 80%以上。
作者图片
代码如下:
df.loc[idx,'Bullish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] > current['Open']
熊市吞没
看跌吞没是看涨吞没的反义词。一根巨大的熊蜡烛完全吞没了前一根蜡烛。
作者图片
代码如下:
df.loc[idx,'Bearish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] < current['Open']
完整的代码
下面是完整的代码。请记住,我们必须用错误来填补空白。
for i in range(2,df.shape[0]):
current = df.iloc[i,:]
prev = df.iloc[i-1,:]
prev_2 = df.iloc[i-2,:]realbody = abs(current['Open'] - current['Close'])
candle_range = current['High'] - current['Low']idx = df.index[i]
# Bullish swing
df.loc[idx,'Bullish swing'] = current['Low'] > prev['Low'] and prev['Low'] < prev_2['Low']# Bearish swing
df.loc[idx,'Bearish swing'] = current['High'] < prev['High'] and prev['High'] > prev_2['High']# Bullish pinbar
df.loc[idx,'Bullish pinbar'] = realbody <= candle_range/3 and min(current['Open'], current['Close']) > (current['High'] + current['Low'])/2 and current['Low'] < prev['Low']# Bearish pinbar
df.loc[idx,'Bearish pinbar'] = realbody <= candle_range/3 and max(current['Open'] , current['Close']) < (current['High'] + current['Low'])/2 and current['High'] > prev['High']
# Inside bar
df.loc[idx,'Inside bar'] = current['High'] < prev['High'] and current['Low'] > prev['Low']
# Outside bar
df.loc[idx,'Outside bar'] = current['High'] > prev['High'] and current['Low'] < prev['Low']
# Bullish engulfing
df.loc[idx,'Bullish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] > current['Open']# Bearish engulfing
df.loc[idx,'Bearish engulfing'] = current['High'] > prev['High'] and current['Low'] < prev['Low'] and realbody >= 0.8 * candle_range and current['Close'] < current['Open']df.fillna(False, inplace=True)
我们的数据框最终将是这样的:
根据列的值过滤行将使我们回测任何使用这种模式的交易策略。
结论
日本烛台模式对于发现趋势反转非常有用。本文中没有描述许多不同的模式,但是在这里您可以找到最重要的模式。这种模式的 Python 实现对任何想开始算法交易冒险的人都非常有用。
如何在人群中识别潜在客户?
数据科学
邮购销售公司的真实数据科学任务
介绍
在这个项目中,德国的一家邮购销售公司对确定普通人群的细分市场感兴趣,并以此作为其营销增长的目标。人口统计信息(由 Arvato Finacial Solutions 通过 Udacity )已提供给普通大众以及邮购公司的老客户以建立公司客户群模型。目标数据集包含邮寄营销活动目标的人口统计信息。
目标是确定哪些人最有可能响应营销活动,成为邮购公司的客户。
数据描述
的。由于与 Arvato 签订了保密协议,因此没有提供该项目的 csv 文件。以下是所使用的文件:
- uda city _ AZDIAS _ 052018 . CSV:德国一般人口的人口统计数据;891 211 人(行)x 366 个特征(列)
- uda city _ CUSTOMERS _ 052018 . CSV:邮购公司客户的人口统计数据;191 652 人(行)x 369 个特征(列)。
- uda city _ MAILOUT _ 052018 _ train . CSV:作为营销活动目标的个人的人口统计数据;42 982 人(行)x 367 人(列)。
- uda city _ MAILOUT _ 052018 _ test . CSV:作为营销活动目标的个人的人口统计数据;42 833 人(行)x 366 人(列)。
- DIAS Attributes—Values 2017 . xlsx:文件中按字母顺序描述的列的详细信息。要了解更多功能,请点击此处。
数据预处理
- **记忆力减退。CSV(**uda city _ AZDIAS _ 052018)保存普通人群人口统计数据的文件大小为 2.5 GB,因此我编写了一个简单的函数来更改数据类型(int64 到 int16),并减少了 78%的内存使用。要了解更多关于功能和内存缩减的信息,请点击此处。
- 数据理解:所有的数据文件都有相同的特征,所以我决定用uda city _ AZDIAS _ 052018 . CSV文件去理解人口统计数据。我使用了DIAS Attributes—Values 2017 . xlsx文件来理解每个值对列的意义。请参见下图中的示例:
这里,属性 AGER_TYP 描述了最佳 AGER 类型。如果您看到上面的值列,它的值为 -1,0,,这意味着含义未知,无法进行分类。进一步检查发现有意义的属性**‘未知’/‘无分类’**为缺失值。所以,我决定用 **nan 来填充这样的值。**当然,有许多属性的值是未知的。欲知详细分析,请点击此处。
3。处理缺失值:有 366 个特性,所以我决定在理解数据(来自第 2 部分)之后首先检查列,因此,我计算了每列中缺失值的百分比,并决定阈值为 30%,也就是说,如果列包含的缺失值超过 70% ,我将简单地删除这些列。
通过进一步检查,我发现以 D19 开头的属性被删除了。D19 当我们在DIAS Attributes-Values 2017 . xlsx文件中查找时,显示它包含交易数据(例如,基于产品组指南的交易活动)
我做的下一件事是按行查找缺失值,我决定删除包含超过 15 个缺失值的行。我在这里使用 Q3–1.5 iqr 来决定阈值 15。
为简单起见,其余的缺失值用平均值估算。
4.特征工程:有很多分类变量,所以如果它们少于 10 级,我就用它们创建虚拟变量。既然所有的特征都是数字,我们可以应用任何机器学习算法。但在此之前,我应用了 StandardScaler() 对所有列进行了变换。
客户细分
这里,主要目标是使用无监督学习方法来分析现有客户和一般人群的属性,以创建客户细分。该分析描述了普通人群中更有可能成为邮购公司主要客户群的部分,以及普通人群中不太可能成为主要客户群的部分。
因此,我使用了 PCA 技术来捕捉数据中的最大方差并降低数据的维度。我决定了一个阈值 50% 。
366 个特征中的 36 个能够捕捉 50%的变化。遵循主成分分析维度 0:
解读第一个 PCA 组件(10 大特性):
- plz 8 _ BAUMAX:plz 8(pos)内最常见的建筑类型——主要是> 10 户家庭住宅
- plz 8 _ ant G4:plz 8(pos)高份额> 10 户住宅数量
- plz 8 _ ant G3:plz 8(pos)中 6-10 户住宅的数量-高份额
- plz 8 _ ant G1:plz 8(负)低份额 1-2 户住宅数量
- MOBI_REGIO :移动模式(负)——高机动性
所以这个群体是高流动性,大家庭区域,拥挤区域,低收入。
接下来,我使用经过主成分分析的数据来应用 k-means 聚类,并确定客户细分群体。我用肘法来决定集群的数量,我决定用 10。
我对邮购公司客户的人口统计数据做了同样的转换uda city _ CUSTOMERS _ 052018 . CSV .
在这里,我们可以看到属于集群 1 和集群 8 的人是响应邮购公司的营销活动并成为客户的人。所以,营销团队应该关注这样的群体。好消息是德国有很多人(1 和 8 的蓝条)属于这些群体。
营销预测-监督学习模型
这里,我们将使用包含作为营销活动目标的个人的人口统计数据的数据集。训练数据集具有客户的响应,我们将使用 ML 模型来学习参数并预测测试数据中客户的响应。
- uda city _ MAILOUT _ 052018 _ train . CSV:作为营销活动目标的个人的人口统计数据;42 982 人(行)x 367 人(列)。
- uda city _ MAILOUT _ 052018 _ test . CSV:作为营销活动目标的个人的人口统计数据;42 833 人(行)x 366 人(列)。
数据准备
我已经使用了相同的清理功能,它是我在分段报告中使用的。我用平均值填充了数字列中缺少的值,并为分类列创建了虚拟变量。我还执行了一个 scaler 转换,因为我想检查不同 ML 算法的性能。但是,数据集中的类是一个不平衡,训练数据中 98% 的响应是负的, 2% 是正的,所以用召回(识别潜在客户)作为衡量标准是不正确的。因此,我使用 ROC AUC 作为评估性能的指标。我还从客户数据集中添加了额外的功能。
test['CUSTOMER_GROUP'] = test['CUSTOMER_GROUP'].apply(lambda x:1 if x=='SINGLE_BUYER' else 0)
test['PRODUCT_GROUP1'] = test['PRODUCT_GROUP'].apply(lambda x:1 if 'FOOD' in x else 0)
test['PRODUCT_GROUP2'] = test['PRODUCT_GROUP'].apply(lambda x:1 if 'COSMETIC' in x else 0)
表现最好的模型是:
我尝试优化两个模型的超参数,Adaboostclasifer 排在最前面。以下是我使用的参数:
预测竞赛
我向 Kaggle 上举办的比赛提交了我对测试数据的预测,我得到了 **0.79459,**的分数,仅比排行榜第一名落后 0.016。
特征重要性
D19_SOZIALES :这是与数据字典中没有给出的交易相关的特征,是潜在客户响应营销活动的最重要特征。
结论
我们使用德国的人口统计数据和营销活动的历史客户数据来确定最佳目标人口统计群体,从而减少营销支出。我们成功地应用主成分分析和 K-均值聚类来识别客户群。我们使用带有超参数调整的 Adaboost 分类器来预测和分类客户是否会对营销活动做出反应。详细分析可以在 这里找到 。
如何使用自然语言处理(NLP)识别垃圾邮件?
使用 Python 自然语言处理的垃圾邮件检测
人类掌握了数百万个单词,但从计算上来说:我们如何使用编程技术操纵大量文本?
计算机可以理解普通语言并与人类对话的想法一直是科幻小说的主题。然而,二十世纪上半叶又有一篇经典论文设想由艾伦·图灵(1950)作为计算智能的标志。
本文将关注计算机系统如何使用自然语言处理(NLP)来分析和解释文本。为此,你应该安装自然语言工具包,你可以从http://nltk.org开始安装。在引用的网站上可以找到说明以及需要安装的相关包的细节,包括 Python 本身,它也是免费的。
什么是自然语言处理(NLP)?
自然语言处理(NLP)是人工智能(AI) 的一个子集,它基本上负责机器或机器人对人类语言的理解。
NLP 中的一个重要子主题是*【NLU】*自然语言理解,原因是它用于理解人类语言的结构和意义,然后在计算机科学的帮助下将这些语言知识转化为基于规则的机器学习算法,这些算法可以解决特定的问题并执行所需的任务。
PYTHON 语言处理
这篇文章的目的是告诉你如何检测垃圾短信。
为此,我们使用来自 UCI 数据集 的数据集,这是一个公共数据集,包含为手机垃圾邮件研究而收集的带 SMS 标签的消息。它有一个由 5.574 条英文短信组成的集合,根据合法(ham)或垃圾邮件进行标记。
因此,我们将训练一个模型来学习自动区分火腿/垃圾邮件。然后我们将使用“测试数据”来测试模型。最后,为了评估我们的模型是否有效,我们将计算准确率、分类报告和混淆矩阵。
探索性数据分析
要开始,我们应该首先导入所有的库,然后加载数据并重命名 names 列:
# Import libraryimport pandas as pd
import numpy as np
import string
import seaborn as sns
import matplotlib.pyplot as plt
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from collections import Counter
from sklearn.metrics import classification_report,confusion_matrix
from sklearn.model_selection import GridSearchCV
%matplotlib inline# Load data
data = pd.read_excel('data.xlsx')# Rename names columns
data.columns = ['label', 'messages']
让我们看看我们的数据描述:
data.describe()
数据描述(图片由作者提供)
请注意,我们的数据包含 5574 条短信的集合,而且我们只有 2 个标签:火腿和垃圾邮件。现在,我们创建一个名为“length”的列,以了解文本消息有多长,然后根据标签绘制它:
data["length"] = data["messages"].apply(len)
data.sort_values(by='length', ascending=False).head(10)
data.hist(column = 'length', by ='label',figsize=(12,4), bins = 5)
长度和标签之间的直方图(图片由作者提供)
请注意,通过直方图,我们已经能够发现垃圾邮件往往有更多的字符。
最有可能的是,您遇到的大多数数据都是数值型或分类型的,但是当它是字符串类型(文本格式)时会发生什么呢?
您可能已经注意到,我们的数据是 string 类型的。因此,我们应该将它转换成一个数字向量,以便能够执行分类任务。为此,我们使用 单词袋 ,其中文本中的每个唯一单词将由一个数字表示。但是在做这个转换之前,我们要去掉所有的标点符号,然后常见的词像:[‘我’,‘我’,‘我自己’,‘我们’,‘我们的’,‘我们的’,‘我们自己’,‘你’,‘是’…]。这个过程叫做标记化**。在这个过程之后,我们将字符串序列转换成数字序列。**
- 去掉所有标点:假设我们有下面这句话:
*** * * * * * * * * 大家好!!!很高兴遇见你*******
而且我们要去掉!!!和。****
首先,我们加载导入字符串库,并执行以下操作:
message = "Hi everyone!!! it is a pleasure to meet you."message_not_punc = []for punctuation in message:
if punctuation not in string.punctuation:
message_not_punc.append(punctuation)# Join the characters again to form the string.
message_not_punc = ''.join(message_not_punc)
print(message_not_punc)**>>> Hi everyone it is a pleasure to meet you**
2.删除常用词:
为此,我们使用 nltk 库,即 nltk.corpus 中的导入停用词****
重要的是要知道停用词支持 23 种语言(这个数字必须是最新的)。在这种情况下,我们使用英语:
from nltk.corpus import stopwords# Remove any stopwords for remove_punc, but first we should to transform this into the list.message_clean = list(message_not_punc.split(" "))# Remove any stopwordsi = 0
while i <= len(message_clean):
for mess in message_clean:
if mess.lower() in stopwords.words(‘english’):
message_clean.remove(mess)
i =i +1
print(message_clean)**>>> ['Hi', 'everyone', 'pleasure', 'meet']**
因此,通过步骤 1 和 2,我们可以创建以下函数:
def transform_message(message):
message_not_punc = [] # Message without punctuation
i = 0
for punctuation in message:
if punctuation not in string.punctuation:
message_not_punc.append(punctuation)
# Join words again to form the string.
message_not_punc = ''.join(message_not_punc)
# Remove any stopwords for message_not_punc, but first we should
# to transform this into the list.
message_clean = list(message_not_punc.split(" "))
while i <= len(message_clean):
for mess in message_clean:
if mess.lower() in stopwords.words('english'):
message_clean.remove(mess)
i =i +1
return message_clean
现在,我们可以通过以下方式将上述函数应用于我们的数据分析:
data['messages'].head(5).apply(transform_message)>>>
0 [Go, jurong, point, crazy, Available, bugis, n...
1 [Ok, lar, Joking, wif, u, oni]
2 [Free, entry, 2, wkly, comp, win, FA, Cup, fin...
3 [U, dun, say, early, hor, U, c, already, say]
4 [Nah, dont, think, goes, usf, lives, around, t...
Name: messages, dtype: object
…向量化…
请注意,我们将消息作为令牌列表。因此,下一步是将这些消息转换成一个向量。
为此,我们从 Scikit Learn 中使用 计数矢量器 。CountVectorizer 将文档集合转换为令牌计数数组。如果你想看 Python 中 countvectorizer 的例子,我们邀请你阅读下面这篇文章:Python 中的 count vector izer
首先,我们从 sklearn learn 导入计数矢量器:
from sklearn.feature_extraction.text import CountVectorizer
CountVectorizer 有很多参数,但是我们只使用“ analyzer ”,这是我们自己之前定义的函数:
vectorization = CountVectorizer(analyzer = transform_message )X = vectorization.fit(data['messages'])
现在,我们应该将消息的整个数据帧转换成向量表示。为此,我们使用变换函数:
X_transform = X.transform([data['messages']])print(X_transform)
>>> : :
(0, 11383) 9
(0, 11384) 20
(0, 11385) 14
(0, 11386) 2
(0, 11387) 4
(0, 11391) 11
(0, 11393) 5
(0, 11396) 1
(0, 11397) 1
(0, 11398) 18
(0, 11399) 18
(0, 11405) 2
(0, 11408) 1
(0, 11410) 1
(0, 11411) 8
(0, 11412) 7
(0, 11413) 1
(0, 11414) 1
(0, 11415) 27
(0, 11417) 3
(0, 11418) 104
(0, 11420) 9
(0, 11422) 1
(0, 11423) 7
(0, 11424) 1
TF-IDF
在对我们的数据应用“计数矢量器”之后,我们使用 TF-IDF。你肯定想知道 TD-FT 是什么?我们为什么要使用它?让我给你解释一下:
TF-IDF 是 的缩写逆文档频率 是一个数值度量,表示一个词与集合中的一个文档的相关程度。
TF-IDF 的值与单词在文档中出现的次数成比例地增加,并且被该单词在文档集合中的频率抵消,这允许处理一些单词通常比其他单词更常见的事实。
如何计算 TF-IDF?
TF-IDF 由两项组成:第一项是项频率(TF) ,第二项是**逆文档频率(IDF)**
词频(TF): 衡量一个词在文档中出现的频率,即一个词在文档中出现的次数除以该文档中的总字数:
TF(t) =(术语 t 在文档中出现的次数)/(文档中的总术语数)
逆文档频率(IDF): 衡量一个术语的重要性,计算方法是语料库中文档数量的对数除以特定术语出现的文档数量。
IDF(t) = log_e(文档总数/包含术语 t 的文档数)
**更多信息请参考[TF-IDF 是什么意思?”T34](http://www.tfidf.com/#:~:text=TF(t)%20%3D%20(Number,terms%20are%20considered%20equally%20important.&text=IDF(t)%20%3D%20log_e(,with%20term%20t%20in%20it).)
继续我们的代码,我们从 sk learn . feature _ extraction . text 导入 TfidfVectorizer,然后:
*tfidf_transformer = TfidfTransformer().fit(X_transform)*
要一次将整个词袋语料库转换为 TF-IDF 语料库:
*X_tfidf = tfidf_transformer.transform(X_transform)
print(X_tfidf.shape)>>> (5572, 11425)*
分类模型
将特征表示为向量,我们最终可以训练我们的垃圾邮件/垃圾邮件分类器。你可以使用任何分类算法。这里我们用支持向量分类(SVC) 算法。
首先,我们将数据分为训练数据和测试数据。我们采用 80 % (0.80)的训练数据和 30% (0.30)的测试数据,并使用 SVC 拟合模型:
*X_train, X_test, y_train, y_test = train_test_split(X_tfidf, data['messages'], test_size=0.30, random_state = 50)
clf = SVC(kernel='linear').fit(X_train, y_train)*
试验模型
为了测试模型,我们使用之前计算的 X_test:
*predictions = clf.predict(X_test)
print('predicted', predictions)>>> predicted ['spam' 'ham' 'ham' ... 'ham' 'ham' 'spam']*
我们的模型可靠吗?
出现的问题是:我们的模型在整个数据集上可靠吗?
为此,我们可以使用 SciKit Learn 的内置分类报告,它返回 P recision,Recall ,F1-Score以及混淆矩阵 x
***from sklearn.metrics import classification_report
print (classification_report(y_test, predictions))***
分类报告(图片由作者提供)
***from sklearn.metrics import confusion_matrix
print(confusion_matrix(y_test,predictions))***
困惑矩阵(图片由作者提供)
准确性是了解模型是否有效的好方法,但这不足以说明我们的模型是好的,为此我们使用了分类报告和混淆矩阵。你可以看到获得的结果相当好。
我们完了!!!希望这些信息对您有用。如果您对完整代码感兴趣,可以从下面的链接中获得: 如何使用 NLP 识别垃圾邮件