ラベル pandas の投稿を表示しています。 すべての投稿を表示
ラベル pandas の投稿を表示しています。 すべての投稿を表示

2018年7月13日金曜日

ハローワークの求人情報を見てみる。賃金分布、地域、業種(python,pandas,matplotlib)

前回、ハローワークインターネットサービスから求人一覧を取得しました。

ハローワークインターネットサービスから求人情報を取得する
http://eneprog.blogspot.com/2018/07/pythonpandas.html

今回はこのデータの中身を見てみます。

・インポートとデータ読み込み
import pandas as pd
from time import sleep

import matplotlib
import matplotlib.pyplot as plt

tables=pd.read_csv("ehime_job.csv",encoding="CP932")
tables.head()
Unnamed: 0NO求人番号職種雇用形態/賃金(税込)就業時間/休日/週休二日産業沿線/就業場所受理日
0NEW!◎113040- 82018581ルームアドバイザー職/新居浜駅前店正社員/182,000円~182,000円変形 1年単位1)10:00~19:00/他/その他不動産業,物品賃貸業のうち不動産代理業・仲介業愛媛県新居浜市平成30年7月9日
1NEW!◎213170- 30358781施工管理/松山市(要普免) 【急募】正社員/230,000円~400,000円1)08:00~17:00/土日/毎週不動産業,物品賃貸業のうち建物売買業,土地売買業愛媛県松山市平成30年7月9日
2NEW!◎321010- 26058881メディカルスタッフ(たんぽぽ薬局今治喜田村店)正社員/167,800円~200,000円変形 1ヶ月単位1)08:30~17:302)08:30~13:303)09:00~18:0...卸売業・小売業のうち医薬品・化粧品小売業愛媛県今治市平成30年7月9日
3NEW!◎427020- 46421181フィールドサービス(松山市)**急募**正社員/150,000円~225,000円変形 1年単位1)08:35~18:30/他/毎週卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日
4NEW!◎527020- 46422081営業職(プレゼン型)松山市★東証一部上場★メーカー正社員/150,000円~225,000円変形 1年単位1)08:35~18:30/土日祝他/毎週卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日

愛媛県のフルタイム正社員の求人情報、7575件です。

「雇用形態/賃金(税込)」と「就業時間/休日/週休二日」は複数の情報が一つのカラムに入っているので分割し、データを整理します。

・「雇用形態/賃金(税込)」の整理
table2=(tables["雇用形態/賃金(税込)"]
        .str.replace("円~","/")
        .str.replace("円","")
        .str.replace(",","")
        .str.split("/",expand=True)
       )

able2.columns=["雇用形態","賃金(最低)","賃金(最大)"]
table2=table2[["賃金(最低)","賃金(最大)"]].astype(int)
table2.head() 
賃金(最低)賃金(最大)
0182000182000
1230000400000
2167800200000
3150000225000
4150000225000


「雇用形態/賃金(税込)」列には「正社員/182,000円~182,000円」というように"雇用形態","賃金(最低)","賃金(最大)"の3つの情報が入っています。区切り文字を"/"に統一し、不要な文字("円",コンマ)を削除して、splitで列を分割します。

その後、列名をつけ、「賃金(最低)」「賃金(最大)」を数値に変換しました。

・「就業時間/休日/週休二日」の分割
table3=tables["就業時間/休日/週休二日"].str.split("/",expand=True)
table3.columns=["就業時間","休日","週休二日"]
table3.head()
就業時間休日週休二日
0変形 1年単位1)10:00~19:00その他
11)08:00~17:00土日毎週
2変形 1ヶ月単位1)08:30~17:302)08:30~13:303)09:00~18:00日祝他毎週
3変形 1年単位1)08:35~18:30毎週
4変形 1年単位1)08:35~18:30土日祝他毎週

同様に「就業時間/休日/週休二日」も3つに分割します。

・データ結合
job_table=(pd.concat([tables,table2,table3],axis=1)
           .drop(["雇用形態/賃金(税込)","就業時間/休日/週休二日"],axis=1)
          )
