R中Web抓取和解析数据 | 研究H-1b数据(3)

本文概述

  • 获取数据
  • 使用必应地图进行地理编码
  • 映射H-1B软件开发人员信息
  • Software Developer H-1B应用程序位置
  • 年度聘用H-1B开发人员的顶级公司
  • 总结
srcmini的博客” 数据可以帮助你的H-1B签证申请” 向你介绍了多年来对H-1B数据的分析结果。现在, 是时候开始自己了! Ted Kwartler将通过一系列R教程指导你完成此过程。
我们回来了第三篇调查H-1B数据的文章。如果你想学习如何以编程方式收集和执行探索性数据分析(EDA), 请在此处查看第一篇文章。
在这最后一部分中, 你将学习如何通过API对纬度和经度坐标的位置进行地理编码。然后, 创建数据映射。接下来, 你将了解H-1B软件开发商的顶级雇主, 并按年比较他们的薪水。
我希望这些观点能帮助你了解你应该在哪里申请, 要谈判多少钱以及该国的地区, 这些地区为软件开发人员提供了大量的高薪。
我之所以选择软件开发人员, 是因为它们是我们数据集中使用最广泛的职位。另外, 我有一些需要赞助的朋友, 从技术上讲。希望这些代码和视觉效果可以帮助他们改善就业工作!
获取数据 你可以在此处查看原始的H-1B帖子, 以像我一样在网络上抓取数据。如果你没有耐心, 建议你前往我的github存储库以获取CSV文件。
首先要做的是使用正确的程序包设置R会话。 bit64软件包使data.table在64位整数的向量上有效工作。
由于data.table包非常有效, 因此可以再次使用它。接下来, 如果你想执行与数据相关的功能, 请使用lubridate。之后, pbapply在使用apply函数时会为你提供R会话进度条。 jsonlite包用于解析来自Bing Maps的地理编码API响应。最后, plyr是用于处理数据的出色软件包。
这两行设置了全局选项, 以首先摆脱科学计数法的影响, 也将打印的小数位增加到15。在使用经度和纬度时, 通常需要很多小数点。使用set.seed可以通过选择特定种子而不是随机种子来确保你的视觉效果类似于此帖子。
library(bit64)library(data.table)library(lubridate)library(pbapply)library(jsonlite)library(plyr)options(scipen=999, digits=15)set.seed(1234)

下一步是从存储库中读取CSV数据。 fread()函数是” 快速友好的文件整理器” , 可快速读取并提供进度更新。以我的经验, 这是导入大型数据帧的最佳方法。
接下来的代码行将ymd应用于与数据相关的向量。
如果你遵循以前的文章, 则不需要这样做, 但是使用fread()意味着你需要更正向量类型。
h1b.data< -fread('h1b_data_clean.csv')h1b.data$start_date< -ymd(h1b.data$start_date)h1b.data$submit_date< -ymd(h1b.data$submit_date)

现在你已经有了数据, 让我们确定最频繁的职位。若要创建h1b.jobs, 应将$ job_title向量更改为categorical。接下来, 使用table()汇总唯一的职位, 并将结果嵌套在as.data.frame()中, 以便可以轻松地对其进行操作。第三行通过新的$ Freq向量对新数据帧进行排序。由于order的默认行为是将值升序排列, 因此你可以使用tail()查看6个最常见的职位。
h1b.jobs< -as.factor(h1b.data$job_title)h1b.jobs< -as.data.frame(table(h1b.jobs))h1b.jobs< -h1b.jobs[order(h1b.jobs$Freq), ]tail(h1b.jobs)

通过查看h1b.jobs, 你可以选择自己感兴趣的工作。
在这里, 你可以通过串联” 软件开发人员” , “ 计算机程序” 和” 软件工程师” 来创建作业。
你是否注意到管道操作员如何在没有空格的情况下将它们分开? ” |” 在你的Enter键上方, 并表示” OR” 。因此, 你将通过” A OR B OR C” 将h1b.data子集化, 例如” A | B | C” 。
jobs< -c('SOFTWARE DEVELOPER|COMPUTER PROGRAMMER|SOFTWARE ENGINEER')

每当逻辑语句为TRUE时, subset()函数将保留一行数据。使用grepl()获取作业中的逻辑结果传递, 并在$ job_title中进行搜索。现在, h1b.devs具有?262K行, 而不是h1b.data的?1.8M行。
h1b.devs< -subset(h1b.data, grepl(jobs, h1b.data$job_title)==T)

