预测H-1B签证申请的状态

机器学习是数据科学和人工智能的一种应用, 它使系统无需进行明确编程即可自动从经验中学习和改进。它使用一组可以访问数据并自己学习的算法。在本教程中, 你将使用Python和XGBoost来预测签证申请的最终案件状态。
本教程将向你介绍:

  • 探索性数据分析
  • 特征工程和特征提取
  • 使用XGboost算法训练数据集
  • 使用训练有素的模型来预测签证申请的案情 :target:before { content:""; display:block; height:150px; margin:-150px 0 0; } h3 {font-weight:normal; margin-top:.5em} h4 { font-weight:lighter }
加载库
Python库是函数和方法的集合, 使你无需编写自己的代码即可执行许多操作。你需要相应地下载, 安装和导入库。
NumPy(以np命名)是使用Python进行科学计算的基本软件包。除其他外, 它包含强大的N维数组对象, 复杂的(广播)功能, 用于集成C / C ++的工具以及有用的线性代数和随机数功能。下一个重要的库pandas(别名为pd)用于导入csv文件。它是BSD许可的开源库, 为Python编程语言提供了高性能, 易于使用的数据结构和数据分析工具。接下来, scikit学习/ sklearn库用于机器学习算法。统计信息库用于导入一些统计函数, 例如mode()。 re用于正则表达式, XGboost用于将XGBoost分类器导入为XGBClassifier()。
import numpy as npimport pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn.linear_model import LogisticRegressionfrom sklearn.metrics import confusion_matrix, classification_reportfrom statistics import modeimport refrom xgboost import XGBClassifier

H1B VISA和数据集
该数据集在Kaggle上可用。
它包含五年的H-1B申请数据, 总共约有300万条记录。数据集中的列包括案例状态, 雇主名称, 工作地点坐标, 职称, 现行工资, 职业代码和申请年份。
外国劳工认证办公室(OFLC)会生成计划数据, 包括有关H1-B签证的数据。披露数据每年更新一次, 可在线获取。 H1B签证是一种非常受欢迎的非移民签证, 它允许从事特殊职业的外国工人进入该国。 H-1B签证是针对美国临时外国工人的基于就业的非移民签证。要使外国公民申请H1-B签证, 美国雇主必须为其提供工作, 并向美国移民局提交H-1B签证申请。这也是国际学生完成大学或高等教育并开始全职工作后所申请和持有的最常见的签证身份。
H1B申请程序的第一步是美国雇主代表外国工人提交H1B申请。第二步, 现行工资和实际工资应由国家就业安全局确认。如果现行工资超过准雇主提出的要约, 则将寻求确定工资。 H1B申请流程的第三步是提交劳动条件申请。下一步是准备请愿书, 并将其提交给适当的USCIS办公室。 H1B申请请愿书的处理时间因地点而异。如果你希望你的请愿加急, 则可以选择加价处理。 H1B申请流程的最后一步是通过输入收据编号来检查H1B签证申请的状态。一旦USCIS将你的申请存档, 他们将在你的系统上更新你的状态。
该数据集包含超过200万个数据点。数据标签分为6类:撤回, 无效, 未分配, 认证透支, 拒绝, 待审质量和遵从性审核-未分配。你应该为每个样本提供以下信息:
  1. CASE_ID-每个申请人的唯一案例ID。
  2. CASE_STATUS –目标变量包含6个不同的类或值。状态与上一个重要事件相关。
  3. EMPLOYER_NAME –提交申请的雇主名称。
  4. SOC_NAME –与职业代码相关的职业名称
  5. JOB_Title –职位名称
  6. FULL_TIME_POSITION –职位是否为全职
  7. PREVAILING_WAGE-工作职位的现行工资定义为在预期就业领域中支付给所请求职业中类似就业工人的平均工资
  8. 年–提交H1b呈请的年份
  9. 工作场所-外籍工人预期工作领域的城市和州信息
  10. Lon –工作地点的经度
  11. 纬度-工作地点的纬度
加载数据集
你应该做的第一步是将数据集加载到对象中。 .read_csv()是熊猫中用于加载csv文件的方法。你将在下面的对象df中找到加载的数据集。
df = pd.read_csv('C:/Users/djhanj/Downloads/h1b_TRAIN.csv')