job_table.head()
Unnamed: 0NO求人番号職種産業沿線/就業場所受理日雇用形態賃金(最低)賃金(最大)就業時間休日週休二日
0NEW!◎113040- 82018581ルームアドバイザー職/新居浜駅前店不動産業,物品賃貸業のうち不動産代理業・仲介業愛媛県新居浜市平成30年7月9日正社員182000182000変形 1年単位1)10:00~19:00その他
1NEW!◎213170- 30358781施工管理/松山市(要普免) 【急募】不動産業,物品賃貸業のうち建物売買業,土地売買業愛媛県松山市平成30年7月9日正社員2300004000001)08:00~17:00土日毎週
2NEW!◎321010- 26058881メディカルスタッフ(たんぽぽ薬局今治喜田村店)卸売業・小売業のうち医薬品・化粧品小売業愛媛県今治市平成30年7月9日正社員167800200000変形 1ヶ月単位1)08:30~17:302)08:30~13:303)09:00~18:00日祝他毎週
3NEW!◎427020- 46421181フィールドサービス(松山市)**急募**卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日正社員150000225000変形 1年単位1)08:35~18:30毎週
4NEW!◎527020- 46422081営業職(プレゼン型)松山市★東証一部上場★メーカー卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日正社員150000225000変形 1年単位1)08:35~18:30土日祝他毎週

データ結合し、表の完成です。

ここから中身を見てみます。

・求人の多い地域
job_area=job_table.groupby("沿線/就業場所")[["沿線/就業場所"]].count().sort_values(by="沿線/就業場所", ascending=False)
job_area[:10] 
沿線/就業場所
沿線/就業場所
愛媛県松山市2853
愛媛県今治市894
愛媛県新居浜市734
愛媛県西条市620
愛媛県四国中央市612
愛媛県宇和島市321
愛媛県大洲市240
愛媛県八幡浜市198
愛媛県伊予郡松前町150
愛媛県東温市150

groupbyで「沿線/就業場所」をグループ化し、データ数を数えました。

松山市の求人数がダントツで多いです。続いて今治市、西条市、新居浜市となっています。

・求人の多い業種
job_table.groupby("産業")[["産業"]].count().sort_values(by="産業", ascending=False)[:10]
産業
産業
医療,福祉のうち老人福祉・介護事業1025
医療,福祉のうち病院478
運輸業,郵便業のうち一般貨物自動車運送業319
建設業のうち一般土木建築工事業246
製造業のうち船舶製造・修理業,舶用機関製造業229
医療,福祉のうち一般診療所207
建設業のうち土木工事業(舗装工事業を除く)143
卸売業・小売業のうち自動車小売業108
卸売業・小売業のうち医薬品・化粧品小売業108
医療,福祉のうち歯科診療所107

産業別では、医療、介護系が最も多く、運輸、建設・製造と続いています。

・賃金の統計量
table2[["賃金(最低)","賃金(最大)"]].describe()
賃金(最低)賃金(最大)
count7575.0000007575.000000
mean167828.605545224215.472871
std35528.51465972106.315667
min45000.00000050000.000000
25%147000.000000173000.000000
50%162500.000000210000.000000
75%184817.000000260000.000000
max416667.000000791666.000000

.describe()で賃金情報の統計量を見てみます。

賃金(最低)の平均は167,828円、中央値162,500円で、賃金(最大)では平均224,215円、中央値210000と平均値と中央値の差は小さくなっています。

・賃金の分布
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams["font.size"] = 16

table2.plot(y=["賃金(最低)","賃金(最大)"],bins=20,alpha=0.5,range=(0,600000),kind="hist",figsize=(10,5))


matplotlibで日本語を表示させると文字化けするので、plt.rcParams['font.family']でフォントを指定しています。alpha=0.5は色の透過度の指定です。

赤色、賃金(最低)では16万円に大きな山となり分布範囲は小さくなっています。このくらいの求人が多いということですね。青色、賃金(最高)の方は最頻値が20万円程度で最低よりも分布が広く、やや右に裾の長いグラフになりました。

参考:
ハローワークインターネットサービス
https://www.hellowork.go.jp/index.html

プログラミング学習:pandasでweb上の表を取得する。
https://eneprog.blogspot.com/2018/04/pandaswebpython.html
ハローワークインターネットサービスから求人情報を取得する
http://eneprog.blogspot.com/2018/07/pythonpandas.html

