0
2

データのクリーニングをやってみる

Last updated at Posted at 2024-08-27

はじめに

今まで比較的綺麗なデータ(KagglePlayGroundなどの欠損値が少ないデータやデータクリーニング済のデータセットなど)を使っていたため、データのクリーニングを経験してみる。

目的
テクノロジー業界の被雇用者である回答者に絞りこみ、データを読み取りやすい形に加工する。

結果
Age : 生産年齢人口から外れる10個の値を外れ値とみなし、外れ値以外の平均値で補完。
Gender : 自由記載で表記が乱れていたため、表記内容から読み取れるGenderをM,F,NBに統一。
State : 欠損値が存在するが、CountryでUnited Statesを選択した場合に回答されたものであるため無回答グループとして扱う。
self_employed : 被雇用者のデータを求めているため、この回答にYesと答えた者と欠損値18個を除外。
no_employees : 欠損値264個存在。欠損値量が多いため、無回答グループとして処置せず。
tech_company : テクノロジー業界のデータを求めているため、この回答にNoと答えた者を除外

その他カラムに関しては欠損値・異常値がないため処置せず。

以上クリーニングから
883行×25行のデータに変更された。

データ確認

データ理解と準備

データ元:Mental Health in Tech Survey

使用したデータセットは、米国で作成されたテクノロジー業界の職場におけるメンタルヘルスに関するアンケートから作成されている。
母集団は米国のテクノロジー業界の被雇用者とし、その標本として1259人の回答が得られている。
また、データの前処理・クリーニングを経て883人まで絞られる。
テクノロジー業界は米国全体の2%、約500万人が雇用されている。1)
このことから、母集団を500万人と仮定する。
母集団500万人の場合標本サイズが1259人であれ883人であれ、95%の信頼水準での許容誤差は約3.5%となり、かなり良好な精度の結果が得られると考えられる。

ライブラリ
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns

データセット概要

データの読み込み
df_mental = pd.read_csv('survey.csv')
df_mental

結果
image.png

データの行列確認
df_mental.shape
(1259, 27)
  • 1259行×27列のデータセット
  • 以下に特徴量の要約を一覧で示す。
カラム名 意訳・解釈 Dtype 変数尺度 欠損値
Timestamp タイムスタンプ object 時系列変数 0
Age 年齢 int64 量的変数 0
Gender 性別 object 質的変数 0
Country object 質的変数 0
state object 質的変数 515
self_employed 自営業 object 質的変数 18
family_history 家族の既往歴 object 質的変数 0
treatment 治療 object 質的変数 0
work_interfere 仕事への影響 object 質的変数 264
no_employees 従業員数 object 質的変数 264
remote_work リモートワーク object 質的変数 0
tech_company テクノロジー会社所属 object 質的変数 0
benefits 福利厚生 object 質的変数 0
care_options ケアオプション object 質的変数 0
wellness_program 健康増進支援の有無 object 質的変数 0
seek_help 助けを求める方法の有無 object 質的変数 0
anonymity 匿名性 object 質的変数 0
leave 休暇 object 質的変数 0
mental_health_consequence 精神的健康と会社の反応 object 質的変数 0
phys_health_consequence 身体的健康と会社の反応 object 質的変数 0
coworkers 同僚 object 質的変数 0
supervisor 上司 object 質的変数 0
mental_health_interview 精神的健康と面接 object 質的変数 0
phys_health_interview 身体的健康と面接 object 質的変数 0
mental_vs_physical 精神的健康vs身体的健康 object 質的変数 0
obs_consequence 観測結果 object 質的変数 0
comments コメント object 質的変数 1095

特徴量の把握とクリーニング

1. Timestamp(タイムスタンプ)

  • おそらくアンケートの回答日時と思われる
時間範囲の確認
print(f"MinDate : {df_mental['Timestamp'].min()}, MaxDate : {df_mental['Timestamp'].max()}")
MinDate : 2014-08-27 11:29:31, MaxDate : 2016-02-01 23:04:31
日数の取得
start_date = datetime(2014, 8, 27)
end_date = datetime(2016, 2, 1)
difference = end_date - start_date
print(difference.days)
523