了解数据
当你拥有可用数据时, 始终建议你浏览数据集。从数据集中收集所有信息。你需要确保已加载的数据采用适当的结构化格式, 并且所有变量或功能均已正确加载。
你可能要在df对象上使用.info()方法来检查数据信息。这表明数据以DataFrame格式存储, 其中1个变量为整数格式, 4个变量为浮点数, 6个变量为对象格式。
你可以尝试的下一个代码是对象上的.head()方法, 以检查数据的前5行。你可以对数据集有个不错的主意。
.describe()方法将告诉你所有整数和浮点变量的最小值, 最大值, 均值, 中位数, 标准差和计数。
df.info()df.head()df.describe()

< class 'pandas.core.frame.DataFrame'> RangeIndex: 2251844 entries, 0 to 2251843Data columns (total 11 columns):CASE_IDint64CASE_STATUSobjectEMPLOYER_NAMEobjectSOC_NAMEobjectJOB_TITLEobjectFULL_TIME_POSITIONobjectPREVAILING_WAGEfloat64YEARfloat64WORKSITEobjectlonfloat64latfloat64dtypes: float64(4), int64(1), object(6)memory usage: 189.0+ MB

案例ID PREVAILING_WAGE 罐头 岁月
计数 2.251844e+06 2.251779e+06 2.251836e+06 2.171398e+06 2.171398e+06
意思 1.501788e+06 1.498183e+05 2.013854e+03 -9.213684e+01 3.815967e+01
小时 8.666892e+05 5.808395e+06 1.680675e+00 1.963492e+01 4.671896e+00
1.000000e+00 0.000000e+00 2.011000e+03 -1.578583e+02 1.343719e+01
25% 7.512768e+05 5.439200e+04 2.012000e+03 -1.119261e+02 3.416536e+01
50% 1.502439e+06 6.502100e+04 2.014000e+03 -8.623793e+01 3.910312e+01
75% 2.252488e+06 8.143200e+04 2.015000e+03 -7.551381e+01 4.088399e+01
最大值 3.002457e+06 6.997607e+09 2.016000e+03 1.457298e+02 6.483778e+01
该数据集有11列, 其中1列是目标变量, 在这种情况下为case_status。因此, 此数据具有1个目标变量和10个独立或解释性变量。你绝对应该检查目标变量的类。你可以在df中的case_status功能上使用.unique()方法来检查目标变量中的唯一类。
这是分类问题。这意味着你需要预测案件状态的类别。
df['CASE_STATUS'].unique()df.head(10)

预测H-1B签证申请的状态

文章图片
特征工程和数据预处理
请注意, 目标变量包含6个不同的类:
  1. 已认证
  2. 认证撤回
  3. 拒绝
  4. 无效
  5. 待审核质量和合规性
  6. 被拒绝
现在, 根据业务问题, 你应该决定要进行多类分类还是二元类分类。如果是二进制类别分类, 则可以分类” 认证” 或” 拒绝” 。因此, 你应该做的第一件事是将剩余的类转换为拒绝或认证的类。在这里, “ 拒绝” 和” 无效” 都是签证被拒绝的情况, 因此你应将这些情况转换为” 拒绝” 。在获得美国签证的情况下, 待审核质量和合规性很可能会被拒绝, 因此也应将其更改为” 拒绝” 。认证撤回属于Certifed类, 因为签证已获得认证, 但用户决定撤回该文件。在下面的部分中, 课程已转换为” 认证” 或” 拒绝” 。
下一个类是Withdrawn, 并且由于很难在此数据集中预测Withdrawn情况, 因此你可以简单地删除withdrawed类。这意味着代表撤回类的所有特征都将从数据集中删除。删除Withdrawn类的另一个原因是, 它在整个数据集中的百分比小于1%, 这意味着模型可能不会正确地对Withdrawn类进行分类。
这是一个不平衡的数据集, 目标变量有多种类别, 主要目的是发现有资格获得h1b签证的可能性, 因此你应仅包括经过认证和拒绝的情况。因此, 最终目标变量将只有2个类别, 即Certified和Denied。
import warningswarnings.filterwarnings("ignore")df.CASE_STATUS[df['CASE_STATUS']=='REJECTED'] = 'DENIED'df.CASE_STATUS[df['CASE_STATUS']=='INVALIDATED'] = 'DENIED'df.CASE_STATUS[df['CASE_STATUS']=='PENDING QUALITY AND COMPLIANCE REVIEW - UNASSIGNED'] = 'DENIED'df.CASE_STATUS[df['CASE_STATUS']=='CERTIFIED-WITHDRAWN'] = 'CERTIFIED'

检查数据集中认证和拒绝类的百分比。
##Drop rows with withdrawndf.EMPLOYER_NAME.describe()df = df.drop(df[df.CASE_STATUS == 'WITHDRAWN'].index)## Storing non null in df w.r.t. case statusdf = df[df['CASE_STATUS'].notnull()]print(df['CASE_STATUS'].value_counts())