使用必应地图进行地理编码 要创建地图, 你需要纬度/经度坐标。有多种服务来查找诸如Google Maps之类的位置。
但是, 我喜欢使用Bing Maps, 因为每天最多只能进行25, 000次查询。要使用此代码, 请在此处注册Bing Maps API密钥。你可以逐行查找所有位置。但是, 你将很快达到Bing限制, 必须等待完成。
相反, 我建议查找每个唯一的位置, 然后在以后加入信息以节省时间。
要在字符向量中查找唯一值, 请使用as.factor()更改$ location, 然后使用级别提取唯一级别。
在此数据集中, 具有262, 659行的Software Developer H-1B应用程序仅来自1, 763个唯一位置。
all.locs< -levels(as.factor(h1b.devs$location))

纽约等某些城镇的空间需要进行编码才能正常工作。 URLencode()函数将填充空格以显示” new%20york” 。在此代码中, URLencode()应用于唯一的位置向量all.locs, 结果未列出回到字符向量。
all.locs< -unlist(pblapply(all.locs, URLencode))

注册后, 将你的API密钥粘贴在引号之间以创建bing.key。使用paste0()创建位置URL。传入URL的基本部分, 然后传入all.locs向量, 传入更多URL信息, 最后传入你的API密钥字符串。当paste0()通过all.locs运行时, R将回收所有单独的地址部分。
bing.key< -'BING_MAPS_API_KEY'bing.urls< -paste0('http://dev.virtualearth.net/REST/v1/Locations?q=', all.locs, '& maxResults=1& key=', bing.key)

接下来, 你需要一个函数, 因此你不必为每个带有位置信息的URL编写代码。
bing.get()函数接受一个单独的URL。使用fromJSON收集响应。
然后, 两个ifelse语句标识各个纬度/经度值。在每个语句中, 如果API提供了响应, 则从响应中选择纬度和经度。如果API找不到位置, 则返回NA。这有助于克服没有纬度/经度值的API响应, 因此你的代码不会中断。
最后, 纬度/经度值被组织成一个小的数据框。
bing.get< -function(bing.url){bing.resp< -fromJSON(bing.url, simplifyDataFrame = T)ifelse(bing.resp$resourceSets$estimatedTotal > 0, lat< -bing.resp$resourceSets$resources[[1]]$point$coordinates[[1]][1], lat< -'NA')ifelse(bing.resp$resourceSets$estimatedTotal > 0, lon< -bing.resp$resourceSets$resources[[1]]$point$coordinates[[1]][2], lon< -'NA')lat.lon< -data.frame(lat=lat, lon=lon)return(lat.lon)}

要测试该功能, 请将其应用于第一个bing.urls。如果该代码有效, 则R控制台将在第一个位置打印纬度/经度。
bing.get(bing.urls[1])

既然你已经验证了该功能正常工作, 并且已经正确创建了URL, 则可以将其应用于整个bing.urls向量。使用进度条申请矢量, pblapply(), 传入Bing URL和bing.get函数。这将返回带有$ lat和$ lon列的1763个数据帧的列表。
组合数据帧的一种快速方法是使用rbindlist(), 它将按行绑定列表元素以创建一个经度/经度值的数据帧。
all.coords< -pblapply(bing.urls, bing.get)coords.df< -rbindlist(all.coords)

为了将原始的Software Developer H-1B签证申请数据加入到位置数据中, 你需要一个公共值。此代码使用与以前相同的代码添加$ location来提取唯一位置。然后$ lat和$ lon从字符更改为数值。可以使用head()检查最终数据帧。
coords.df$location< -levels(as.factor(h1b.devs$location))coords.df$lat< -as.numeric(as.character(coords.df$lat))coords.df$lon< -as.numeric(as.character(coords.df$lon))head(coords.df)

接下来, 你需要将经纬度值添加到h1b.data中。使用join会将coords.df视为查找表。每次在cords.df数据框中标识h1b.devs中的位置之一时, 就会添加附加的$ lat和$ lon值。要检查从API返回的NA数量, 请使用is.na()和sum()。
h1b.devs< - join(h1b.devs, coords.df, by='location')sum(is.na(h1b.devs$lat))