このデータセットのアンケート期間は2014-08-27から2016-02-01までの523日間(約1年半)である。

2. Age(年齢)

df_mental['Age'].unique()
array([         37,          44,          32,          31,          33,
                35,          39,          42,          23,          29,
                36,          27,          46,          41,          34,
                30,          40,          38,          50,          24,
                18,          28,          26,          22,          19,
                25,          45,          21,         -29,          43,
                56,          60,          54,         329,          55,
       99999999999,          48,          20,          57,          58,
                47,          62,          51,          65,          49,
             -1726,           5,          53,          61,           8,
                11,          -1,          72], dtype=int64)

おかしな値が紛れ込んでいる。

df_mental['Age'].describe()
count    1.259000e+03
mean     7.942815e+07
std      2.818299e+09
min     -1.726000e+03
25%      2.700000e+01
50%      3.100000e+01
75%      3.600000e+01
max      1.000000e+11
Name: Age, dtype: float64

平均値・標準偏差が99999999999に引っ張られてしまっている。
また、マイナス値や労働基準的におかしい5歳など外れ値が見られる。
知りたいのは一般的に会社に雇われている年齢層である。

ここでは、生産年齢人口区分に漏れる者は外れ値とみなすこととする。(米国でも生産年齢人口を15~64としているため)

# 生産年齢人口に含まれない年齢を抽出
df_non_working_age_population = df_mental[(df_mental['Age'] < 15) | (df_mental['Age'] > 64)]

# ユニークな値とその数を取得
unique_values_counts = df_non_working_age_population['Age'].value_counts()

# 結果を表示
print("生産年齢人口に含まれない年齢のユニークな値とその数:")
print(unique_values_counts)

print(f'\n合計 : {unique_values_counts.sum()}')

生産年齢人口に含まれない年齢のユニークな値とその数:
-29             1
 329            1
 99999999999    1
 65             1
-1726           1
 5              1
 8              1
 11             1
-1              1
 72             1
Name: Age, dtype: int64

合計 : 10個

1259行中10個が外れ値となった。
ここで一旦その行を確認する。

df_non_working_age_population

カラム数が多いので結果は省略する。
要約すると、2014年8月~10月の範囲で上記外れ値が見られた。
少数のため削除してもよいが、一旦外れ値以外の平均値で補完する。

# 生産年齢人口に含まれる年齢の平均値を計算
median_age = df_mental[(df_mental['Age'] >= 15) & (df_mental['Age'] <= 64)]['Age'].mean()

# 生産年齢人口に含まれない年齢を平均値で補完
df_mental.loc[(df_mental['Age'] < 15) | (df_mental['Age'] > 64), 'Age'] = mean_age

df_mental['Age'].describe()
count    1259.000000
mean       32.010326
std         7.117393
min        18.000000
25%        27.000000
50%        31.000000
75%        36.000000
max        62.000000
Name: Age, dtype: float64

image.png

ボリュームゾーンは30代を中心とした山になっている。

3. Gender(性別)

df_mental['Gender'].unique()
array(['Female', 'M', 'Male', 'male', 'female', 'm', 'Male-ish', 'maile',
       'Trans-female', 'Cis Female', 'F', 'something kinda male?',
       'Cis Male', 'Woman', 'f', 'Mal', 'Male (CIS)', 'queer/she/they',
       'non-binary', 'Femake', 'woman', 'Make', 'Nah', 'All', 'Enby',
       'fluid', 'Genderqueer', 'Female ', 'Androgyne', 'Agender',
       'cis-female/femme', 'Guy (-ish) ^_^', 'male leaning androgynous',
       'Male ', 'Man', 'Trans woman', 'msle', 'Neuter', 'Female (trans)',
       'queer', 'Female (cis)', 'Mail', 'cis male', 'A little about you',
       'Malr', 'p', 'femail', 'Cis Man',
       'ostensibly male, unsure what that really means'], dtype=object)

単純な生物学的な記載だけでも大文字小文字が入り混じっている。