CERTIFIED2114025DENIED70606Name: CASE_STATUS, dtype: int64

拒绝类别仅占总数据集的3.2%, 这意味着你现在在数据集中拥有大约96.8%的认证案例。这表明数据集高度不平衡。数据集不平衡的问题之一是模型更倾向于出现率更高的类。在这种情况下, 该模型将偏向于认证。尽管解决此不平衡分类问题的技术有所不同, 但在本教程中你将不需要这些技术。
print(70606/(70606+2114025))

0.03231941687177377

处理缺失值和NA值
该数据集不干净, 并且包含许多缺失值。这是最重要的步骤, 因为你必须处理缺失的值。最简单的方法是删除它们, 但你不应删除这些值, 否则会丢失信息。让我们逐步看一下如何处理缺失值:
##check count of NANcount_nan = len(df) - df.count()print(count_nan)

CASE_ID0CASE_STATUS0EMPLOYER_NAME11SOC_NAME12725JOB_TITLE6FULL_TIME_POSITION1PREVAILING_WAGE41YEAR0WORKSITE0lon77164lat77164dtype: int64

如果你查看EMPLOYER_NAME的缺失值数量, 则可以使用模式(这是最常出现的值)来填充这11个缺失值。这已经在下面完成
## Filling na in employer name with modedf['EMPLOYER_NAME'] = df['EMPLOYER_NAME'].fillna(df['EMPLOYER_NAME'].mode()[0])

assert语句在下面使用。当遇到断言语句时, Python会评估附带的表达式, 希望它是正确的。如果表达式为假, Python会引发AssertionError异常。如果断言失败, Python将ArgumentExpression用作AssertionError的参数。
assert pd.notnull(df['EMPLOYER_NAME']).all().all()

下一个功能是provering_wage。你会发现大多数请愿书的工资在40k到80k美元之间。有些请愿书的工资超过50万美元, 有些请愿书的工资为0美元。由于此类情况很少, 因此应将其限制在第2个百分点和第98个百分点, 以将其视为异常值
##to check the percentile in wagesprint(np.nanpercentile(df.PREVAILING_WAGE, 98))df.PREVAILING_WAGE.median()

138703.065000.0

在将工资限制在第98个百分点和第2个百分点之后, 平均值和中位数非常相似。上述中位数为65K, 平均值为68K。最后, 你可以将NA值替换为平均值。你也可以用中位数替换它们, 因为两个值几乎相似。
## replacing min and max with 2 and 98 percentiledf.loc[df.PREVAILING_WAGE < 34029, 'PREVAILING_WAGE']= 34029df.loc[df['PREVAILING_WAGE'] > 138703, 'PREVAILING_WAGE']= 138703df.PREVAILING_WAGE.fillna(df.PREVAILING_WAGE.mean(), inplace = True)

对于JOB_TITLE, FULL_TIME_POSITION和SOC_NAME列, 你可以使用模式(最常出现的值)填充缺少的值。由于缺失值的百分比非常低, 因此无需在此处应用插补技术。这已经在下面完成。
## Filling na in JOB_TITLE and FULL_TIME_POSITION with modedf['JOB_TITLE'] = df['JOB_TITLE'].fillna(df['JOB_TITLE'].mode()[0])df['FULL_TIME_POSITION'] = df['FULL_TIME_POSITION'].fillna(df['FULL_TIME_POSITION'].mode()[0])df['SOC_NAME'] = df['SOC_NAME'].fillna(df['SOC_NAME'].mode()[0])

下一个功能是FULL_TIME_POSITION:Y表示请愿者具有全职角色, N表示兼职角色。申请的工作中约有85%为全职工作。只是两种不同的方法来计算同一件事。
foo1 = df['FULL_TIME_POSITION']=='Y'foo2 = df['CASE_STATUS']=='CERIFIED'print(len(df[foo1])/len(df))fooy = df.FULL_TIME_POSITION[df['FULL_TIME_POSITION']=='Y'].count()foox = df.CASE_STATUS[df['CASE_STATUS']=='CERIFIED'].count()print(fooy/df.FULL_TIME_POSITION.count())

0.85895695886399130.858956958864

放置纬度和经度列
制作模型时, 你可以立即放置lat和lon列, 因为这将在以后的工作现场列中进行介绍。在具有列名称的df DataFrame上使用drop方法。注意, 你还需要定义轴。轴0代表行, 轴1代表列。
# Dropping lat and lon columnsdf = df.drop('lat', axis = 1)df = df.drop('lon', axis = 1)

