LoginSignup
3

More than 5 years have passed since last update.

精神病患者の判定しようとしたら前処理に時間がかかった話

Posted at

この記事はSRA Advent Calendar 2018の17日目の記事です。

関西事業部の安井です。
6月頃から有料の機械学習セミナー・ディープラーニングセミナーに通い、色々とノウハウを学びました。
復習も兼ねて、精神病患者の診断をしたいと思っていましたが、時間の都合上、前処理途中でタイムアップとなってしまいました...。
とりあえず、できたところまでは投稿しようと思います。

概要

データは Kaggle で公開されている下記のデータを使用します。

このデータセットは精神面での健康及び精神疾患の頻度に対する考え方を調査したアンケート結果となります。なおアンケートは2014年にテクノロジー系の職場で実施されました。

目的

アンケートの結果から精神病かどうか判定します。

データセット

分析をするにあたって、データ自信をどう扱うか、モデルに突っ込む前に色々と処理することが重要ですが(いわゆる前処理)、そのさらに前段階でより重要なことがあります。
データの特性(カラムの意味やどんな値か)を知ることが重要です。(今回この作業が思ったより時間がかかったため、分析までいかなかったわけですが...。)

  • ファイル形式
    • CSV ファイル
    • 1259行 x 27列
  • カラムの意味
カラム名 意味
Timestamp アンケートを提出した日時
Age 回答者の年齢
Gender 回答者の性別
Country 回答者の国
state アメリカに住んでいる場合、どの州に住んでいますか?
self_employed 自営業ですか?
family_history 親族の中に精神病を患った人はいますか?
treatment メンタルヘルスケアを受けたことはありますか?
work_interfere 精神健康状態が悪いと仕事に影響しますか?
no_employees 会社または職場の人数は?
remote_work 労働時間の少なくとも50%以上はリモート(社外)で働いていますか?
tech_company テクノロジー系の会社または組織ですか?
benefits あなたの雇用主はメンタルヘルスに対する利益(手当)を提供していますか?
care_options あなたはあなたの雇用主が提供するメンタルヘルスケアに対するオプションについて認識していますか?
wellness_program あなたの雇用主は従業員の健康問題の一つとしてメンタルヘルスについて議論したことがありますか?
seek_help あなたの雇用主はメンタルヘルスの問題について学ぶためのリソースや援助の探し方を提供していますか?
anonymity あなたがメンタルヘルスあるいは薬物乱用に対する治療を受けることを選択する場合、匿名性は保護されますか?
leave メンタルヘルスに対する治療のために傷病休暇を利用することはどれくらい簡単ですか?
mental_health_consequence あなたの雇用主に精神面での健康問題について話し合うとネガティブな結果になると思いますか?
phys_health_consequence あなたの雇用主に身体面での健康問題について話し合うとネガティブな結果になると思いますか?
coworkers 職場の同僚に精神面での健康問題について話し合いたいと思いますか?
supervisor 直属の上司に精神面での健康問題について話し合いたいと思いますか?
mental_health_interview 就職候補先の面接で精神面での健康問題を提示しようと思いますか?
phys_health_interview 就職候補先の面接で身体面での健康問題を提示しようと思いますか?
mental_vs_physical あなたの雇用主は精神的健康を身体的健康と同じくらい重視していると感じますか?
obs_consequence あなたの職場で精神病になった同僚に対してネガティブな結果になったことを聞いたことや見たことはありますか?
comments 追加のメモ、コメント

目的変数

目的変数は treatment (メンタルヘルスケアを受けたことはありますか?)とします。他の変数によって、treatment を予測できるように分析します。

基礎集計

# csv ファイルの読み込み
df_data = pd.read_csv("./survey.csv")
print(df_data.columns)
# カラムの表示
"""
結果
Index(['Timestamp', 'Age', 'Gender', 'Country', 'state', 'self_employed', 'family_history', 'treatment', 'work_interfere', 'no_employees', 'remote_work', 'tech_company', 'benefits', 'care_options', 'wellness_program', 'seek_help', 'anonymity', 'leave', 'mental_health_consequence', 'phys_health_consequence', 'coworkers', 'supervisor', 'mental_health_interview', 'phys_health_interview', 'mental_vs_physical', 'obs_consequence', 'comments'], dtype='object')
"""
# 統計情報を確認
display(df_data.describe(include='all'))
# 結果は割愛