M:男性、F:女性、NB:ノンバイナリで推測し分類することとする。

f = 'F'
m = 'M'
nb = 'NB'

gender_mapping = {
    'Female':f,
    'M':m,
    'Male':m,
    'male':m,
    'female':f,
    'm':m,
    'Male-ish':nb,
    'maile':m,
    'Trans-female':nb,
    'Cis Female':f,
    'F':f, 
    'something kinda male?':nb,
    'Cis Male':m, 
    'Woman':f, 
    'f':f, 
    'Mal':m, 
    'Male (CIS)':m, 
    'queer/she/they':nb,
    'non-binary':nb, 
    'Femake':f, 
    'woman':f, 
    'Make':m, 
    'Nah':nb, 
    'All':nb, 
    'Enby':nb,
    'fluid':nb,
    'Genderqueer':nb,
    'Female ':f,
    'Androgyne':nb,
    'Agender':nb,
    'cis-female/femme':nb,
    'Guy (-ish) ^_^':nb, 
    'male leaning androgynous':nb,
    'Male ':m, 
    'Man':m, 
    'Trans woman':nb, 
    'msle':m, 
    'Neuter':nb, 
    'Female (trans)':nb,
    'queer':nb, 
    'Female (cis)':m, 
    'Mail':m, 
    'cis male':m, 
    'A little about you':nb,
    'Malr':m, 
    'p':nb, 
    'femail':f, 
    'Cis Man':m,
    'ostensibly male, unsure what that really means':nb

}

df_mental['Gender'] = df_mental['Gender'].map(gender_mapping)

df_mental['Gender'].unique()
array(['F', 'M', 'NB'], dtype=object)

image.png

男性の回答が圧倒的に多い。

4. Country

欠損値、異常値がみられないため処置なし。

image.png

米国アンケートのためUSの回答が多い。
次にUK,Canada,Germanyと多国籍の回答が続く。

5. state

アンケート内容 : 米国の場合、どの州または地域に住んでいますか?

原文:If you live in the United States, which state or territory do you live in?

欠損値は515個存在する。
異常値はみられないため処置なし。

欠損値に関しては米国以外の国と推測し、回答なしグループとしてそのまま残すこととする。

欠損値を除いたグラフ。
image.png

米国中、カリフォルニア、ワシントン、ニューヨークと主要都市が続く。

6. self_employed

アンケート内容 : 自営業ですか?
原文 : Are you self-employed?

欠損値は18個存在する。
ユニークな値は欠損値を省けば'Yes'か'No'のバイナリ値である。
今回知りたいのは被雇用者側についてであり、欠損値はすくないため削除とする。

df_mental = df_mental.dropna(subset=['self_employed'])
df_mental['self_employed'].unique()
array(['Yes', 'No'], dtype=object)

image.png

Noを被雇用者、Yesを雇用者側と判断する。
被雇用者のみでもデータ量が確保できるため、雇用者と回答した者の行を削除する。

df_mental = df_mental[df_mental['self_employed'] != 'Yes']

print(df_mental['self_employed'].unique())
print(df_mental.shape)
['No']
(1095, 27)

データフレームが被雇用者のみのデータになったため、'self_employed']カラムを削除する。

df_mental = df_mental.drop('self_employed', axis=1)
df_mental.shape
(1095, 26)

7. family_history

アンケート内容 : 精神疾患の家族歴はありますか?
原文 : Do you have a family history of mental illness?

YesかNoのバイナリ値。欠損値・異常値なし。

image.png

8. treatment

アンケート内容 : 精神疾患の治療を受けたことがありますか?

原文 : Have you sought treatment for a mental health condition?

YesかNoのバイナリ値。欠損値・異常値なし。

image.png

9. work_interfere(目的変数)

アンケート内容 : 精神的な健康上の問題がある場合、それが仕事に支障をきたしていると感じますか?

原文 : If you have a mental health condition, do you feel that it interferes with your work?

欠損値264個存在。

欠損値を除いた回答は
'Often' - よく影響する、'Sometimes' - 時々影響する、'Rarely' - ほとんど影響しない、'Never' - 影響しない
となっている。