特征创建
现在, 在制作模型时不可能每列都有, 但是同时这些列拥有一些你应该提取的信息。
EMPLOYER_NAME包含雇主的姓名, 并且有很多唯一的雇主。是公司为其员工提交申请。你不能在模型中直接使用EMPLOYER_NAME, 因为它具有许多唯一的字符串值或类别;超过500名雇主。这些雇主充当因素或级别。建议不要在单个列中使用许多因素。
为员工提交申请的前5名公司是Infosys, TCS, Wipro, Deloitte和IBM。但是, 如果有任何大学正在提交申请, 则该申请更有可能被接受。
因此, 问题是, 如何从此功能中提取一些信息?
好吧, 你可能可以创建一个名为NEW_EMPLOYER的新功能:如果雇主名称包含字符串” University” (例如, 如果美国大学正在递交签证申请, 则它有更多机会获得员工的批准)。
因此, 如果EMPLOYER_NAME包含” 大学” , 则NEW_EMPLOYER包含大学值。
创建一个新的空列很容易, 如下所示
df['NEW_EMPLOYER'] = np.nandf.shape

(2184631, 10)

请注意, 在检查EMPLOYER_NAME中的University字符串时有一个陷阱。
如果大学字符串在某些行中用大写字母在其他行中用小写字母怎么办?如果要映射小写大学, 则将错过大写大学, 反之亦然。因此, 为了正确地映射和检查大学字符串, 你应该首先将所有字符串转换为相同的大小写;小写或大写。
在下面的代码中, 使用函数str.lower()将EMPLOYER_NAME的所有值都转换为小写
现在, EMPLOYER_NAME中的所有值都是相同的, 并且很容易找到包含University作为雇主名称的行。
EMPLOYER_NAME中包含关键字university的所有字符串在NEW_EMPLOYER列中的值为” 大学” 。所有其余的空行将填充为” 非大学” 。
warnings.filterwarnings("ignore")df['EMPLOYER_NAME'] = df['EMPLOYER_NAME'].str.lower()df.NEW_EMPLOYER[df['EMPLOYER_NAME'].str.contains('university')] = 'university'df['NEW_EMPLOYER']= df.NEW_EMPLOYER.replace(np.nan, 'non university', regex=True)

现在, 下一个变量是SOC_NAME, 它由一个职业名称组成。与SOC_NAME相关的值很多, 因此你可能需要创建一个新功能, 其中包含申请人的重要职业, 并将其与SOC_NAME值进行映射。你可以创建一个名为OCCUPATION的新变量。例如, 计算机, 编程器和软件都是计算机职业。这将覆盖前80%的职业, 次要职业和剩余职业将被归类为其他职业。
# Creating occupation and mapping the valueswarnings.filterwarnings("ignore")df['OCCUPATION'] = np.nandf['SOC_NAME'] = df['SOC_NAME'].str.lower()df.OCCUPATION[df['SOC_NAME'].str.contains('computer', 'programmer')] = 'computer occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('software', 'web developer')] = 'computer occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('database')] = 'computer occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('math', 'statistic')] = 'Mathematical Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('predictive model', 'stats')] = 'Mathematical Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('teacher', 'linguist')] = 'Education Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('professor', 'Teach')] = 'Education Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('school principal')] = 'Education Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('medical', 'doctor')] = 'Medical Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('physician', 'dentist')] = 'Medical Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('Health', 'Physical Therapists')] = 'Medical Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('surgeon', 'nurse')] = 'Medical Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('psychiatr')] = 'Medical Occupations'df.OCCUPATION[df['SOC_NAME'].str.contains('chemist', 'physicist')] = 'Advance Sciences'df.OCCUPATION[df['SOC_NAME'].str.contains('biology', 'scientist')] = 'Advance Sciences'df.OCCUPATION[df['SOC_NAME'].str.contains('biologi', 'clinical research')] = 'Advance Sciences'df.OCCUPATION[df['SOC_NAME'].str.contains('public relation', 'manage')] = 'Management Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('management', 'operation')] = 'Management Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('chief', 'plan')] = 'Management Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('executive')] = 'Management Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('advertis', 'marketing')] = 'Marketing Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('promotion', 'market research')] = 'Marketing Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('business', 'business analyst')] = 'Business Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('business systems analyst')] = 'Business Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('accountant', 'finance')] = 'Financial Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('financial')] = 'Financial Occupation'df.OCCUPATION[df['SOC_NAME'].str.contains('engineer', 'architect')] = 'Architecture & Engineering'df.OCCUPATION[df['SOC_NAME'].str.contains('surveyor', 'carto')] = 'Architecture & Engineering'df.OCCUPATION[df['SOC_NAME'].str.contains('technician', 'drafter')] = 'Architecture & Engineering'df.OCCUPATION[df['SOC_NAME'].str.contains('information security', 'information tech')] = 'Architecture & Engineering'df['OCCUPATION']= df.OCCUPATION.replace(np.nan, 'Others', regex=True)

