Calendrier de l'Avent Python 2019 Jour 25: christus_tree:.
Le même 25e jour du calendrier de l'avent Python 2018 de l'année dernière, j'ai écrit un article intitulé Statistiques apprises en Python et environnement d'analyse de données créé à la maison. Dans l'article, nous avons obtenu les données du revenu annuel le plus élevé présentées à partir du 15e projet de classement des utilisateurs de participation de Job Change Draft et effectué une analyse simple des données.
Cet article résume les résultats d'une analyse des données du marché des ingénieurs à l'aide des données du 22e projet de classement des utilisateurs participants.
C'est à peu près cette période de l'année, mais jetons un coup d'œil à l'état actuel du marché des ingénieurs vers 2020.
Le code que j'ai écrit l'année dernière n'a reçu que le montant le plus élevé, je l'ai donc modifié pour extraire toutes les données des données de classement des utilisateurs.
Tout d'abord, exécutez le programme suivant pour acquérir les données nécessaires à l'analyse des données (*). L'environnement de cet article est géré par Rasppie.
** (*) Lors du scraping, vérifiez les conditions d'utilisation du service cible et tenez compte de la charge côté service. ** **
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
#Importer les modules requis pour le scraping
import csv
import sys
sys.path.append('/home/pi/.local/lib/python3.5/site-packages/')
import time
import traceback
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
#Options d'utilisation de Headless Chrome
options = webdriver.chrome.options.Options()
options.add_argument('--headless')
#Paramètres du pilote
browser = webdriver.Chrome(executable_path="/usr/lib/chromium-browser/chromedriver", chrome_options=options)
#Informations de connexion
USER = “user”
PASS = “pass”
#Afficher l'écran de connexion
url_login = "https://job-draft.jp/sign_in"
browser.get(url_login)
time.sleep(1)
print("J'ai visité la page de connexion")
#Entrez votre adresse e-mail et votre mot de passe dans le formulaire
e = browser.find_element_by_id("user_email")
e.clear()
e.find_element_by_id("user_email").send_keys(USER)
e = browser.find_element_by_id("user_password")
e.clear()
e.find_element_by_id("user_password").send_keys(PASS)
time.sleep(1)
#Soumettre le formulaire
e.find_element_by_xpath("//*[@id=\"new_user\"]/div[4]").click()
print("Vous êtes maintenant connecté")
#une fonction
list = []
dict = {}
page = ""
last = 50
def get_user_data():
url = "https://job-draft.jp/festivals/22/users?page="
url = url+str(page)
browser.get(url)
count = 12
if page == 49:
count = 8
num = 2
while num < count:
try:
user = browser.find_elements_by_css_selector("#page-wrapper > div.wrapper-content > div > div > div.col-xs-12.col-sm-12.col-md-8.col-lg-8 > div.ibox > div > div > div:nth-child("+(str(num))+") > div > div.col-xs-3 > div:nth-child(2) > a > span")
age = browser.find_elements_by_css_selector("#page-wrapper > div.wrapper-content > div > div > div.col-xs-12.col-sm-12.col-md-8.col-lg-8 > div.ibox > div > div > div:nth-child("+(str(num))+") > div > div.col-xs-3 > div:nth-child(3) > span")
name = browser.find_elements_by_css_selector("#page-wrapper > div.wrapper-content > div > div > div.col-xs-12.col-sm-12.col-md-8.col-lg-8 > div.ibox > div > div > div:nth-child("+(str(num))+") > div > div.col-xs-9 > div.row > div.col-xs-4.col-sm-3.col-md-3.col-lg-3 > span.f-w-bold.u-font-ml")
max_amount = browser.find_elements_by_css_selector("#page-wrapper > div.wrapper-content > div > div > div.col-xs-12.col-sm-12.col-md-8.col-lg-8 > div.ibox > div > div > div:nth-child("+(str(num))+") > div > div.col-xs-9 > div.row > div:nth-child(2) > span.f-w-bold.u-font-ml")
cum_avg = browser.find_elements_by_css_selector("#page-wrapper > div.wrapper-content > div > div > div.col-xs-12.col-sm-12.col-md-8.col-lg-8 > div.ibox > div > div > div:nth-child("+(str(num))+") > div > div.col-xs-9 > div.row > div:nth-child(3) > span.f-w-bold.u-font-ml")
ambition = browser.find_elements_by_css_selector("#page-wrapper > div.wrapper-content > div > div > div.col-xs-12.col-sm-12.col-md-8.col-lg-8 > div.ibox > div > div > div:nth-child("+(str(num))+") > div > div.col-xs-9 > div.u-m-t-5 > div:nth-child(1) > span.f-w-bold.u-font-mm")
except NoSuchElementException:
print("Il n'y avait aucun élément")
sys.exit(1)
for user, age, name, max_amount, cum_avg, ambition in zip(user, age, name, max_amount, cum_avg, ambition):
user = user.text
age = age.text
name = name.text
max_amount = max_amount.text
max_amount = max_amount.replace('Dix mille yens', '')
cum_avg = cum_avg.text
cum_avg = cum_avg.replace('Dix mille yens', '')
ambition = ambition.text
print(user)
print(age)
print(name)
print(max_amount)
print(cum_avg)
print(ambition)
dict = {"user": user, "age": age, "name": name, "max_amount": max_amount, "cum_avg": cum_avg, "ambition": ambition }
list.append(dict)
with open('./user_ranking.csv', 'a') as f:
writer = csv.writer(f)
writer.writerow(dict.values())
num += 1
def main():
print("Commencer le scraping des données")
global page
global last
try:
if not page:
get_user_data()
page = 2
time.sleep(3)
#Boucle vers la dernière page
while page < last:
get_user_data()
page += 1
time.sleep(3)
except Exception as e:
traceback.print_exc()
sys.exit(99)
#Quittez le pilote et fermez toutes les fenêtres associées
browser.quit()
print("Récupération des données terminée avec succès")
#En traitement
if __name__ == '__main__':
main()
Lisez le fichier CSV obtenu en exécutant le programme ci-dessus à partir de Jupyter Notebook.
Si vous ne définissez pas d'argument dans pandas, la première ligne sera reconnue comme un en-tête.
Les données acquises n'ont pas d'en-tête. Si vous spécifiez header = None
, l'en-tête sera automatiquement ajouté par numéro, mais spécifiez l'en-tête pour une compréhension facile.
import numpy as np
import pandas as pd
#Lire le fichier csv
df = pd.read_csv("/tmp/user_ranking.csv", names=("âge", "Quantité maximale", "Nom d'utilisateur", "Nombre de nominations", "ambition", "Moyenne cumulative"))
Vérifiez le début du bloc de données pour vous assurer qu'il est chargé.
df.head()
Étant donné que les données récupérées sont enregistrées en tant que dict, les clés sont dans le désordre. C'est un peu difficile à voir, je vais donc réorganiser les touches pour en faire la même chose que le site Web.
#Trier
df = df.loc[:, ["Nom d'utilisateur","âge", "Nombre de nominations", "Quantité maximale", "Moyenne cumulative", "ambition"]]
Il a été réorganisé pour le rendre plus facile à voir. Vous êtes maintenant prêt.
L'idée de base des statistiques est la suivante.
Le 22e repêchage a réuni 486 personnes. Sur ce nombre, 320 ont été nominés et 166 non. Comme je l'ai écrit dans l'article de l'année dernière, la valeur moyenne changera selon que "sans rendez-vous" est inclus ou non.
Puisqu'il semble que le salaire annuel moyen indiqué dans les résultats des offres soit calculé par ceux qui excluent «sans rendez-vous», nous l'analyserons également sur la base des données excluant «sans rendez-vous» cette fois-ci également.
Supprimez les colonnes non numériques du bloc de données pour les statistiques.
#Nombre de candidatures autre que 0
df_nominated = df[df['Nombre de nominations'] != 0]
#Supprimer une valeur non numérique
df_nominated = df_nominated.drop(['âge', 'Nom d'utilisateur', 'ambition'], axis=1)
Assurez-vous qu'il ne s'agit que d'un nombre.
df_nominated.head()
Ensuite, vérifiez le type de données. Vous pouvez voir que le montant maximum et la moyenne cumulée sont ** objet **.
#Vérifier le type de données
df_nominated.dtypes
Étant donné que les statistiques ne peuvent pas être confirmées telles quelles, changez-les en type int. Passez au type int64 en fonction du type de données du nombre de nominations.
#Conversion de type de données
df_nominated.loc[:, "Quantité maximale"] = df_nominated.loc[:, "Quantité maximale"].astype(np.int64)
df_nominated.loc[:, "Moyenne cumulative"] = df_nominated.loc[:, "Moyenne cumulative"].astype(np.int64)
Maintenant que le type de données est int64, vérifiez les statistiques. Le montant maximal moyen est de ** 6,7 millions de yens ** et l'écart type est de ** 1,2 million de yens **. Le marché passe de ** 5,5 millions de yens à 7,9 millions de yens **.
#Afficher les statistiques
df_nominated.describe()
Ensuite, vérifions le coefficient de corrélation. Comme vous pouvez le constater, il existe une forte corrélation positive entre le montant maximum et la moyenne cumulée.
#Afficher le coefficient de corrélation
df_nominated.corr()
Vérifiez la relation des données de chaque colonne avec la matrice du diagramme de dispersion. La taille du graphique peut être modifiée avec «figsize». L'unité est en pouces.
#Afficher la matrice du diagramme de dispersion
%matplotlib inline
from pandas.plotting import scatter_matrix
_ = scatter_matrix(df_nominated, figsize=(8,6))
Comparons le montant maximum dans l'histogramme. Extrayez la quantité maximale de la trame de données.
#Trier par ordre croissant
df_aomount = df_nominated.sort_values(by="Quantité maximale")
#Extraire la plus grande quantité de la trame de données et l'ajouter à la liste
amount_list = []
for a in df_aomount["Quantité maximale"]:
amount_list.append(a)
Vous pouvez voir qu'il y en a beaucoup dans la fourchette de 6 millions de yens.
#Afficher sous forme d'histogramme
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plt.hist(amount_list, rwidth=10, bins=40)
plt.xlabel('Maximum amount')
plt.ylabel('Number of people')
plt.show()
Vérifiez l'histogramme séparément pour chaque groupe d'âge.
Préparez également les données de la trame de données.
import re
#Trier par ordre croissant
df_age = df.sort_values(by="Quantité maximale")
df_age = df_age[df_age['Nombre de nominations'] != 0]
s10_list = []
s20_list = []
s30_list = []
s40_list = []
s50_list = []
s60_list = []
#Extraire par âge de la base de données et ajouter à la liste
for age, amount in zip(df_age["âge"], df_age["Quantité maximale"]):
if type(amount) is str:
amount = np.int64(amount)
if re.match('10 ans', age):
s10_list.append(amount)
elif re.match('20 ans', age):
s20_list.append(amount)
elif re.match('30 s', age):
s30_list.append(amount)
elif re.match('Quarante', age):
s40_list.append(amount)
elif re.match('Années 50', age):
s50_list.append(amount)
elif re.match('Années 60', age):
s60_list.append(amount)
Afficher sous forme d'histogramme.
#Afficher sous forme d'histogramme (multiple)
fig, ax = plt.subplots(figsize=(10,8))
labels = ['10', '20', '30', '40', '50', '60']
ax.hist((s10_list, s20_list, s30_list, s40_list, s50_list, s60_list), label=labels)
plt.xlabel('Maximum amount')
plt.ylabel('Number of people')
ax.legend()
plt.show()
À l'origine, le nombre d'échantillons est faible, mais il n'y a pas de rendez-vous pour les personnes dans la cinquantaine et la soixantaine, et on voit que c'est dans la vingtaine et la trentaine que le marché augmente, même s'il se situe dans la fourchette attendue.
Vérifiez le diagramme des moustaches. Les moustaches de boîte sont parfaites lorsque vous souhaitez trouver des valeurs aberrantes.
#S'affiche sous forme de moustaches de boîte
fig, ax = plt.subplots(figsize=(10,8))
labels = ['10', '20', '30', '40', '50', '60']
ax.boxplot((s10_list, s20_list, s30_list, s40_list, s50_list, s60_list), labels=labels)
plt.xlabel('age')
plt.ylabel('Maximum amount')
plt.show()
Vous pouvez voir que la classe de 10 millions de yens est détectée comme une valeur aberrante. Est-il intéressant de voir le revenu annuel dans la trentaine? La différence de fourchette est la plus importante dans chaque groupe d'âge.
Les données nous indiquent que la différence de revenu annuel se creusera dans les années 30. Vous pouvez également voir que la ligne minimale pour les personnes dans la quarantaine est de 6 millions de yens.
wordcloud Extrayez les ambitions des données récupérées et affichez-les dans le nuage de mots pour les visualiser.
Pour utiliser WordCloud, exécutez la commande suivante pour créer l'environnement (*). Dans cet article, ** fonts-takao-mincho ** est utilisé pour la police japonaise.
(*) L'environnement de cet article est Razupai
$ pip3 install wordcloud
$ sudo apt-get install fonts-takao-mincho
Extrayez les ambitions du bloc de données et ajoutez-les à la liste.
#Extraire les ambitions des blocs de données et les ajouter à la liste
word_list = []
for w in df["ambition"]:
if type(w) is float:
w = str(w)
word_list.append(w)
Combinez les éléments de la liste en un objet mot.
#Stocker dans un objet Word
word = ''
for w in word_list:
word += w
word.replace(',', '')
Créez un nuage de mots. À ce stade, si vous souhaitez afficher en japonais, spécifiez le chemin de la police.
from wordcloud import STOPWORDS, WordCloud
#Création de nuage de mots
wordcloud = WordCloud(width=1200, height=900, background_color='white', colormap='winter', font_path='/usr/share/fonts/truetype/fonts-japanese-mincho.ttf')
wordcloud.generate(word)
wordcloud.to_file('wordcloud.png')
Affichez le nuage de mots créé.
#Affichage de l'image
from IPython.display import Image
Image("./wordcloud.png ")
Ce que j'ai vu en analysant les données du marché des ingénieurs
C'était une chose essentielle et universelle qui n'a jamais changé, ** apprendre des connaissances et devenir ingénieur **.
Nous améliorerons un peu le programme ci-dessus et analyserons d'autres données acquises.
Nous utiliserons les données de la liste cumulative des entreprises participantes comme classement pour déterminer quels types d'entreprises sont populaires. Préparez la trame de données selon la même procédure.
Les éléments suivants trient les ** nominations ** par ordre décroissant et affichent les dix premiers. Le nombre de nominations étant par ordre décroissant, vous pouvez voir que l'entreprise se concentre sur les activités de recrutement.
#Lire le fichier csv
df_com = pd.read_csv("/tmp/companies_list.csv", names=("Nom de la compagnie", "Synthèse", "Nom", "Nombre d'appels d'amour", "Consentement (taux d'acceptation)"))
#Triez les nominations par ordre décroissant et affichez le top 10
df_com.sort_values(by="Nom", ascending=False).head(10)
(*) Le degré de synthèse est défini sur NaN car l'attribut de données est ** hidden-xs.hidden-sm **, donc ce programme a été reconnu comme une sorte de périphérique et a été affiché et n'a pas pu être acquis.
Les éléments suivants trient les ** Love Calls ** par ordre décroissant et affichent le top 10. Vous pouvez voir que c'est une entreprise populaire parce qu'elle est dans l'ordre décroissant des appels d'amour.
#Triez le nombre d'appels d'amour par ordre décroissant et affichez le top 10
df_com.sort_values(by="Nombre d'appels d'amour", ascending=False).head(10)
Examinez les résultats des enchères passées. Les données récupérées sont triées par ordre décroissant d'index car les 22e données viennent en premier.
#Lire le fichier csv
df_results = pd.read_csv("/tmp/past_bid_results.csv", names=("Revenu annuel de la présentation centrale", "Fois", "Nombre d'entreprises participantes", "Le nombre de participants", "Nombre total de candidatures", "Revenu annuel total présenté", "Salaire annuel moyen"))
#Trier
df_results = df_results.loc[:, ["Fois", "Le nombre de participants", "Nombre d'entreprises participantes", "Nombre total de candidatures", "Salaire annuel moyen", "Revenu annuel de la présentation centrale", "Revenu annuel total présenté"]]
#Trier par index décroissant
df_results = df_results.sort_index(ascending=False)
Vérifiez le nombre de participants, le nombre d'entreprises participantes et le nombre total de nominations dans les résultats de l'offre passée par ordre chronologique.
x = ['1', '2', '3', '4', '5', '6' , '7' , '8' , '9' , '10' , '11' , '12' , '13' , '14' , '15' , '16' , '17' , '18' , '19' , '20' , '21' , '22']
y = []
y2 = []
y3 = []
for i in df_results["Le nombre de participants"]:
y.append(i)
for i in df_results["Nombre d'entreprises participantes"]:
y2.append(i)
for i in df_results["Nombre total de candidatures"]:
y3.append(i)
fig, ax = plt.subplots()
ax.plot(x, y, label='Number of participants')
ax.plot(x, y2, label='Number of participating companies')
ax.plot(x, y3, label='Total nominations')
ax.legend(loc='best')
plt.xlabel('time')
plt.ylabel('number')
plt.show()
Le nombre de participants est resté pratiquement inchangé et le nombre d'entreprises participantes a augmenté petit à petit. Le nombre total de candidatures a diminué de -36% lorsqu'il est calculé sur la base du taux de changement (*) de la 15e réunion tenue à la même époque que l'année dernière.
Taux de changement= \frac{(Point de temps de référence-Heure de référence de chaque fois)}{Heure de référence} × 100
Vérifiez le salaire annuel moyen et le salaire annuel central des résultats des offres passées par ordre chronologique.
x = ['1', '2', '3', '4', '5', '6' , '7' , '8' , '9' , '10' , '11' , '12' , '13' , '14' , '15' , '16' , '17' , '18' , '19' , '20' , '21' , '22']
y = []
y2 = []
for i in df_results["Salaire annuel moyen"]:
y.append(i)
for i in df_results["Revenu annuel de la présentation centrale"]:
y2.append(i)
fig, ax = plt.subplots()
ax.plot(x, y, label='Average presented annual income')
ax.plot(x, y2, label='Centrally presented annual income')
ax.legend(loc='best')
plt.xlabel('time')
plt.ylabel('Amount of money')
plt.show()
Le salaire annuel moyen et le salaire annuel présenté au niveau central du 3 au 19 étaient sur une tendance à la hausse, mais on peut voir qu'ils ont diminué du 20 au 22, qui a eu lieu à la fin de cette année.
Dans la mesure où les entreprises participantes sont considérées comme une prémisse, il n'y a pas de système SIer. La plupart d'entre eux sont des sociétés d'exploitation, qui peuvent être divisées en grandes entreprises, méga-entreprises basées sur le Web et startups. De plus, la plupart des entreprises sont basées à Tokyo.
Par conséquent, ce qui peut être déduit des données de l'échantillon est ** la valeur marchande de l'ingénieur de la société exploitante **.
Ce qui précède est un résumé des résultats de l'enquête basé sur les hypothèses.
Sur la base des résultats de l'enquête de 2018 présentés dans le Livre blanc 2019 sur les ressources humaines en TI, le nombre total total de ressources humaines en TI nationales est de ** 1226000 **. Parmi eux, les ressources humaines informatiques de la société informatique (côté fournisseur informatique) sont ** 938 000 ** et les ressources humaines informatiques de la société utilisatrice (côté utilisateur informatique) ** 288 000 **.
Source: Livre blanc sur les ressources humaines IT 2019 Graphique 1-2-8 Estimation du nombre total de ressources humaines IT
Voir «Rapport annuel de l'Enquête sur la population active 2018» du rapport annuel de l'Enquête sur la population active, qui est une enquête du ministère des Affaires intérieures et des Communications. Le nombre moyen d'employés / employés réguliers de sexe masculin en 2018 était de 5 à 6,99 millions de yens, ce qui était le plus élevé avec 22,8% (en hausse de 0,1 point par rapport à l'année précédente), suivi de 3 à 3,99 millions de yens à 19,8% (même taux que l'année précédente). Il est devenu. Dans le cas des hommes et des femmes, le prix le plus élevé est de 3 à 3,99 millions de yens.
Source: Tableau statistique II Tableau détaillé "II-A-Tableau 3" - "Revenus du travail (annuel), nombre de salariés par type d'emploi"
À propos des informations statistiques sur les salaires des ingénieurs système et des programmeurs de e-Stat, un site portail de statistiques gouvernementales sur lequel vous pouvez consulter les statistiques japonaises. Il est montré ci-dessous.
On peut voir que les données observées dans le projet de changement de carrière ne représentent qu'une petite partie du total d'environ 1,2 million de personnel informatique national.
Étant donné que le terme ressources humaines informatiques est utilisé au sens large, il comprend les ingénieurs système, les programmeurs et les consultants. La plupart d'entre eux peuvent être divisés en gros entre l'industrie des services d'information de l'industrie de l'information et de la communication et l'industrie des services associée à Internet, mais comme les ingénieurs qui installent dans des automobiles telles que la construction automobile sont classés dans l'industrie de la construction automobile, la situation réelle dans l'ensemble de l'industrie. S'est avéré difficile à estimer.
En examinant le rapport d'enquête annuelle sur la main-d'œuvre du ministère de l'Intérieur et des Communications, il est observé dans le projet de changement d'emploi sur la base du fait qu'il y a de nombreux employés et employés réguliers de sexe masculin dans la classe 500 à 699 et des données statistiques relatives aux salaires e-stat. La valeur marchande de 6 millions de yens peut être la même pour l'industrie dans son ensemble.
Je pense que l'argent viendra plus tard lorsque mes compétences (dans lesquelles je suis bon) correspondent à ce que la société et l'entreprise veulent. Faisons fonctionner le bord.
Recommended Posts