Het doel van deze tutorial is je te laten zien hoe je gegevens over H1B-visa kunt verzamelen via webscraping met R. Vervolgens leer je ook hoe je de JSON-objecten parseert en hoe je de data kunt opslaan en bewerken, zodat je een basis verkennende data-analyse (EDA) kunt doen op de grote dataset met H1B-aanvragen.
Misschien leer je wel hoe je jezelf het best positioneert als kandidaat, of ontdek je nieuwe R-code!
Introductie
Vorige week presenteerde DataCamp's blog "Can Data Help Your H-1B Visa Application" enkele resultaten van een analyse van H-1B-data door de jaren heen. Nu is het tijd om zelf aan de slag te gaan met de data en te ontdekken wat je nog meer kunt vinden! Ted Kwartler gidst je hier doorheen met een serie R-tutorials.
Ik heb een vriend bij een advocatenkantoor in Texas dat H1B-visa indient. De H1B is een niet-immigrantenvisum in de Verenigde Staten waarmee Amerikaanse werkgevers tijdelijk buitenlandse werknemers in gespecialiseerde beroepen kunnen inhuren. Blijkbaar is geaccepteerd worden extreem moeilijk omdat er een beperkte hoeveelheid visa is tegenover duizenden aanvragers. Hoewel dat anekdotisch is, besloot ik de data zelf te verkennen in de hoop gekwalificeerde kandidaten te helpen weten dat de VS een gastvrije plek is!
Je data verzamelen: webscraping en parseren
Een DataCamp-collega wees me op deze site, een eenvoudige website met H1B-data van 2012 tot 2016. De site zegt 2 miljoen H1B-aanvragen te hebben, georganiseerd in één tabel.Ik besloot deze data programmatisch te verzamelen (lees: scrapen), want ik was niet van plan de rest van m’n leven te kopiëren en plakken! Zoals je ziet, toont de afbeelding hieronder een deel van de site met H1B-data van Boston:
De libraries die in deze tutorial gebruikt worden zijn onder andere jsonlite voor het parsen van JSON-objecten, rvest dat HTML “oogst”, pbapply, mijn persoonlijke favoriet omdat het voortgangsbalken toevoegt aan de basis-apply-functies, en data.table, dat de prestaties van R op grote dataframes verbetert.
library(jsonlite)library(rvest)library(pbapply)library(data.table)Mogelijk gemaakt door
De paginastructuur verkennen
Als je de site verkent, merk je dat het zoekformulier suggesties voor invullen geeft. Als je bijvoorbeeld een “B” in het stadsveld typt, verschijnt er een modaal met suggesties, zoals hieronder te zien is. De afbeelding hieronder toont de invulsuggesties wanneer ik “B” typ:
Dat betekent dat je de invulsuggesties kunt gebruiken als efficiënte manier om de site te bevragen. Met Chrome kun je herladen en dan rechtsklikken om de pagina te “Inspecteren”, vervolgens naar “Network” in het ontwikkelaarsvenster gaan en tot slot “B” op de pagina typen om het modaal te laden. Als je de links in het netwerkpaneel verkent, vind je een PHP-query die een JSON-object met steden teruggeeft, zoals deze. Het doel is eerst alle voorgestelde steden te verzamelen en vervolgens die lijst te gebruiken om een groot aantal pagina’s met H1B-data te scrapen. Als je de vorige URL bekijkt, zie je dat die eindigt op een letter. Je kunt dus paste0() gebruiken met de URL-basis, http://h1bdata.info/cities.php?term=, en letters. De basis wordt hergebruikt voor elke waarde in letters. Het object letters is een ingebouwde R-vector van “a” tot en met “z”. Het object json.cities is een vector met URL’s, van a tot z, die alle invulsuggesties als JSON bevatten.
json.cities<-paste0('http://h1bdata.info/cities.php?term=', letters)Mogelijk gemaakt door
JSON-objecten parsenHet json.cities-object is een vector van 26 links die door R moeten worden ingelezen. Met lapply() of pblapply() samen met fromJSON zal R elk van de JSON-objecten parsen om all.cities te maken. Je nestelt het resultaat in unlist zodat de output een eenvoudige stringvector is. Met deze code heb je alle invulsteden georganiseerd in een vector die je kunt gebruiken om de daadwerkelijke webpagina’s met data te construeren.
Om de laadtijd per individuele pagina te verlagen, kun je besluiten om twee parameters, city en year, mee te geven aan elke webpaginaquery. Bijvoorbeeld Boston H1B-data in 2012, dan Boston 2013 enzovoort. Een uitstekende functie om factoreen combinaties te maken is expand.grid(). In de code hieronder zie je dat de stadsinformatie, all.cities, en daarna het jaar met seq() van 2012 tot 2016 worden doorgegeven. De functie creëert meer dan 5000 combinaties van stad en jaar. expand.grid() maakt programmatisch Boston 2012, Boston 2013, Boston 2014, enz., omdat elke stad en elk jaar een unieke factoreen combinatie vormen.
Sommige steden, zoals Los Angeles, bestaan uit twee woorden en moeten voor URL’s worden gecodeerd. De functie url_encode() verandert “Los Angeles” in Los%20Angeles om het adres te valideren. Je geeft de hele vector door en url_encode() werkt rij voor rij:
city.year$city<-urltools::url_encode(as.character(city.year$city))Mogelijk gemaakt door
Tot slot gebruik je opnieuw de functie paste0() om de basis-URL te concateneren met de combinaties van stad en staat in city.year. Bekijk een voorbeeldlink hier.
all.urls<-paste0('http://h1bdata.info/index.php?em=&job=&city=', city.year[,1],'&year=', city.year[,2])Mogelijk gemaakt door
Informatie van pagina’s extraheren
Als je de vorige stappen hebt doorlopen, kun je een aangepaste functie main maken om de data van elke pagina te verzamelen. Het is een eenvoudige workflow met functies uit rvest. Eerst wordt een URL geaccepteerd en read_html() parseert de paginainhoud. Vervolgens wordt de enige html_table van de pagina geselecteerd uit alle andere HTML-informatie. De functie main zet het object x om naar een data.table zodat het efficiënt in het geheugen kan worden opgeslagen. Tot slot kun je, voordat main afsluit, een Sys.sleep toevoegen zodat je niet wordt gezien als een DDOS-aanval.
main<-function(url.x){
x<-read_html(url.x)
x<-html_table(x)
x<-data.table(x[[1]])return(x)
Sys.sleep(5)}Mogelijk gemaakt door
Op naar die data! Ik gebruik graag de voortgangsbalk van pblapply() zodat ik de scrapingvoortgang kan bijhouden. Je geeft eenvoudig all.urls en de main-functie door aan de functie pblapply(). R gaat meteen aan de slag met het laden van een pagina, het verzamelen van de tabel en het vasthouden van een data.table in het geheugen voor die pagina. Elke URL wordt om de beurt opgehaald en in het geheugen bewaard.
Poeh! Dat kostte uren! Op dit punt is all.h1b een lijst met data.tables, één per pagina. Om de lijst te verenigen in één enkele data.table, kun je rbindlist gebruiken. Dit lijkt op do.call(rbind, all.h1b) maar is veel sneller.
all.h1b<-rbindlist(all.h1b)
Sla de data tenslotte op zodat je dit niet opnieuw hoeft te doen. Gelukkig voor jou heb ik hier een kopie opgeslagen.
write.csv(all.h1b,'h1b_data.csv', row.names=F)
Je data opschonen
Ook al heb je de data gescrapet, er zijn nog extra stappen nodig om het in een hanteerbaar formaat te krijgen.
Je gebruikt lubridate om data te helpen organiseren. Je maakt ook gebruik van stringr, dat wrappers biedt voor stringmanipulatie.
Het blijkt dat de webscrape 1,8 miljoen van de 2 miljoen H1B-records heeft vastgelegd. Naar mijn mening is 1,8 miljoen goed genoeg. Laten we de data dus laden met fread(): deze functie lijkt op read.csv maar is de efficiëntere “fast & friendly file finagler”.
De kolomnamen van de gescrapete data zijn in hoofdletters en bevatten spaties.
Daardoor is ernaar verwijzen op naam onhandig, dus het eerste wat je wilt doen is ze hernoemen.
Voor het hernoemen van kolomnamen heb je functies nodig aan beide kanten van de toekenningsoperator (<-). Aan de linkerkant gebruik je colnames() en geef je het dataframe door. Aan de rechterkant van de operator kun je een vector met strings doorgeven.
In dit voorbeeld neem je eerst de oorspronkelijke namen en maak je ze met tolower() lowercase. In de tweede regel pas je gsub() toe, een globale substitutiefunctie.
Wanneer gsub() een patroon herkent, in dit geval een spatie, vervangt het alle instanties door de tweede parameter, de underscore. Ten slotte moet je gsub() vertellen dat de vervangingen moeten plaatsvinden in names(h1b.data), de nu lowercase kolommen van het dataframe.
colnames(h1b.data)<-tolower(names(h1b.data))colnames(h1b.data)<-gsub(' ','_',names(h1b.data))Mogelijk gemaakt door
Een van de eerste functies die ik gebruik bij het verkennen van data is de functie tail(). Deze functie geeft de onderste rijen terug. Hier zal tail() de laatste 8 rijen teruggeven.
Dit helpt je snel te zien hoe de datastructuur en vectoren eruitzien.
Vervolgens controleer ik altijd de klasse van de vectoren. Bij webgescrapete data kunnen numerieke waarden of factoren tekst worden. Je zult zien dat het nu corrigeren van klassen latere frustratie kan voorkomen!
Met de functie apply() kun je h1b.data doorgeven, dan 2 en de functie class. Omdat je 2 hebt geselecteerd, controleert R de klasse van elke kolom en geeft die terug in je console. Je kunt apply() met 1 gebruiken om een functie rijgewijs toe te passen, maar dat helpt hier niet.
Alle kolommen zijn “characters” en moeten worden gecorrigeerd. Ik laat je zien hoe je een van de datumkolommen wijzigt en laat de rest aan jou. Met tail() kun je de laatste 6 rijen van de verkeerd geclassificeerde datums bekijken.
Om de datums te corrigeren, moeten de /-schuine strepen worden vervangen door -. Gebruik opnieuw gsub() om te zoeken naar / en deze te vervangen door -.
tail(h1b.data$submit_date)
h1b.data$submit_date<-gsub('/','-', h1b.data$submit_date)Mogelijk gemaakt door
Met de streepjes op hun plaats pas je mdy() toe, wat staat voor "month, day, year". Dit komt omdat de datums in die volgorde zijn opgegeven. Als de volgorde anders was, zou je de mdy-letters dienovereenkomstig herschikken.
Om te controleren of de kolom correct is gewijzigd, bekijk je opnieuw de tail en controleer je de klasse. De tail() zou datums moeten printen die lijken op “2016-03-11 UTC” en de klasse van de vector zou “POSIXct” in plaats van “character” moeten zijn.
h1b.data$submit_date<-mdy(h1b.data$submit_date)tail(h1b.data$submit_date)class(h1b.data$submit_date)Mogelijk gemaakt door
Voor dit type analyse is het een goed idee om alleen de maand en het jaar uit de datums te halen in nieuwe kolommen. In de code hieronder zie je dat twee nieuwe kolommen $submit_month en $submit_yr worden gedeclareerd.
Binnen lubridate kan de functie month() op een hele kolom worden toegepast om de maandwaarden uit een datum te extraheren. De functie year() accepteert op vergelijkbare wijze de datumkolom om h1b.data$submit_yr te maken. Als je de functie head() gebruikt, zou je nu twee nieuwe kolommen moeten zien.
h1b.data$submit_month<-month(h1b.data$submit_date, label=T)
h1b.data$submit_yr<-year(h1b.data$submit_date)head(h1b.data)Mogelijk gemaakt door
Bekijk vervolgens de kolom $base_salary. Daarin staat een komma op de duizendtallenplaats en R ziet dit als een character, dus dat moet worden aangepast. Opnieuw schiet gsub() te hulp om de komma te verwijderen en te vervangen door een leeg teken. Vervolgens wordt as.numeric() toegepast op h1b.data$base_salary om de waarden officieel naar nummers om te zetten.
Met head() op de derde regel kun je een deel van de nieuwe vector bekijken.
h1b.data$base_salary<-gsub(',','',h1b.data$base_salary)
h1b.data$base_salary<-as.numeric(h1b.data$base_salary)head(h1b.data$base_salary)Mogelijk gemaakt door
Een andere manier om deze data te snijden is per staat. Als je de kolom h1b.data$location bekijkt, zie je dat de stad en staat gescheiden zijn door een komma. De onderstaande code gebruikt str_split_fixed() om de locatie-informatie op de eerste komma te splitsen. Geef eenvoudig de kolom, het scheidingsteken en het aantal terug te geven kolommen door. Het resulterende state-object is een grote matrix met hetzelfde aantal rijen als h1b.data en 2 kolommen.
De volgende twee regels code binden de afzonderlijke staatvectoren als $city en $state aan h1b.data. De vectoren zijn niet perfect, omdat spellingen kunnen verschillen, zoals “Winston Salem” versus “Winston-Salem”. Over het geheel genomen is deze methode goed genoeg voor eenvoudige EDA, maar houd er rekening mee dat in andere analyses enige termenaggregatie nodig kan zijn.
Als je een H1B-visum zou aanvragen, wil je weten in welke staten de meeste kansen liggen om je kans op acceptatie te vergroten. De functie table() wordt gebruikt om categorische variabelen te tellen en is eenvoudig toe te passen op h1b.data$state. In de tweede regel kun je een klein dataframe maken om de namen van de staten en de getelde H1B-data vast te leggen.
state.tally<-table(h1b.data$state)
state.tally<-data.frame(state=names(state.tally), h1b=as.vector(state.tally))Mogelijk gemaakt door
Met state.tally en barplot() maak je een basis staafdiagram van H1B-waarden per staat. De tweede parameter names.arg geeft de staaflabels aan en las=3 vertelt R de labels verticaal te plaatsen. Je ziet wat slordige locaties door de kommagesplitste data, maar de boodschap is duidelijk… een H1B-aanvrager zal waarschijnlijk in CA, NJ, NY of TX terechtkomen.
barplot(state.tally$h1b,
names.arg =names(table(h1b.data$state)),
las=3)Mogelijk gemaakt door
Je ziet de telling van H1B-visa per staat van 2012 tot 2016.
Laten we vervolgens proberen het verband te begrijpen tussen H1B-visa en een extern feit. Voor de eenvoud heeft R een ingebouwde dataset genaamd state.x77. Dit is een matrix met 50 rijen, 1 per staat, en feiten zoals bevolking en levensverwachting in de US Census van 1977.
Tip: gebruik in je eigen analyse een recentere gegevensbron.
Voor nu is state.x77 een goed voorbeeld om te leren. Bekijk deze ingebouwde dataset met head().
Laten we deze informatie samenvoegen met de state.tally-data in een groter dataframe om relaties te begrijpen. Maak daarvoor een dataframe state.data met staatafkortingen, state.abb, en de oude Censusdata van 1977. Roep daarna merge aan met state.tally en state.data.
Je kunt expliciet de kolom state aangeven als de vector om op te joinen. Bekijk een deel van het dataframe in de derde regel door de 15e tot en met 20e rij te indexeren.
state.data<-data.frame(state=state.abb,state.x77)
state.data<-merge(state.tally,
state.data,
by='state')
state.data[15:20,]Mogelijk gemaakt door
Een basis EDA-functie is cor: deze print de correlatie tussen twee variabelen.
Onthoud dat correlatie varieert van -1 tot 1: 0 betekent dat de variabelen geen correlatie hebben en waarschijnlijk niet gerelateerd zijn. Een getal dat 1 nadert betekent dat de waarden positief gecorreleerd zijn (hopelijk) zoals R-programmeren en inkomen. Een negatief getal betekent dat de relatie in tegenovergestelde richting beweegt, zoals R-programmeren en een sociaal leven!
Deze code past cor toe op de bevolkingsgrootte van 1977 en de huidige H1B-tellingen. Onthoud dat de code bedoeld is om te illustreren hoe je de analyse uitvoert ondanks de temporele mismatch. Je kunt $Population wijzigen om naar een andere vector in het dataframe te verwijzen.
Een andere manier om variablerelaties te onderzoeken is met een scatterplot, in het bijzonder een scatterplotmatrix. Gebruik pairs() om snel een scatterplotmatrix te tekenen. De code hieronder gebruikt een formule om de relaties te definiëren. Elke kolom wordt afzonderlijk gedeclareerd met een plusteken ertussen. De parameter data accepteert het dataframe en main geeft simpelweg de plottitel aan.
pairs(~ h1b + Population + Income,
data = state.data,
main='h1b relationships')Mogelijk gemaakt door
Je ziet dat deze scatterplotmatrix H1B-tellingen visualiseert ten opzichte van Population en Income per staat.
Je kunt een relatie tussen Population en h1b waarnemen. Dat is intuïtief logisch, omdat dichter bevolkte staten meer baanmogelijkheden hebben die een H1B-visum vereisen.
Om in te zoomen op een enkele plot uit de matrix, roep je simpelweg plot() aan en geef je de twee variabelen door.
We zijn nog maar net begonnen met het verkennen van H1B-visa! Deze dataset is erg rijk en in de volgende post ga je het salarisdeel verkennen, uitschieters verwijderen en meer overtuigende ggplot2-visuals maken.
Je bouwt ook voort op deze EDA-concepten door de H1B-status in de tijd te verkennen en ook topwerkgevers. Een van de coole visuals die ik je alvast laat zien is een boxplot die de salarisverdelingen per H1B-visumstatus toont met deze code:
ggplot(h1b.data)+geom_boxplot(aes(factor(case_status),base_salary,fill=as.factor(case_status)))+ylim(0,100000)+theme_gdocs()+scale_fill_gdocs()+theme(axis.text.x=element_blank())Mogelijk gemaakt door
Gebruik je vaardigheden in het bewerken en visualiseren van gegevens om de stemgeschiedenis van de Algemene Vergadering van de Verenigde Naties te bekijken.
Het doel van deze tutorial is je te laten zien hoe je gegevens over H1B-visa kunt verzamelen via webscraping met R. Vervolgens leer je ook hoe je de JSON-objecten parseert en hoe je de data kunt opslaan en bewerken, zodat je een basis verkennende data-analyse (EDA) kunt doen op de grote dataset met H1B-aanvragen.
Misschien leer je wel hoe je jezelf het best positioneert als kandidaat, of ontdek je nieuwe R-code!
Introductie
Vorige week presenteerde DataCamp's blog "Can Data Help Your H-1B Visa Application" enkele resultaten van een analyse van H-1B-data door de jaren heen. Nu is het tijd om zelf aan de slag te gaan met de data en te ontdekken wat je nog meer kunt vinden! Ted Kwartler gidst je hier doorheen met een serie R-tutorials.
Ik heb een vriend bij een advocatenkantoor in Texas dat H1B-visa indient. De H1B is een niet-immigrantenvisum in de Verenigde Staten waarmee Amerikaanse werkgevers tijdelijk buitenlandse werknemers in gespecialiseerde beroepen kunnen inhuren. Blijkbaar is geaccepteerd worden extreem moeilijk omdat er een beperkte hoeveelheid visa is tegenover duizenden aanvragers. Hoewel dat anekdotisch is, besloot ik de data zelf te verkennen in de hoop gekwalificeerde kandidaten te helpen weten dat de VS een gastvrije plek is!
Je data verzamelen: webscraping en parseren
Een DataCamp-collega wees me op deze site, een eenvoudige website met H1B-data van 2012 tot 2016. De site zegt 2 miljoen H1B-aanvragen te hebben, georganiseerd in één tabel.Ik besloot deze data programmatisch te verzamelen (lees: scrapen), want ik was niet van plan de rest van m’n leven te kopiëren en plakken! Zoals je ziet, toont de afbeelding hieronder een deel van de site met H1B-data van Boston:
De libraries die in deze tutorial gebruikt worden zijn onder andere
jsonlitevoor het parsen van JSON-objecten,rvestdat HTML “oogst”,pbapply, mijn persoonlijke favoriet omdat het voortgangsbalken toevoegt aan de basis-apply-functies, endata.table, dat de prestaties van R op grote dataframes verbetert.De paginastructuur verkennen
Als je de site verkent, merk je dat het zoekformulier suggesties voor invullen geeft. Als je bijvoorbeeld een “B” in het stadsveld typt, verschijnt er een modaal met suggesties, zoals hieronder te zien is. De afbeelding hieronder toont de invulsuggesties wanneer ik “B” typ:
Dat betekent dat je de invulsuggesties kunt gebruiken als efficiënte manier om de site te bevragen. Met Chrome kun je herladen en dan rechtsklikken om de pagina te “Inspecteren”, vervolgens naar “Network” in het ontwikkelaarsvenster gaan en tot slot “B” op de pagina typen om het modaal te laden. Als je de links in het netwerkpaneel verkent, vind je een PHP-query die een JSON-object met steden teruggeeft, zoals deze. Het doel is eerst alle voorgestelde steden te verzamelen en vervolgens die lijst te gebruiken om een groot aantal pagina’s met H1B-data te scrapen. Als je de vorige URL bekijkt, zie je dat die eindigt op een letter. Je kunt dus
paste0()gebruiken met de URL-basis,http://h1bdata.info/cities.php?term=, enletters. De basis wordt hergebruikt voor elke waarde inletters. Het objectlettersis een ingebouwde R-vector van “a” tot en met “z”. Het objectjson.citiesis een vector met URL’s, van a tot z, die alle invulsuggesties als JSON bevatten.json.cities-object is een vector van 26 links die door R moeten worden ingelezen. Metlapply()ofpblapply()samen metfromJSONzal R elk van de JSON-objecten parsen omall.citieste maken. Je nestelt het resultaat inunlistzodat de output een eenvoudige stringvector is. Met deze code heb je alle invulsteden georganiseerd in een vector die je kunt gebruiken om de daadwerkelijke webpagina’s met data te construeren.expand.grid(). In de code hieronder zie je dat de stadsinformatie,all.cities, en daarna het jaar metseq()van 2012 tot 2016 worden doorgegeven. De functie creëert meer dan 5000 combinaties van stad en jaar.expand.grid()maakt programmatisch Boston 2012, Boston 2013, Boston 2014, enz., omdat elke stad en elk jaar een unieke factoreen combinatie vormen. Sommige steden, zoals Los Angeles, bestaan uit twee woorden en moeten voor URL’s worden gecodeerd. De functieurl_encode()verandert “Los Angeles” in Los%20Angeles om het adres te valideren. Je geeft de hele vector door enurl_encode()werkt rij voor rij: Tot slot gebruik je opnieuw de functiepaste0()om de basis-URL te concateneren met de combinaties van stad en staat incity.year. Bekijk een voorbeeldlink hier.Informatie van pagina’s extraheren
Als je de vorige stappen hebt doorlopen, kun je een aangepaste functie
mainmaken om de data van elke pagina te verzamelen. Het is een eenvoudige workflow met functies uitrvest. Eerst wordt een URL geaccepteerd enread_html()parseert de paginainhoud. Vervolgens wordt de enigehtml_tablevan de pagina geselecteerd uit alle andere HTML-informatie. De functiemainzet het objectxom naar eendata.tablezodat het efficiënt in het geheugen kan worden opgeslagen. Tot slot kun je, voordatmainafsluit, eenSys.sleeptoevoegen zodat je niet wordt gezien als een DDOS-aanval.Op naar die data! Ik gebruik graag de voortgangsbalk van
pblapply()zodat ik de scrapingvoortgang kan bijhouden.Je geeft eenvoudig
all.urlsen de main-functie door aan de functiepblapply(). R gaat meteen aan de slag met het laden van een pagina, het verzamelen van de tabel en het vasthouden van een data.table in het geheugen voor die pagina. Elke URL wordt om de beurt opgehaald en in het geheugen bewaard.De data combineren in één data.table
Poeh! Dat kostte uren! Op dit punt is
all.h1been lijst met data.tables, één per pagina. Om de lijst te verenigen in één enkele data.table, kun jerbindlistgebruiken. Dit lijkt opdo.call(rbind, all.h1b)maar is veel sneller.all.h1b<-rbindlist(all.h1b)Sla de data tenslotte op zodat je dit niet opnieuw hoeft te doen. Gelukkig voor jou heb ik hier een kopie opgeslagen.
write.csv(all.h1b,'h1b_data.csv', row.names=F)Je data opschonen
Ook al heb je de data gescrapet, er zijn nog extra stappen nodig om het in een hanteerbaar formaat te krijgen.
Je gebruikt
lubridateom data te helpen organiseren. Je maakt ook gebruik vanstringr, dat wrappers biedt voor stringmanipulatie.Hoewel het een persoonlijke voorkeur is, gebruik ik graag
scipen=999. Het is niet verplicht, maar het haalt wetenschappelijke notatie weg.Het blijkt dat de webscrape 1,8 miljoen van de 2 miljoen H1B-records heeft vastgelegd. Naar mijn mening is 1,8 miljoen goed genoeg. Laten we de data dus laden met
fread(): deze functie lijkt opread.csvmaar is de efficiëntere “fast & friendly file finagler”.De kolomnamen van de gescrapete data zijn in hoofdletters en bevatten spaties.
Daardoor is ernaar verwijzen op naam onhandig, dus het eerste wat je wilt doen is ze hernoemen.
Voor het hernoemen van kolomnamen heb je functies nodig aan beide kanten van de toekenningsoperator (
<-). Aan de linkerkant gebruik jecolnames()en geef je het dataframe door. Aan de rechterkant van de operator kun je een vector met strings doorgeven.In dit voorbeeld neem je eerst de oorspronkelijke namen en maak je ze met
tolower()lowercase. In de tweede regel pas jegsub()toe, een globale substitutiefunctie.Wanneer
gsub()een patroon herkent, in dit geval een spatie, vervangt het alle instanties door de tweede parameter, de underscore. Ten slotte moet jegsub()vertellen dat de vervangingen moeten plaatsvinden innames(h1b.data), de nu lowercase kolommen van het dataframe.Een van de eerste functies die ik gebruik bij het verkennen van data is de functie
tail(). Deze functie geeft de onderste rijen terug. Hier zaltail()de laatste 8 rijen teruggeven.Dit helpt je snel te zien hoe de datastructuur en vectoren eruitzien.
Vervolgens controleer ik altijd de klasse van de vectoren. Bij webgescrapete data kunnen numerieke waarden of factoren tekst worden. Je zult zien dat het nu corrigeren van klassen latere frustratie kan voorkomen!
Met de functie
apply()kun jeh1b.datadoorgeven, dan2en de functie class. Omdat je2hebt geselecteerd, controleert R de klasse van elke kolom en geeft die terug in je console. Je kuntapply()met 1 gebruiken om een functie rijgewijs toe te passen, maar dat helpt hier niet.O jee!
Alle kolommen zijn “characters” en moeten worden gecorrigeerd. Ik laat je zien hoe je een van de datumkolommen wijzigt en laat de rest aan jou. Met
tail()kun je de laatste 6 rijen van de verkeerd geclassificeerde datums bekijken.Om de datums te corrigeren, moeten de
/-schuine strepen worden vervangen door-. Gebruik opnieuwgsub()om te zoeken naar/en deze te vervangen door-.Met de streepjes op hun plaats pas je
mdy()toe, wat staat voor "month, day, year". Dit komt omdat de datums in die volgorde zijn opgegeven. Als de volgorde anders was, zou je demdy-letters dienovereenkomstig herschikken.Om te controleren of de kolom correct is gewijzigd, bekijk je opnieuw de tail en controleer je de klasse. De
tail()zou datums moeten printen die lijken op “2016-03-11 UTC” en de klasse van de vector zou “POSIXct” in plaats van “character” moeten zijn.Voor dit type analyse is het een goed idee om alleen de maand en het jaar uit de datums te halen in nieuwe kolommen. In de code hieronder zie je dat twee nieuwe kolommen
$submit_monthen$submit_yrworden gedeclareerd.Binnen
lubridatekan de functiemonth()op een hele kolom worden toegepast om de maandwaarden uit een datum te extraheren. De functieyear()accepteert op vergelijkbare wijze de datumkolom omh1b.data$submit_yrte maken. Als je de functiehead()gebruikt, zou je nu twee nieuwe kolommen moeten zien.Bekijk vervolgens de kolom
$base_salary. Daarin staat een komma op de duizendtallenplaats en R ziet dit als een character, dus dat moet worden aangepast. Opnieuw schietgsub()te hulp om de komma te verwijderen en te vervangen door een leeg teken. Vervolgens wordtas.numeric()toegepast oph1b.data$base_salaryom de waarden officieel naar nummers om te zetten.Met
head()op de derde regel kun je een deel van de nieuwe vector bekijken.Een andere manier om deze data te snijden is per staat. Als je de kolom
h1b.data$locationbekijkt, zie je dat de stad en staat gescheiden zijn door een komma. De onderstaande code gebruiktstr_split_fixed()om de locatie-informatie op de eerste komma te splitsen. Geef eenvoudig de kolom, het scheidingsteken en het aantal terug te geven kolommen door. Het resulterende state-object is een grote matrix met hetzelfde aantal rijen alsh1b.dataen 2 kolommen.De volgende twee regels code binden de afzonderlijke staatvectoren als
$cityen$stateaanh1b.data. De vectoren zijn niet perfect, omdat spellingen kunnen verschillen, zoals “Winston Salem” versus “Winston-Salem”. Over het geheel genomen is deze methode goed genoeg voor eenvoudige EDA, maar houd er rekening mee dat in andere analyses enige termenaggregatie nodig kan zijn.Je data verkennen: eerste stappen
Als je een H1B-visum zou aanvragen, wil je weten in welke staten de meeste kansen liggen om je kans op acceptatie te vergroten. De functie
table()wordt gebruikt om categorische variabelen te tellen en is eenvoudig toe te passen oph1b.data$state. In de tweede regel kun je een klein dataframe maken om de namen van de staten en de getelde H1B-data vast te leggen.Met
state.tallyenbarplot()maak je een basis staafdiagram van H1B-waarden per staat. De tweede parameternames.arggeeft de staaflabels aan enlas=3vertelt R de labels verticaal te plaatsen. Je ziet wat slordige locaties door de kommagesplitste data, maar de boodschap is duidelijk… een H1B-aanvrager zal waarschijnlijk in CA, NJ, NY of TX terechtkomen.Je ziet de telling van H1B-visa per staat van 2012 tot 2016.
Laten we vervolgens proberen het verband te begrijpen tussen H1B-visa en een extern feit. Voor de eenvoud heeft R een ingebouwde dataset genaamd
state.x77. Dit is een matrix met 50 rijen, 1 per staat, en feiten zoals bevolking en levensverwachting in de US Census van 1977.Tip: gebruik in je eigen analyse een recentere gegevensbron.
Voor nu is
state.x77een goed voorbeeld om te leren. Bekijk deze ingebouwde dataset methead().Laten we deze informatie samenvoegen met de
state.tally-data in een groter dataframe om relaties te begrijpen. Maak daarvoor een dataframestate.datamet staatafkortingen, state.abb, en de oude Censusdata van 1977. Roep daarnamergeaan metstate.tallyenstate.data.Je kunt expliciet de kolom
stateaangeven als de vector om op te joinen. Bekijk een deel van het dataframe in de derde regel door de 15e tot en met 20e rij te indexeren.Een basis EDA-functie is
cor: deze print de correlatie tussen twee variabelen.Onthoud dat correlatie varieert van -1 tot 1: 0 betekent dat de variabelen geen correlatie hebben en waarschijnlijk niet gerelateerd zijn. Een getal dat 1 nadert betekent dat de waarden positief gecorreleerd zijn (hopelijk) zoals R-programmeren en inkomen. Een negatief getal betekent dat de relatie in tegenovergestelde richting beweegt, zoals R-programmeren en een sociaal leven!
Deze code past
cortoe op de bevolkingsgrootte van 1977 en de huidige H1B-tellingen. Onthoud dat de code bedoeld is om te illustreren hoe je de analyse uitvoert ondanks de temporele mismatch. Je kunt$Populationwijzigen om naar een andere vector in het dataframe te verwijzen.Een andere manier om variablerelaties te onderzoeken is met een scatterplot, in het bijzonder een scatterplotmatrix. Gebruik
pairs()om snel een scatterplotmatrix te tekenen. De code hieronder gebruikt een formule om de relaties te definiëren. Elke kolom wordt afzonderlijk gedeclareerd met een plusteken ertussen. De parameterdataaccepteert het dataframe en main geeft simpelweg de plottitel aan.Je ziet dat deze scatterplotmatrix H1B-tellingen visualiseert ten opzichte van
PopulationenIncomeper staat.Je kunt een relatie tussen
Populationenh1bwaarnemen. Dat is intuïtief logisch, omdat dichter bevolkte staten meer baanmogelijkheden hebben die een H1B-visum vereisen.Om in te zoomen op een enkele plot uit de matrix, roep je simpelweg
plot()aan en geef je de twee variabelen door.Volgende stappen met je H1B-visumdata
We zijn nog maar net begonnen met het verkennen van H1B-visa! Deze dataset is erg rijk en in de volgende post ga je het salarisdeel verkennen, uitschieters verwijderen en meer overtuigende
ggplot2-visuals maken.Je bouwt ook voort op deze EDA-concepten door de H1B-status in de tijd te verkennen en ook topwerkgevers. Een van de coole visuals die ik je alvast laat zien is een boxplot die de salarisverdelingen per H1B-visumstatus toont met deze code:
Blijf op de hoogte voor een volgend deel in de serie "Exploring H-1B Data with R"! Bekijk in de tussentijd gerust onze R data frame-tutorial, onze cursus Data importeren in R of onze cursus Data manipuleren in R met dplyr.