# 各カラムの中身を確認する。
for column in df_data.columns.values:
    print(column)
    print(df_data[column].unique())
"""
結果
Age
[ 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]
Gender
['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']
Country
['United States' 'Canada' 'United Kingdom' 'Bulgaria' 'France' 'Portugal' 'Netherlands' 'Switzerland' 'Poland' 'Australia' 'Germany' 'Russia' 'Mexico' 'Brazil' 'Slovenia' 'Costa Rica' 'Austria' 'Ireland' 'India' 'South Africa' 'Italy' 'Sweden' 'Colombia' 'Latvia' 'Romania' 'Belgium' 'New Zealand' 'Zimbabwe' 'Spain' 'Finland' 'Uruguay' 'Israel' 'Bosnia and Herzegovina' 'Hungary' 'Singapore' 'Japan' 'Nigeria' 'Croatia' 'Norway' 'Thailand' 'Denmark' 'Bahamas, The' 'Greece' 'Moldova' 'Georgia' 'China' 'Czech Republic' 'Philippines']
state
['IL' 'IN' nan 'TX' 'TN' 'MI' 'OH' 'CA' 'CT' 'MD' 'NY' 'NC' 'MA' 'IA' 'PA' 'WA' 'WI' 'UT' 'NM' 'OR' 'FL' 'MN' 'MO' 'AZ' 'CO' 'GA' 'DC' 'NE' 'WV' 'OK' 'KS' 'VA' 'NH' 'KY' 'AL' 'NV' 'NJ' 'SC' 'VT' 'SD' 'ID' 'MS' 'RI' 'WY' 'LA' 'ME']
self_employed
[nan 'Yes' 'No']
family_history
['No' 'Yes']
treatment
['Yes' 'No']
work_interfere
['Often' 'Rarely' 'Never' 'Sometimes' nan]
no_employees
['6-25' 'More than 1000' '26-100' '100-500' '1-5' '500-1000']
remote_work
['No' 'Yes']
tech_company
['Yes' 'No']
benefits
['Yes' "Don't know" 'No']
care_options
['Not sure' 'No' 'Yes']
wellness_program
['No' "Don't know" 'Yes']
seek_help
['Yes' "Don't know" 'No']
anonymity
['Yes' "Don't know" 'No']
leave
['Somewhat easy' "Don't know" 'Somewhat difficult' 'Very difficult'
 'Very easy']
mental_health_consequence
['No' 'Maybe' 'Yes']
phys_health_consequence
['No' 'Yes' 'Maybe']
coworkers
['Some of them' 'No' 'Yes']
supervisor
['Yes' 'No' 'Some of them']
mental_health_interview
['No' 'Yes' 'Maybe']
phys_health_interview
['Maybe' 'No' 'Yes']
mental_vs_physical
['Yes' "Don't know" 'No']
obs_consequence
['No' 'Yes']
# comments は量が多いので割愛
"""

前処理

  1. 年齢にありえない値が見られるので、外れ値とみなしてデータから除去します。
    対象:-1726, -29, -1, 329, 99999999999
  2. 性別が様々なので、M(男性)とF(女性)に統一します。
    また、どちらか判断できないものは'O'とします。
    M に変換する文字列 -> M, Male, male, m, Male-ish, maile, something kinda male?, Cis Male, Mal, Male (CIS), Make, Guy (-ish) ^_^, Male , Man, msle, Mail, cis male, Malr, Cis Man
    F に変換する文字列 -> Female, female, Trans-female, Cis Female, F, Woman, f, queer/she/they, Femake, woman, Female, cis-female/femme, Trans woman, Female (trans), Female (cis), femail
    O に変換する文字列 -> non-binary, Nah, All, Enby, fluid, Genderqueer, Androgyne, Agender, male leaning androgynous, Neuter, queer, A little about you, p, ostensibly male, unsure what that really means
  3. 欠損値の有無の確認
    欠損値が見られる場合は、no_data で補います。
  4. 使用しないカラムの削除
  5. カテゴリー変数を全てダミー変数で置き換える