由于签证申请主要取决于州的位置, 因此你应该从WORKSITE变量中拆分州信息。
## Splitting city and state and capturing state in another variabledf['state'] = df.WORKSITE.str.split('\s+').str[-1]

加州拥有最多的请愿书, 巩固了其作为IT运营选择基地的地位, 其次是德克萨斯州, 纽约和新泽西州。
print(df.head())

CASE_ID CASE_STATUSEMPLOYER_NAME\01CERTIFIEDuniversity of michigan12CERTIFIEDgoodman networks, inc.23CERTIFIEDports america group, inc.34CERTIFIEDgates corporation, a wholly-owned subsidiary o...46CERTIFIEDburger king corporationSOC_NAME\0biochemists and biophysicists1chief executives2chief executives3chief executives4chief executivesJOB_TITLE FULL_TIME_POSITION\0POSTDOCTORAL RESEARCH FELLOWN1CHIEF OPERATING OFFICERY2CHIEF PROCESS OFFICERY3REGIONAL PRESIDEN, AMERICASY4EXECUTIVE V P, GLOBAL DEVELOPMENT AND PRESIDEN...YPREVAILING_WAGEYEARWORKSITENEW_EMPLOYER\036067.02016.0ANN ARBOR, MICHIGANuniversity1138703.02016.0PLANO, TEXASnon university2138703.02016.0JERSEY CITY, NEW JERSEYnon university3138703.02016.0DENVER, COLORADOnon university4138703.02016.0MIAMI, FLORIDAnon universityOCCUPATIONstate0Advance SciencesMICHIGAN1Management OccupationTEXAS2Management OccupationJERSEY3Management OccupationCOLORADO4Management OccupationFLORIDA

现在, 为了计算概率, 你需要将目标类转换为二进制, 即0和1。可以使用CERTIFIED和DENIED, 但是在这种情况下将无法计算概率和AUC分数。因此, 你必须将其映射到0和1。
from sklearn import preprocessingclass_mapping = {'CERTIFIED':0, 'DENIED':1}df["CASE_STATUS"] = df["CASE_STATUS"].map(class_mapping)

print(df.head())

CASE_IDCASE_STATUSEMPLOYER_NAME\010university of michigan120goodman networks, inc.230ports america group, inc.340gates corporation, a wholly-owned subsidiary o...460burger king corporationSOC_NAME\0biochemists and biophysicists1chief executives2chief executives3chief executives4chief executivesJOB_TITLE FULL_TIME_POSITION\0POSTDOCTORAL RESEARCH FELLOWN1CHIEF OPERATING OFFICERY2CHIEF PROCESS OFFICERY3REGIONAL PRESIDEN, AMERICASY4EXECUTIVE V P, GLOBAL DEVELOPMENT AND PRESIDEN...YPREVAILING_WAGEYEARWORKSITENEW_EMPLOYER\036067.02016.0ANN ARBOR, MICHIGANuniversity1138703.02016.0PLANO, TEXASnon university2138703.02016.0JERSEY CITY, NEW JERSEYnon university3138703.02016.0DENVER, COLORADOnon university4138703.02016.0MIAMI, FLORIDAnon universityOCCUPATIONstate0Advance SciencesMICHIGAN1Management OccupationTEXAS2Management OccupationJERSEY3Management OccupationCOLORADO4Management OccupationFLORIDA

对于JOB_TITLE, 你可以进行数值转换。
数据集中有238176个唯一的职位标题, 如下所示。
test1 = pd.Series(df['JOB_TITLE'].ravel()).unique()print(pd.DataFrame(test1))