2018年7月11日水曜日

ハローワークインターネットサービスから求人情報を取得する(python,pandas,スクレイピング)

私は現在、求職中です。どんな求人があるのか気になるので、ハローワークインターネットサービスから求人情報を取得してみることにしました。

ハローワークインターネットサービス 求人情報基本条件入力
https://www.hellowork.go.jp/servicef/130020.do?action=initDisp&screenId=130020


上記から検索条件を指定して検索すると、職種、雇用形態、賃金などが記載された「求人情報一覧」という表がでてきます。



この表を取得することを目指します。

・インポート
import pandas as pd
from time import sleep

pandasのほか、timesのsleepをインポート。sleepは一時的に処理を止めるときに使います。

・URLを作る
pageno=1

url=("https://www.hellowork.go.jp/servicef/130050.do?"
     "fwListNaviBtn1=1&"
     "fwListNowPage=1&"
     "fwListLeftPage=" + str(pageno) +"&" #ページ番号
     "fwListNaviCount=1&"
     "kyujinShuruiHidden=1&" #フルタイム
     "koyoKeitaiHidden=1&" #正社員
     "todofukenHidden=38&" #愛媛県
     "screenId=130050&"
     "xab_vrbs=detailJokenDispButton,commonNextScreen,detailJokenChangeButton,commonDetailInfo")

情報を取得するURLを作成します。普通に検索しただけではURLが出てこないので、ソースと下記ページを参考に作りました。

ハローワークの一覧を簡易クロールして求人ページのURLを抽出する

今回は「フルタイム」「正社員」「愛媛県」の求人を指定しました。それぞれの数値はソースなどで確認してください。また、URLの前半部分の「13050」とscreenIdは変更することがあるようです。

・表の取得
df_tmp=pd.read_html(url,match="求人番号",header=0)
df=df_tmp[0]

作成したURLからread_htmlで表を取得します。read_htmlの使い方は以前書きました。

プログラミング学習:pandasでweb上の表を取得する。(python)

read_htmlでは、webページ上の表を一つずつリストとして取得します。上記記事ではリスト番号から目的の表を探しましたが、今回は match="求人番号"で"求人番号"という言葉が含まれている表だけを取得しています。header=0で1行目を列名として使います。

df=df_tmp[0]で目的の表を取り出し。match指定していしているので目的の表1つだけがdf_tmpに取得されているはずです(要確認)

・複数ページ取得
tables=pd.DataFrame()

for pageno in range(1,4):
    print(pageno)
    url=("https://www.hellowork.go.jp/servicef/130050.do?"
       "fwListNaviBtn1=1&"
       "fwListNowPage=1&"
       "fwListLeftPage=" + str(pageno) +"&"
       "fwListNaviCount=1&"
       "kyujinShuruiHidden=1&" #フルタイム
       "koyoKeitaiHidden=1&" #正社員
       "todofukenHidden=38&" #愛媛県
       "screenId=130050&"
       "xab_vrbs=detailJokenDispButton,commonNextScreen,detailJokenChangeButton,commonDetailInfo")
    
    df_tmp=pd.read_html(url,match="求人番号",header=0)
    tables=tables.append(df_tmp[0]).reset_index(drop=True)
    
    sleep(1)


1~3ページ目まで取得する例です。各ページの表をtablesにappendで結合します。ページ移行時にsleepで1秒待機しています。

出力(一部)
Unnamed: 0NO求人番号職種雇用形態/賃金(税込)就業時間/休日/週休二日産業沿線/就業場所受理日
0NEW!◎2138010- 23863381一般作業正社員/206,100円~274,800円変形 1ヶ月単位1)08:15~17:00/日他/その他建設業のうち一般土木建築工事業愛媛県伊予郡松前町平成30年7月10日
1NEW!◎2238010- 23866581運転手(大型)正社員/250,000円~400,000円変形 1ヶ月単位1)08:00~17:00/他/その他運輸業,郵便業のうち特定貨物自動車運送業愛媛県松山市平成30年7月10日
2NEW!◎2338010- 23868781介護支援専門員(施設)正社員/165,000円~220,000円変形 1ヶ月単位1)08:30~17:30/他/その他医療,福祉のうち老人福祉・介護事業愛媛県東温市平成30年7月10日
3NEW!◎2438010- 23886881大型車両整備士正社員/287,086円~337,098円1)08:30~17:30/日祝他/その他運輸業,郵便業のうち一般貨物自動車運送業愛媛県東温市平成30年7月10日
4NEW!◎2538010- 23893781看護師・准看護師正社員/190,000円~240,000円変形 1ヶ月単位1)08:45~18:152)08:45~18:303)08:45~12:4...医療,福祉のうち一般診療所愛媛県松山市平成30年7月10日