欠損値は回答なし('No answer')として扱う。

image.png

10. no_employees

アンケート内容 : あなたの会社または組織には何人の従業員がいますか?

原文 : How many employees does your company or organization have?

欠損値264個存在。
1-5,6-25,26-100,100-500,500-1000,more than 1000の区分がある。

image.png

欠損値量が多い。従業員数を把握していない人の回答か。
無回答グループとして扱うこととする。

26-100人の従業員数の会社に所属している人の回答が多い。

11. remote_work

アンケート内容 : 少なくとも50%の時間はリモート(オフィス外)で働いていますか?

原文 : Do you work remotely (outside of an office) at least 50% of the time?

欠損値・異常値なし。YesかNoのバイナリ値。

image.png

12. tech_company

アンケート内容 : あなたの雇用主は主にテクノロジー企業/組織ですか?

原文 : Is your employer primarily a tech company/organization?

欠損値・異常値なし。YesかNoのバイナリ値。

image.png

テクノロジー企業の分析をしたいため、Noと回答した行を削除する。

df_mental = df_mental[df_mental['tech_company'] != 'No']
print(df_mental['tech_company'].unique())
print(df_mental.shape)
['Yes']
(883, 26)

テクノロジー企業のみのデータなったためtech_company列も削除する

df_mental = df_mental.drop('tech_company', axis=1)
df_mental.shape
(883, 25)

13. benefits

アンケート内容 : あなたの雇用主はメンタルヘルスの福利厚生を提供していますか?

原文 : Does your employer provide mental health benefits?

欠損値・異常値なし。
['Yes', 'No', "Don't know"]で回答される。

image.png

会社側の制度の有無に関連していそうである。
また、被雇用者の会社制度理解に関連しているとみていいのではないだろうか。

14. care_options

アンケート内容 : あなたの雇用主が提供するメンタルヘルスケアのオプションを知っていますか?

原文 : Do you know the options for mental health care your employer provides?

欠損値・異常値なし。
['Yes', 'No', 'Not sure']で回答される。

image.png

こちらもbenefits同様、被雇用者の会社制度理解に関連していそうである。

15. wellness_program

アンケート内容 : あなたの雇用主は、従業員の健康増進プログラムの一環としてメンタルヘルスについて話し合ったことがありますか?

原文 : Has your employer ever discussed mental health as part of an employee wellness program?

欠損値・異常値なし。
['Yes', 'No', "Don't know"]で回答される。

image.png

会社側のメンタルヘルスへの関心に関連していそうである。

16. seek_help

アンケート内容 : あなたの雇用主は、メンタルヘルスの問題についてさらに学び、助けを求める方法を学ぶためのリソースを提供していますか?

原文 : Does your employer provide resources to learn more about mental health issues and how to seek help?

欠損値・異常値なし。
['Yes', 'No', "Don't know"]で回答される。

image.png

wellness_program同様、会社側のメンタルヘルスへの関心に関連していそうである。

17. anonymity

アンケート内容 : メンタルヘルスや薬物乱用治療リソースを利用する場合、匿名性は保護されますか?

原文 : Is your anonymity protected if you choose to take advantage of mental health or substance abuse treatment resources?

欠損値・異常値なし。
['Yes', 'No', "Don't know"]で回答される。

image.png

18. leave

アンケート内容 : 精神的な健康上の問題で病気休暇を取るのはどれくらい簡単ですか?

原文 : How easy is it for you to take medical leave for a mental health condition?

欠損値・異常値なし。
['Very difficult', 'Somewhat difficult', 'Somewhat easy', 'Very easy', "Don't know"]で回答される。

image.png

Don't knowの場合、病気休暇を取得した経験がなく、周りにもそういった休暇を取得した人が少ないため知らないと解釈して良いかもしれない。

19. mental_health_consequence

アンケート内容 : 雇用主とメンタルヘルスの問題について話し合うと、悪い結果が生じると思いますか?

原文 : Do you think that discussing a mental health issue with your employer would have negative consequences?