00POSTDOCTORAL RESEARCH FELLOW1CHIEF OPERATING OFFICER2CHIEF PROCESS OFFICER3REGIONAL PRESIDEN, AMERICAS4EXECUTIVE V P, GLOBAL DEVELOPMENT AND PRESIDEN...5PRESIDENT6VICE PRESIDENT AND CHIEF HUMAN RESOURCES OFFICER7TREASURER AND COO8CHIEF COMMERCIAL OFFICER9BOARD MEMBER10CEO11PRESIDENT, NORTHEAST REGION12CHIEF OPERATING OFFICER (COO)13GENERAL MANAGER, OPERATIONS14CHIEF EXECUTIVE OFFICER15CHIEF BUSINESS OFFICER16EXECUTIVE DIRECTOR17VICE PRESIDENT, BUSINESS DEVELOPMENT18HEAD OF US SALES19VICE PRESIDENT OF OPERATIONS20VICE PRESIDENT, FINANCE AND OPERATIONS ANALYSIS21ACCOUNT DIRECTOR22TECHNICAL DIRECTOR23SVP BUSINESS OPERATIONS AND DEVELOPMENT24CHIEF FINANCIAL OFFICER25CHIEF MEDICAL OFFICER26ASSISTANT VICE PRESIDENT, BUSINESS DEVELOPMENT27VICE PRESIDENT OF QUALITY28PRESIDENT & CHIEF EXECUTIVE OFFICER29CHIEF EXECUTIVE OFFICER AND RESEARCH SCIENTIST......238146LOGISTIC AND SALES MANAGER238147MEDICAL DIRECTOR, HQ MEDICAL IMMUNOLOGY - EARL...238148PHYSICAL THERAPIST/FACILITY REHAB DIRECTOR238149BIZTEK DEVELOPER238150SALES ANALYST - RETAIL CHANNEL238151ASSISTANT WOMEN'S DESIGNER238152ASSAY DEVELOPMENT ASSOCIATE238153ADMINISTRATIVE SUPPORT238154PROGRAM MANAGEMENT ANALYST - SAP238155RESEARCH ASSOCIATE/ CRIMINAL JUSTICE238156SENIOR MOBILE APPLICATIONS DEVELOPER-CLIENT DE...238157ASSOCIATE, IT RISK & BUSINESS ANALYST (LEAD)238158INDUSTRY LEAD238159SYSTEMS AND DATA ANALYST - TECHNICAL PROJECT M...238160ADMINISTRATIVE ANALYST 1238161POWER DEVICE PRODUCT DEVELOPMENT ENGINEER238162SECURITIES ANALYST, EQUITIES DERIVATIVES238163CONSULTANT, SYSTEMS ANALYST238164ENGLISH LANGUAGE EDUCATION TEACHER238165STAFF SYSTEMS ENGINEER (SOFTWARE)238166SR. SOFTWAREENGINEER238167COMMUNICATIONS SPECIALIST (PARTNER DEVELOPMENT)238168MANAGER, SITE MERCHANDISING - HEALTH & SPORTS238169DIRECTOREDUCATIONAL PROGRAMS238170REGISTERED NURSE (ER)238171FOOT AND ANKLE SURGEON238172DFT MODELING ENGINEER238173SENIOR SOFTWARE ENGINEER (LTE PROTOCOL STACK)238174SALES AND LOGISTIC MANAGER238175APPRAISERS, REAL ESTATE[238176 rows x 1 columns]

由于现在你已经从下面的变量中生成了新功能, 因此可以将它们放置为水平放置在各列上, 轴= 1。
# dropping these columnsdf = df.drop('EMPLOYER_NAME', axis = 1)df = df.drop('SOC_NAME', axis = 1)df = df.drop('JOB_TITLE', axis = 1)df = df.drop('WORKSITE', axis = 1)df = df.drop('CASE_ID', axis = 1)

df1 = df.copy()

将dtype更改为类别:现在, 进入建模部分之前, 你肯定应该检查变量的数据类型。例如, 在这里, 应将一些变量用作类别或因子, 但它们应放在对象字符串fromat中。
因此, 你必须将这些变量的数据类型从对象更改为类别, 因为它们是分类特征。
df1[['CASE_STATUS', 'FULL_TIME_POSITION', 'YEAR', 'NEW_EMPLOYER', 'OCCUPATION', 'state']] = df1[['CASE_STATUS', 'FULL_TIME_POSITION', 'YEAR', 'NEW_EMPLOYER', 'OCCUPATION', 'state']].apply(lambda x: x.astype('category'))

df1.info()

< class 'pandas.core.frame.DataFrame'> Int64Index: 2184631 entries, 0 to 2251800Data columns (total 7 columns):CASE_STATUScategoryFULL_TIME_POSITIONcategoryPREVAILING_WAGEfloat64YEARcategoryNEW_EMPLOYERcategoryOCCUPATIONcategorystatecategorydtypes: category(6), float64(1)memory usage: 45.8 MB