無事、一覧表の取得が出来ました。これを整理して、ざっくりどんな業種・地域に求人が多いかや賃金の傾向などを見てみたいと思います。


参考:

2018年6月26日火曜日

janomeの形態素情報を保存する。(python、自然言語処理、形態素解析、pandas)

前回エネルギー基本計画案から名詞(代名詞、非自立名詞)だけを取り出してwordcloudを作ってみましたが、同じ文章を分析するのに、何度もjanomeで形態素解析を繰り返すのが無駄な気がしてきました。

このため、今回はjanomeで解析した形態素情報を丸ごと取り出し、pandasデータフレームとして保存したいと思います。これだと一度、形態素解析をかけると後で再利用が楽になるはずです。

janomeでの形態素解析、形態素情報については下記記事をご参照ください。

Janomeで形態素解析をやってみる。(python,自然言語処理,分かち書き

・インポート
from janome.tokenizer import Tokenizer
from wordcloud import WordCloud
import matplotlib.pyplot as plt

import pandas as pd

・形態素情報を取り出す
t = Tokenizer()
text="エネルギー"

tokens = t.tokenize(text)
for token in tokens:
    print(token)

print(type(token))
str(token)
エネルギー	名詞,一般,*,*,*,*,エネルギー,エネルギー,エネルギー
<class janome.tokenizer.token="">
'エネルギー\t名詞,一般,*,*,*,*,エネルギー,エネルギー,エネルギー'

janomeの形態素解析で出力される形態素情報の形式をみてみます。

janome.tokenizer.Tokenというタイプで、「表層形(タブ区切り),品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音」という並びになっています。strで文字列にすることで丸ごと保存できそうです。

・形態素情報をpandasデータフレームに保存
t = Tokenizer()

text="はじめに\n\n2011年3月の東日本大震災及び東京電力福島第一原子力発電所事故を受けて、政府は、2014年4月、2030年を念頭に、第4次エネルギー基本計画を策定し、原発依存度の低減、化石資源依存度の低減、再生可能エネルギーの拡大を打ち出した。"

tokens = t.tokenize(text)

partofspeech_pd=pd.DataFrame()
for token in tokens:
    str_token=str(token).replace("\t",",")
    token_list=str_token.split(",")
    partofspeech_pd= partofspeech_pd.append(pd.Series(token_list),ignore_index=True)

partofspeech_pd.columns = ["単語","品詞","品詞細分類1","品詞細分類2","品詞細分類3","活用型","活用形","原形","読み","発音"]
partofspeech_pd[:20]
単語品詞品詞細分類1品詞細分類2品詞細分類3活用型活用形原形読み発音
0はじめ名詞副詞可能****はじめハジメハジメ
1助詞格助詞一般***
2\n\n記号空白****\n\n**
3名詞****
4名詞****ゼロゼロ
5名詞****イチイチ
6名詞****イチイチ
7名詞接尾助数詞***ネンネン
83月名詞副詞可能****3月サンガツサンガツ
9助詞連体化****
10東日本名詞固有名詞地域一般**東日本ヒガシニッポンヒガシニッポン
11大震災名詞一般****大震災ダイシンサイダイシンサイ
12及び接続詞*****及びオヨビオヨビ
13東京電力名詞固有名詞組織***東京電力トウキョウデンリョクトーキョーデンリョク
14福島名詞固有名詞地域一般**福島フクシマフクシマ
15接頭詞数接続****ダイダイ
16名詞****イチイチ
17原子力名詞一般****原子力ゲンシリョクゲンシリョク
18発電名詞サ変接続****発電ハツデンハツデン
19名詞接尾一般***ショショ

表層形と品詞などの形態素情報を区切っているタブをコンマに置換後、コンマを区切り文字にして分割しリストに保管。リストをpandasのseriesにしてデータフレームに行追加しています。最後に列名をつけて完成です。

これで形態素情報を全て保存したデータフレームができました。

が、エネルギー基本計画(案)全てを変換するのに約1時間かかり、できたCSVは約2.7MBあります(もとのtxtは330KB)。さらに時間短縮、データ要量削減の工夫が必要なようです。

さて、このデータフレームをどう使うのか。前回の名詞(代名詞、非自立名詞をのぞく)でwordcludを作る例をやってみます。dfにエネルギー基本計画(案)全ての形態素情報が入っています。

・名詞(代名詞、非自立名詞をのぞく)を抽出
noun = df[df["品詞"]=="名詞"]
noun2=noun[(noun["品詞細分類1"] != "代名詞") & (noun["品詞細分類1"] != "非自立")]
noun2
単語品詞品詞細分類1品詞細分類2品詞細分類3活用型活用形原形読み発音
0はじめ名詞副詞可能****はじめハジメハジメ
3名詞****
4名詞****ゼロゼロ
5名詞****イチイチ
6名詞****イチイチ
7名詞接尾助数詞***ネンネン
83月名詞副詞可能****3月サンガツサンガツ
10東日本名詞固有名詞地域一般**東日本ヒガシニッポンヒガシニッポン
11大震災名詞一般****大震災ダイシンサイダイシンサイ
13東京電力名詞固有名詞組織***東京電力トウキョウデンリョクトーキョーデンリョク
14福島名詞固有名詞地域一般**福島フクシマフクシマ
16名詞****イチイチ
17原子力名詞一般****原子力ゲンシリョクゲンシリョク
18発電名詞サ変接続****発電ハツデンハツデン
19名詞接尾一般***ショショ
20事故名詞一般****事故ジコジコ
25政府名詞一般****政府セイフセイフ
28名詞****
29名詞****ゼロゼロ
30名詞****イチイチ

"品詞"列から値が"名詞"の行を抽出した後、"品詞細分類1"列が"代名詞"、"非自立"の行を除きました。pandasの複数条件抽出では、"and"の代わりに"&"を使うことに注意(and、orを使うとエラーになる)。
・半角スペースで文字列連結
noun_df=" ".join(list(noun2["単語"])) 

条件に適した行を取り出した後、"単語"列を抽出し、リストに変換してjoinで半角スペース区切りの文字列を作ります。これで前回と同様にwordcloudが作れます。

1回ずつ形態素解析をする必要がなくなり、品詞ごとなどの抽出や集計など試行錯誤がやりやすくなりました。

↓こちらはエネルギー基本計画(案)から動詞の原形で作ったwordclud


「する」「進める」が大きく表示され、計画への意欲(?)が現れているようです。

参考:
wordcloudライブラリ
https://amueller.github.io/word_cloud/index.html

資源エネルギー庁:エネルギー基本計画(案)
http://www.enecho.meti.go.jp/committee/council/basic_policy_subcommittee/pdf/basic_policy_subcommittee_002.pdf

修正:PDFMinerでpdfからtxtを抽出する。
http://eneprog.blogspot.com/2018/05/pdfminerpdftxtpythonpdfminersix.html
正規表現を使って、エネルギー基本計画のテキストを整形する。
http://eneprog.blogspot.com/2018/06/pythonresplit.html
Janomeで形態素解析をやってみる。
http://eneprog.blogspot.com/2018/06/janomepython.html
エネルギー基本計画(案)の特徴を見てみる。その1 wordcloud
https://eneprog.blogspot.com/2018/06/wordcloudpythonjanome.html
エネルギー基本計画(案)の特徴を見てみる。その2 名詞でwordcloud
https://eneprog.blogspot.com/2018/06/2-pythonjanomewordcloud.html
//SyntaxHighlighter CDNより https://cdnjs.com/libraries/SyntaxHighlighter // 対応言語