医療職からデータサイエンティストへ医療職からデータサイエンティストへ統計学、機械学習に関する記事をまとめています。Pythonによるデータ前処理手法の網羅的まとめ2019-09-16Pythonによるデータ前処理手法の網羅的まとめPythonデータ解析をする上で、もっとも重要な工程であるデータの前処理、今回はそんな前処理をPythonで行うための様々な方法をまとめました。こんな処理も追加してほしいというご要望があれば、お気軽にコメントください(^^)Rユーザの方にはこちらをwww.medi-08-data-06.work本記事は主にこちらを参照しています。まとめ参考データセットの作成まずはデータを作成していきます。コピペして実行すれば、データセットが作成されますので、作り方は特に気にしなくて大丈夫です。今回は2019年の仮想売り上げデータを想定します。6変数は以下の通りです。列名を変更してみましょう。変数名を変更するにはrename()を使います。#idを大文字にする。6columnsとした後にdict形式で記述して、列名を変更します。引数のinplaceをTRUEとすると、実行した時点で元のデータフレームに変更が反映されます。ちなみにcolumnsではなく、indexを指定すると行名を変更することもできます。欠損値の処理データの前処理をする上で欠損値の処理はとても重要な作業です。この欠損値処理だけで本が一冊かけてしまうぐらい奥が深いものですが、今回は一番シンプルな方法で処理していきます。変数"purchase"と"purchase_num"にランダムに100個の欠損を作ります。50一番シンプルな方法は欠損値のある行を削除してしまう方法です。これにはdropna()を使います。5)もともと1000行あったデータが904行になりました。1つでも欠損があるとその行全部が削除されるため、データとしてはもったいないです。そこでfillna()を使って、それぞれの変数の平均値で補完します。int64これでデータを無駄にすることなく、欠損値を補完することができました。次は変数の追加や、編集を行ってみます。やり方があるのですが、個人的に一番スマートな書き方はassign()を使うやり方です。購入額”purchase”を購入数”purchase_num”で割って、商品一個当たりの購入単価を表す変数”purchase_one”を作ります。1172.000000今回は一変数のみの追加ですが、assign()を繋げることで、複数の変数を一気に追加することが出来ます。assign()は既存の変数の編集を行うこともできるので、先ほど作った”purchase_one”を四捨五入してみます。1172.0また、ある条件分岐にしたがって新たな変数を作りたい場合、例えば購入額によって、"upper"、"low"などの記号をつけた変数を作りたい場合は、即時関数lambdaとif文、map()を使って以下のようにします。#購入額5000円以上でhight、5000未満でlowとする。hight少しややこしいですね。map()は一つ一つの要素に関数を適応できるメソッドです。lambdaで関数を定義し、if文を1行で記述しています。上記を分解すると以下のようになります。Falseの値もし、より複雑な条件分岐をさせたい場合は、あらかじめ関数を定義しておく方が可読性が良くなります。今度は3水準に分岐させてみましょう。middleうまく変換できていますね。変数の修正はnumpyと組み合わせるともっと簡潔に書くことができます。購入額によって、"upper"、"low"ラベルを付けたい場合は、np.whereを使って以下のように書きます。"low"))先ほどのmapを使った書き方は、一つずつ値を確認しているのに対して、np.whereはベクトルで処理をしているので、True、Falseの値にベクトルで指定することもできます。条件がFalseの場合は元の購入額を入れるといった処理を行うこともできます。sales_data["purchase"]))また、複数条件でラベルづけしたい場合、np.selectを使うと実現できます。---条件での抽出(行)ある条件で、行を絞り込みたいときは、query()を使うのが良いでしょう。and(&)やor(|)などを使うことが出来ます。purchase<=1000")queryの中は文字列で指定することに注意してください。boolean型を使う方法もあり、こちらの方が速いですが、可読性や記述のしやすさから私はqueryを使っています。グルーピングと集計データの前処理では、変数とグループごとにデータを集約したい時がよくあります。お店ごとに総売上を計算してみましょう。9.252148e+05まずはgrooupby()でグルーピングする変数名を指定します。agg()で集約したい変数名と処理を書いていきます。ここでは、”store”ごとに”purchase”を”sum”するという処理をしています。ちなみにグルーピングに使った変数は行名(index)になってしまうため、reset_index()で変数として扱えるようにしています。分かりやすいように結果を変数に代入し、列名も変更しておきました。rename()を使わない方法としては、上記のような方法もあります。複数の変数に対して処理を行ったり、同じ変数に違う関数を適応したりもできます。86ここでは、お店ごとの総売上と購入額の平均値を算出し、さらにお客数もカウントしています。nunique()とは、重複無しでユニークな値の数を数える関数です。(1,1,1,2,3)という配列にnunique()を使うとユニークな値は1,2,3なので3と返ってきます。同じidを持つ人が異なる日付で購入しており、idの重複カウントを避けるためにこれを使用しています。複数のデータセットをあるルールに基づいて結合するという処理も簡単に行うことができます。2019年の上半期、下半期それぞれでお店ごとの売り上げを集約し、それを結合してみましょう。secondまずは、上半期、下半期のデータを抽出し、お店ごとの総売上を集計します。assign()を使って上半期、下半期が分かる変数を追加し、結果をそれぞれ変数に代入しました。データフレームの結合にはpandasのconcat()を使って結合しています。”axis=0”で行方向、”axis=1”で列方向に結合されます。行方向の結合は問題ないですが、列方向の結合はconcat()では痒い所に手が届かないことがあります。お店のデモグラフィックな情報(地域やCEOの名前など)を保存してあるデータセットがあるとします。それをお店の名前と紐づけて列方向に結合させるにはmerge()を使うのがベターです。Kanayamaこのデータを先ほど上半期、下半期で集計したデータと結合します。right_on”に結合を紐づける変数名を指定します。今回はどちらも”sotre”なので”on=store”と書くこともできます。”how”には結合方法を指定します。結合方法には以下のようなものがあります。long)データの横持ち型(wide)と縦持ち型(long)は、言葉で説明するのは難しいですが、この2つの型を変換したくなるときは多々あります。pythonでは、stack()、unstack()を使うこともありますが、個人的にはpivot_table()とmelt()を使う方が好きです。縦持ちから横持ちに変換していきます。使用するデータが先ほどの上半期、下半期の総売上を結合したデータです。447711少しややこしいですが、”index”には残したい変数名を、”columns”には変数にしたい列名を、”values”には、変数に対応させたい値を指定します。”index”と”columns”に対応する値が2つ以上ある場合は、pivot_table()はデフォルトで平均値を取ります。先ほどのお店のでもグラフィックデータをマージしたデータセットを使います。521730.060526ここでは、Nagoya×yearとTokyo×yearの組み合わせで重複する”purchase”があるため、平均値が計算されています。”aggfunc”を指定すれば、平均値以外を算出することもできますが、今回は省略します。複数のカラムをindexにしたい場合は、set_index()でカラムをindexに変換した後、pivot_table()を使います。447711逆に縦持ちにしたい場合はpandasのmelt()を使います。先ほど変換した"long2wide"を縦持ちにしてみます。447711pandasのmelt()では、"id_vars"で残したい変数名を、"value_vars"で縦持ちにしたい変数名を指定します。扱いは、モデル作成や解析を行う上では重要です。今回の変数"sotre"はアルファベットで記載されているため数値型に変換する必要があります。ここでは最もよく利用されるダミー変数化を行なっていきます。pythonでダミー変数化を行うにはpandasのget_dummies()を使います。0"drop_first"はダミー変数化した最初の変数(ここではダミー変数A)を除くかどうかを指定します。これが必要かというと、B,C,D,Eが全て0であればAであることが明白だからです。余分な変数はない方が良いのです。get_dummies()ではデータフレームをそのまま渡せば、文字型の変数を判断して勝手にダミー変数化してくれますが、予期しない変数まで変換されることもあるため、上記のように個別に変換を行なっています。追記その他にもよく使いそうな文字列処理をまとめてみました。多くのデータは、時系列的に格納されていることはよくあります。Pythonでは変数を日時型として扱うことで、色々便利なことができます。文字として認識されている変数"day"を日時型に変換してみましょう。pandasのto_datetime()を使います。'pandas._libs.tslibs.timestamps.Timestamp'>"str"から、"Timestamp"に変わったことが分かりますね。to_datetimeで変換すると"datetime64"型となり、dt.~~とすると年や日にち、曜日アクセスすることができます。6assignを使って、変数dayの様々な変換後の変数を作ってみました。"year"、"month"、"days"はお分かりかと思います。"week"は曜日を表し、0:日曜日~6:土曜日を表します。今回は時刻データを含んでいませんが、"dt.hour"や"dt.minutes"とすることで、時刻データを扱うこともできます。まとめデータの前処理はデータ解析の7~8割を占めるとも言われる重要な作業です。逆にここを効率的に処理することができれば、解析速度は格段に向上するでしょう。紹介しきれていない処理もありますので、こんな処理をいつもやってるよーなどがあれば、追加させて頂きます!※本記事は筆者が個人的に学んだことをまとめた記事になります。所属する組織の意見・見解とは無関係です。数学の記法や詳細な理論、用語等で誤りがあった際はご指摘頂けると幸いです。今回は主に以下の書籍を参考にさせて頂きました。前処理のみをここまで網羅的に解説した書籍は他にはないでしょう。学んだこと、日々の所感をまとめていきます。※本ブログは筆者が個人的に学んだこと感じたことをまとめたブログになります。所属する組織の意見・見解とは無関係です。medi_data0826引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。