在训练和测试集中拆分数据
将数据集分为训练和测试集是一种标准做法。其背后的原因是, 你应该使用训练集拟合并训练模型, 然后最终预测并检查测试集的准确性。
X = df.drop('CASE_STATUS', axis=1)y = df.CASE_STATUSseed = 7test_size = 0.40X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=seed)X_train.columns

Index(['FULL_TIME_POSITION', 'PREVAILING_WAGE', 'YEAR', 'NEW_EMPLOYER', 'OCCUPATION', 'state'], dtype='object')

检查训练集中是否有空值。不应有任何东西。
print(X_train.isnull().sum())

FULL_TIME_POSITION0PREVAILING_WAGE0YEAR0NEW_EMPLOYER0OCCUPATION0state0dtype: int64

对X_train和X_test进行编码以使它们为Xgboost做好准备, 因为它仅适用于数字数据。函数pd.get_dummies()用于将分类值编码为整数。它将创建所有分类值的转置, 然后将值存在的位置映射为1, 如果不存在则将其映射为0。你绝对应该尽力在下面打印X_train_encode来检查转置。
X_train_encode = pd.get_dummies(X_train)X_test_encode = pd.get_dummies(X_test)

y_train.head()

168870201808423015503180149541902947820Name: CASE_STATUS, dtype: int64

XGBoost
XGBoost是” Extreme Gradient Boosting” 的缩写, 这是一个有监督的学习问题。在这里, 你使用训练数据(具有多个特征)x(i)来预测目标变量y(i)。
【预测H-1B签证申请的状态】它是为速度和性能而设计的梯度增强决策树的实现。
Boosting是一种综合方法, 旨在基于” 弱” 分类器创建强分类器(模型)。在这种情况下, 弱者和强者指的是学习者与实际目标变量之间的相关程度的度量。通过迭代地在彼此之上添加模型, 下一个预测变量可以校正先前模型的错误, 直到训练数据被该模型准确预测或再现为止。
现在, 梯度提升还包括一种集成方法, 该方法可以顺序添加预测变量并校正以前的模型。但是, 此方法不是在每次迭代后为分类器分配不同的权重, 而是使新模型适合先前预测的新残差, 然后在添加最新预测时将损失最小化。
因此, 最后, 你将使用渐变下降来更新模型, 因此也使用了渐变增强的名称。
要了解有关XGBoost的更多信息, 请查看我们的” 极端渐变增强” 课程。
XGBoost可以使用pip轻松安装
  • 点安装xgboost
要使用xgboost软件包, 请记住以下几点:
  • 使用一种热编码将类别变量转换为数值变量
  • 对于分类, 如果因变量属于类因子, 则将其转换为数值
as_matrix足够快地实现一种热编码。你可以将数据集转换为矩阵格式, 如下所示。
train_X = X_train_encode.as_matrix()train_y = y_train.as_matrix()

用于分类的XGBoost模型称为XGBClassifier()。你可以创建它并将其适合你的训练数据集。你可以使用max_features作为sqrt创建一个XGBClassifier()。 max_features是寻找最佳分割时要考虑的功能数量。因此, 如果n_features为100, 则max_features为10。
import xgboostgbm=xgboost.XGBClassifier(max_features='sqrt', subsample=0.8, random_state=10)

使用GridSearchCV()调整超参数:
  1. GridSearchCV()实现拟合和得分方法。如果在使用的估算器中实现了predict, predict_proba, decision_function, transform和inverse_transform, 则它们也将实现。
  2. 通过对参数网格进行交叉验证的网格搜索, 优化了用于应用这些方法的估计器的参数。
  3. 你可以将n_estimators设置为1、10和100, 将learning_rate设置为0.1、0.01和0.5。下面使用相同的方法。
  4. n_estimators:要执行的提升阶段数。梯度提升对于过度拟合具有相当强的鲁棒性, 因此, 大量提升通常会带来更好的性能。
  5. learning_rate:梯度增强决策树的问题在于它们学习速度过快并过度拟合训练数据。降低梯度增强模型中学习速度的一种有效方法是使用学习率, 也称为收缩率。梯度提升涉及顺序创建树并将树添加到模型。创建新树以纠正现有树序列中预测中的残留误差。结果是模型可以快速拟合, 然后过度拟合训练数据集。减慢学习速度的一种技术是在将新树添加到模型时, 应用加权因子进行校正。根据文献或工具, 该加权称为收缩因子或学习率。通常会有一个较小的值, 范围在0.1到0.3之间, 以及小于1的值。
  6. 根据gbm分类器的准确性, 它将创建3种不同的折痕, 并选择最佳的learning_rate和n_estimators
from sklearn.model_selection import GridSearchCV