# データ前処理
## 1. 外れ値の除去 (年齢が0歳以上99歳以下とする。)
df_data_new = df_data[(0<=df_data["Age"]) & (df_data["Age"]<=99)]
print(df_data_new["Age"].unique())
"""
# 結果
[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 43 56 60 54 55 48 20 57 58 47 62 51 65 49  5 53 61  8 11 72]
"""

## 2. 性別の名寄せ
df_data_new["Gender_Uni"] = df_data_new["Gender"].map({"M": "M", "Male":"M", "male":"M", "m":"M", "Male-ish":"M", "maile":"M", "something kinda male?":"M", "Cis Male":"M", "Mal":"M", "Male (CIS)":"M", "Make":"M", "Guy (-ish) ^_^":"M", "Male ":"M", "Man":"M", "msle":"M", "Mail":"M", "cis male":"M", "Malr":"M", "Cis Man":"M", "Female":"F", "female":"F", "Trans-female":"F", "Cis Female":"F", "Woman":"F", "f":"F", "F":"F", "queer/she/they":"F", "Femake":"F", "woman":"F", "Female":"F", "cis-female/femme":"F", "Trans woman":"F", "Female (trans)":"F", "Female (cis)":"F", "femail":"F", "Female ":"F", "non-binary":"O", "Nah":"O", "All":"O", "Enby":"O", "fluid":"O", "Genderqueer":"O", "Androgyne":"O", "Agender":"O", "male leaning androgynous":"O", "Neuter":"O", "queer":"O", "A little about you":"O", "p":"O", "ostensibly male, unsure what that really means":"O"})

print(df_data_new["Gender_Uni"].unique())
"""
# 結果
['F' 'M' 'O']
"""

display(df_data_new["Gender_Uni"].value_counts())
"""
# 結果
M    990
F    252
O     12
Name: Gender_Uni, dtype: int64
"""

##3. 欠損値の確認と対応
###確認
display(df_data_new.isnull().sum())
"""
Timestamp                       0
Age                             0
Gender                          0
Country                         0
state                         513
self_employed                  18
family_history                  0
treatment                       0
work_interfere                263
no_employees                    0
remote_work                     0
tech_company                    0
benefits                        0
care_options                    0
wellness_program                0
seek_help                       0
anonymity                       0
leave                           0
mental_health_consequence       0
phys_health_consequence         0
coworkers                       0
supervisor                      0
mental_health_interview         0
phys_health_interview           0
mental_vs_physical              0
obs_consequence                 0
comments                     1091
Gender_Uni                      0
dtype: int64
"""

### 欠損値を処理する
#### self_employed -> No_data
#### state -> No_data
#### work_interfere -> No_data
#### comments -> No_data
df_data_new = df_data_new.fillna({"self_employed":"No_data", "state":"No_data", "work_interfere":"No_data", "comments":"No_data"})

### 確認
display(df_data_new.isnull().sum())
"""
Timestamp                    0
Age                          0
Gender                       0
Country                      0
state                        0
self_employed                0
family_history               0
treatment                    0
work_interfere               0
no_employees                 0
remote_work                  0
tech_company                 0
benefits                     0
care_options                 0
wellness_program             0
seek_help                    0
anonymity                    0
leave                        0
mental_health_consequence    0
phys_health_consequence      0
coworkers                    0
supervisor                   0
mental_health_interview      0
phys_health_interview        0
mental_vs_physical           0
obs_consequence              0
comments                     0
Gender_Uni                   0
dtype: int64
"""

##4. 使用しないカラムの削除
### Timestamp, Gender, state, comments を削除する
### Timestamp: 回答した日時なので、精神病の判定に影響を与えるはずがない
### Gender: Gender_Uni を使用
### state: アメリカの地域によって、精神病判断に寄与する可能性はあるが、今回は使用しないことにする
### comments: 内容は判定に重要になりそうだが、今回は使用しないことにする
df_data_new = df_data_new.drop(["Timestamp", "Gender", "state", "comments"], axis=1)

##5. カテゴリー変数を全てダミー変数で置き換える
### どの変数をダミー変数とするか、確認。2値の場合は0/1でOK。

今後

ということで、今回は前処理途中で終了となってしまいました。当然前処理は大変なのですが、カラムの意味を理解するのにも思ったより時間がかかってしました。前処理では、Gender の名寄せが地味に大変でした。データの集計等も満足にできなかったので、もう少し余裕のあるときにまとめ直したいと思います。

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
3