欠損値・異常値なし。
['Yes', 'Maybe', 'No']で回答される。

image.png

Maybeの場合そういった問題に話し合った経験が自分にも周囲にもない回答とみれる。
Noの場合はっきりと悪い結果が生じないという雇用主への信頼が読み取れる。

20. phys_health_consequence

アンケート内容 : 雇用主と身体的な健康問題について話し合うと、マイナスの結果が生じると思いますか?

原文 : Do you think that discussing a physical health issue with your employer would have negative consequences?

欠損値・異常値なし。
['Yes', 'Maybe', 'No']で回答される。

image.png

21. coworkers

アンケート内容 : 同僚とメンタルヘルスの問題について話し合う気はありますか?

原文: Would you be willing to discuss a mental health issue with your coworkers?

欠損値・異常値なし。
['Yes', 'Some of them', 'No']で回答される。

image.png

22. supervisor

アンケート内容 : メンタルヘルスの問題について直属の上司と話し合う意思はありますか?

原文 : Would you be willing to discuss a mental health issue with your direct supervisor(s)?

欠損値・異常値なし。
['Yes', 'Some of them', 'No']で回答される。

image.png

同僚とはSome of themの回答が多いが、上司の場合はYesの回答が多い。
仕事の都合上相談をする機会が多いためだろう。
頻度でいえばNoの回答は同僚の場合より多くなっている。

23. mental_health_interview

アンケート内容 : 面接で、採用候補者にメンタルヘルスの問題について話しますか?

原文 : Would you bring up a mental health issue with a potential employer in an interview?

欠損値・異常値なし。
['Yes', 'Maybe', 'No']で回答される。

image.png

24. phys_health_interview

アンケート内容 : 面接で、潜在的な雇用主に身体的な健康問題について話しますか?

原文 : Would you bring up a physical health issue with a potential employer in an interview?

欠損値・異常値なし。
['Yes', 'Maybe', 'No']で回答される。

image.png

身体的な健康問題については多分の割合が多いが、精神的な健康問題についてははっきりとNoが多い。

25. mental_vs_physical

アンケート内容 : あなたの雇用主は、心の健康を身体の健康と同じくらい真剣に受け止めていると思いますか?

原文 : Do you feel that your employer takes mental health as seriously as physical health?

欠損値・異常値なし。
['Yes', "Don't know", 'No']で回答される。

image.png

26. obs_consequence

アンケート内容 : 職場で精神疾患を持つ同僚による悪影響について聞いたり、目撃したりしたことがありますか?

原文 : Have you heard of or observed negative consequences for coworkers with mental health conditions in your workplace?

欠損値・異常値なし。Yes,Noのバイナリ値。

image.png

27. comments

その他メモやコメント

欠損値1095個存在。
つまりデータ1259中164個のコメントが存在する。

データフレームのままではコメントが読みづらいため、csv形式でコメントのみ抽出する。

df_comments = df_mental[df_mental['comments'].notna()]
df_comments['comments'].to_csv('comments.csv', index=False)

コメントは109個ある。

コメント内容一部抜粋

  • 仕事についての補足
    • Relatively new job. Ask again later
    • I just started a new job last week hence a lot of don't know's
  • 国の事情情報
    • In Russia we have mandatory medical insurance. Every employer must pay 3.6% of……
  • 会社情報補足
    • My employer employs 17k people worldwide and my previous ……
  • 調査へのコメント
    • I openly discuss my mental health struggles.
    • Thank you for shining a light on this topic.
    • I've answered 'Yes' on remote working but 50% is the maximum time we're allowed.…… so I've answered 'Don't know'.
  • メンタルヘルスに関する詳細
    • When I've had a depression I was lucky to have an awesome manager who was very understanding and found a budget to pay for my therapy sessions.People have often felt ……

コメントを残す人は、より正確な回答を残そうといった傾向がありそうである。

以上、クリーニングから883行×25行のデータに変更された。

参考URL

1)米国テクノロジー業界のレイオフのリアル 2023-01-26 2024-8-27閲覧

テクノロジー業界は米国全体の2%、約500万人しか雇用していない

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2