parameters = [{'n_estimators': [10, 100]}, {'learning_rate': [0.1, 0.01, 0.5]}]

grid_search = GridSearchCV(estimator = gbm, param_grid = parameters, scoring='accuracy', cv = 3, n_jobs=-1)

grid_search = grid_search.fit(train_X, train_y)

在训练集上拟合GridSearchCV()后, 它的准确率为97%, 学习率为0.5:
warnings.filterwarnings("ignore")grid_search.grid_scores_, grid_search.best_params_, grid_search.best_score_

([mean: 0.96764, std: 0.00000, params: {'n_estimators': 10}, mean: 0.96764, std: 0.00000, params: {'n_estimators': 100}, mean: 0.96764, std: 0.00000, params: {'learning_rate': 0.1}, mean: 0.96764, std: 0.00000, params: {'learning_rate': 0.01}, mean: 0.96765, std: 0.00006, params: {'learning_rate': 0.5}], {'learning_rate': 0.5}, 0.96764669532140457)

下面的代码将为你的模型提供最佳的估计。你应该多次使用不同的learning_rate和n_estimators值尝试GridSearchCV()。你将使用不同的超参数组合获得准确性得分的输出。然后, 你可以选择最佳组合。
grid_search.best_estimator_

XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1, colsample_bytree=1, gamma=0, learning_rate=0.5, max_delta_step=0, max_depth=3, max_features='sqrt', min_child_weight=1, missing=None, n_estimators=100, n_jobs=1, nthread=None, objective='binary:logistic', random_state=10, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None, silent=True, subsample=0.8)

现在, 你应该使用相同的估算器最终拟合模型, 因为这是模型的最佳估算器。
gbm=xgboost.XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1, colsample_bytree=1, gamma=0, learning_rate=0.5, max_delta_step=0, max_depth=3, max_features='sqrt', min_child_weight=1, missing=None, n_estimators=100, n_jobs=1, nthread=None, objective='binary:logistic', random_state=10, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None, silent=True, subsample=0.8).fit(train_X, train_y)

使用gbm.predict对测试集执行预测。
y_pred = gbm.predict(X_test_encode.as_matrix())

现在, 你可以打印混淆矩阵和分类报告。
print(confusion_matrix(y_test, y_pred))print(classification_report(y_test, y_pred))

[[845548118] [ 28057130]]precisionrecallf1-scoresupport00.971.000.9884566610.520.000.0128187avg / total0.950.970.95873853

该模型的总体精度为96.56%, 其中Certified的精度为97%, Dened的精度为56%。请注意, 这是一个高度不平衡的数据集, 少数类仅占总数的3%, 因此结果偏向于多数类CERTIFIED。因此, 要解决此问题, 可以使用许多技术, 例如欠采样或过采样。你可以尝试的一种技术是SMOTE –采样中的合成少数。
现在, 你可以查看AUC得分和ROC曲线进行预测。数据集高度不平衡, 在所有签证申请中只有3%被拒绝, 因此该模型高度偏向多数类(已认证)。 ROC图显示该曲线下有50%的面积。
from sklearn.metrics import roc_auc_scoreroc_auc_score(y_test, y_pred)

0.50223626010451605

from sklearn import metricsimport matplotlib.pyplot as pltfpr_xg, tpr_xg, thresholds = metrics.roc_curve(y_test, y_pred)print(metrics.auc(fpr_xg, tpr_xg))auc_xgb = np.trapz(tpr_xg, fpr_xg)plt.plot(fpr_xg, tpr_xg, label=" auc="+str(auc_xgb))plt.legend(loc=4)plt.show()

0.502236260105

预测H-1B签证申请的状态

文章图片
最后, 你可以将模型保存在磁盘上, 这样就不必下次再次运行它。这是使用Python中的Pickle模块完成的。
import pickle"""Saving the Model"""XGB_Model_h1b = 'XGB_Model_h1b.sav'pickle.dump(gbm, open(XGB_Model_h1b, 'wb'))

总结
制作模型时最重要的是特征工程和选择过程。你应该能够从功能中提取最大的信息, 以使模型更健壮和准确。功能选择和提取取决于时间和经验。可能有几种方法来处理数据集中的可用信息。
有很多不同的方法可以使你的模型学习。学习算法应该给你最好的结果。你可能可以使用不同的学习算法, 然后将它们集成在一起以使你的模型更健壮。在生产过程中也可以进行A / B测试, 这样你就可以知道哪种模型的性能要好得多。继续, 点击代码并尝试其他方法。快乐的编码。

    推荐阅读