h1b.devs对象包含用于软件开发人员的所有H-1B Visa应用程序以及工作位置的经/纬度。
映射H-1B软件开发人员信息 现在, 在Software Developer H-1B数据具有适当的经度和纬度的情况下, 你可以构建地图。首先, 让我们创建一个仅包含唯一位置的静态地图。
下面的代码引用了1763个独特的经/纬对, 以演示软件开发人员的” 热点” 。例如, 旧金山和圣何塞是不同的位置, 但是使用经/纬度, 你可以看到位置如何在地图上聚类。
对于此代码, 添加ggplot2和ggthemes。这些是图形绘图库的流行语法:
library(ggplot2)library(ggthemes)

首先加载状态图信息。将map_data()与” state” 一起使用将创建一个包含坐标和绘图信息的数据框。这用作美国地图的基础层。
state.map < - map_data("state")

接下来创建一个基本的ggplot。多边形层将state.map数据和X, Y分别声明为long / lat。这部分代码是分开的, 以便你可以在下一部分中看到如何添加和更改图层。
ggplot() + geom_polygon(data = http://www.srcmini.com/state.map, aes(x=long, y=lat, group=group), colour ="grey", fill = NA)

R中Web抓取和解析数据 | 研究H-1b数据(3)

文章图片
这是基本的美国地图图层。
在这一层的顶部, 你将添加带有geom_point的点。在这一层中, 使用lon和lat声明coords.df对象。你可以将点更改为半透明, 并带有alpha和指定的颜色” 红色” 。接下来, 将情节限制为以美国为中心, 添加标题, 主题, 最后删除很多元素。
ggplot() + geom_polygon(data = http://www.srcmini.com/state.map, aes(x=long, y=lat, group=group), colour ="grey", fill = NA) + geom_point(data=http://www.srcmini.com/coords.df, aes(x=lon, y=lat), alpha=0.05, col="red")+xlim(-125, -65) + ylim(25, 50) + ggtitle("Certified H1B Visas") +theme_gdocs() +theme(panel.border = element_blank(), axis.text = element_blank(), line = element_blank(), axis.title = element_blank())

该图是显示H-1B位置簇的静态图像:
R中Web抓取和解析数据 | 研究H-1b数据(3)

文章图片
Software Developer H-1B应用程序位置 最好有一个动态地图, 以便你可以更自由地与数据进行交互。 JavaScript传单包具有R包, 用于创建基于HTML的交互式地图。将传单库与htmltools一起加载以开始使用。
library(leaflet)library(htmltools)

由于绘制点是使用javascript在客户端完成的, 因此可能很耗时。结果, 你可以对数据进行采样。可以在建立索引的同时对数据表进行采样, 方法是使用带有.N的行数和1000的样本量。接下来, 使用jitter()稍微调整每个纬度/经度值, 以防重复。
leaf.sample< -h1b.devs[sample(.N, 1000), ]leaf.sample$lat< -jitter(leaf.sample$lat)leaf.sample$lon< -jitter(leaf.sample$lon)

使用传单的一种简单方法是使用%> %运算符。
令人困惑的是, 这也称为管道!
这次, 管道运算符%> %迫使对象前进到下一个函数。这使代码简洁明了, 易于遵循。
在这里, leaf.sample数据帧被传递到leaflet()函数中。将对象转发到addTiles()中以获取地图图形, 然后再次将其转发到addMarkers()中。这可以用3行代码来完成, 但是只用%> %即可。
在addMarkers()函数中, 将添加一个弹出窗口, 以便你可以单击标记以查看雇主。
leaflet(leaf.sample)%> % addTiles() %> % addMarkers(popup = ~htmlEscape(employer))

带有标记弹出窗口的传单地图的屏幕截图:
R中Web抓取和解析数据 | 研究H-1b数据(3)

文章图片
要创建更有趣的地图, 你需要添加更多信息。通过H-1B应用程序$ start_yr对标记进行颜色编码。调用palette()将打印R中命名的8种不同颜色。你可以使用此向量对制造商进行颜色编码。使用应用于调色板信息和$ start_yr向量的colorNumeric()创建pal。
palette()pal< -colorNumeric(palette(), domain=h1b.data$start_yr)

像以前一样, 传入leaf.sample并开始管道向前。
addCircleMarkers()代替默认标记。在函数内, 半径由薪水除以$ 10K决定。
添加弹出信息的另一种方法是paste()。使用HTML换行符< br> 分隔元素可确保弹出窗口清晰易读。最后, 通过引用pal对象选择颜色。
leaflet(leaf.sample) %> % addTiles() %> %addCircleMarkers(radius = ~base_salary/10000, popup = paste('Employer:', leaf.sample$employer, '< br> ', 'Job Title:', leaf.sample$job_title, '< br> ', 'Salary:', leaf.sample$base_salary, '< br> ', 'Year:', leaf.sample$start_yr, '< br> ', 'Case Status', leaf.sample$case_status), color = ~pal(start_yr), stroke = F, fillOpacity = 0.5)

这次, 随着你的浏览, 地图变得更加有趣。颜色与年份有关, 标记的大小与薪水有关, 并且弹出窗口包含更多信息。
这是结果图的屏幕截图:
R中Web抓取和解析数据 | 研究H-1b数据(3)

文章图片
确保还检查了传单地图, 这些地图可视化了过去几年中排名前五的H-1B职位的认证签证。你可以在这里找到它。
年度聘用H-1B开发人员的顶级公司 你可能需要按时间探索按雇主划分的顶级软件开发人员薪水。让我们集中讨论使用子集的” CERTIFIED” 应用程序, 因为这些应用程序可以带来实际的美国就业机会。
dev.certs< -subset(h1b.devs, h1b.devs$case_status=='CERTIFIED')

使用聚合可按多个分组获取摘要统计信息。在此示例中, aggregate将$ base_salary按$ submit_yr和$ employer分成几组, 然后计算平均值, 并返回一个数据帧。
avg.salary< -aggregate(dev.certs$base_salary, by=list(dev.certs$submit_yr, dev.certs$employer), FUN=mean)

稍后, 将为每个雇主计算每年的工资汇总统计信息。
下一个重要的问题是寻找H-1B软件开发人员的顶级雇主。
由于你在使用$ job_title时使用它来创建h1b.jobs, 因此此代码现在应该看起来很熟悉。致电head()之后, 你应该了解排名前6位的开发者雇主。
top.emp< -as.data.frame(table(dev.certs$employer))top.emp< -top.emp[order(top.emp$Freq, decreasing=T), ]head(top.emp)

认识了最重要的雇主之后, 就可以使用grep返回avg.salary中与雇主名称匹配的行位置。可以在将平均薪水编入索引时仅使用该雇主。
goog< -avg.salary[grep('google', avg.salary$Group.2, ignore.case=T), ]msft< -avg.salary[grep('microsoft', avg.salary$Group.2, ignore.case=T), ]tata< -avg.salary[grep('TATA CONSULTANCY SERVICES LIMITED', avg.salary$Group.2, ignore.case=T), ]acc< -avg.salary[grep('accenture', avg.salary$Group.2, ignore.case=T), ]

查看数据表明Google的H-1B软件开发人员薪水稳定。微软的收入同比增长。两家技术巨头的薪酬都远远超过其他顶级H-1B软件开发商雇主Tata和Accenture。尽管塔塔咨询(Tata Consulting)的平均开发人员薪金在2016年有所上升。
| Year | Google| Microsoft | Tata Consulting | Accenture ||------|----------|-----------|-----------------|-----------|| 2012 | $129, 462 || $64, 707| $65, 800|| 2013 | $129, 399 | $112, 823| $65, 125| $66, 301|| 2014 | $127, 520 | $124, 508| $66, 417| $70, 997|| 2015 | $130, 450 | $125, 104| $68, 263| $73, 670|| 2016 | $133, 450 | $129, 304| $89, 438| $72, 680|

总结 希望你喜欢H-1B签证申请学习。在此过程中, 你学习了一些基本的EDA功能以及探索数据的方法, 包括时间, 位置, 频率和摘要统计信息。 H-1B数据非常丰富, 可能还有很多工作可以从数据集中提取见解。你可以随时探索不同的职业, 或深入研究特定的雇主或地区。
最后, 我希望这可以帮助你学习更多R, 并可能成功申请H-1B签证!
【R中Web抓取和解析数据 | 研究H-1b数据(3)】你是否有兴趣使用R做更多的EDA?考虑在R:案例研究课程中参加我们的探索性数据分析和探索性数据分析。

    推荐阅读