» Python実践データ分析100本ノック | 下山輝昌, 松田雄馬, 三木孝行
はじめに
この本を手にした動機
- 元々データ分析に以前から興味があったものの、次に繋げられなかった
- 2021年10月から12月まで受講した初級Python講座で得たことをなにか繋げたかった
- 講座受講の経緯等こちら:若手エンジニア成長支援No1企業を目指して|中野ヤスオ|ARI |note
- コードを書くことが楽しくなってきたので、毎日少しづつ出来るテーマを見つけたかった
今回の読み方
- 冒頭にある「本書の効果的な使い方」を参照し、それに準拠
- 各章各ノックの内容を「写経」しつつ、本文とコードを読み進め、分からないところをGoogleで調べる感じ
- 人それぞれだが、自分は本(Kindle)とブラウザ、メモ用のエディターを横に並べるスタイルがやりやすかった
- 写経環境は「Jyupyter-Notebook」を用いたが、「Google Colaboratory(Colab)」でも全然OK!(実際最後の自然言語処理の章はColabを利用)
- 提供されている写経用ipynbファイルがとても便利だった!(下記サイトからDLできる)
- コードのメソッドや属性で初見のものがあれば、それをGoogleで検索した
- メソッドも「Python」等を付けた検索するとほぼ100%解説記事に辿りつけた
- 私が悩んだりつまづいたことほぼすべての内容について、先達が何らかの記事を書いてくれていたり公式を翻訳をしてくれている。感謝。
- ノックを1つづつ写経する前に、まずその章をざっとななめ読みしてから個別ノックの写経に入る方がよいかも
- 初心者だと各ノックのコード記述の理解で都度つまづく可能性が高い。
- 全体の流れを抑えてから個別のノックを深く理解する方が理解が速い
「Python実践データ分析100本ノック」の写経をやってみて
-
Pythonを用いたデータ分析作業がイメージできた
- 特にPandasでどんなことができるのかは少しイメージできた気がする
- 昔DBAだったころにPL/SQLでやっていた各種データパッチ作業を思い出したが、相当便利になっていると思う
- 実際のスクリプトが多く紹介されており、理解が深まりやすい
- とくに明細から特徴量を集計したテーブルを作るコード例(ノック36)などは今後参考になりそう
-
データ分析の本質を垣間見た
- 丁寧に何重もデータの中身を確認をしながら行う準備工程の大切さ、環境整備の重要性が伝わった
- そして自ら目的やアプローチの最適性を考えることの重要性が再三述べられていた
- 最新モデルでより高い精度を競えるのは随分先
- まずは何を解決するか、そしてその判断考察の元データを整えることが最優先
-
今後の目標が出来た
- イメージできたことと使いこなせるには大きなギャップがあるので、データ分析が自分の武器にできるように継続的にスキルを磨いていきたい。
この本をオススメしたい方
- Python基本的初級レベル文法は学習済みで、より具体的なコード例に多く触れたい方
- 「データ分析」や「データサイエンス」「機械学習」の具体的な実装内容や作業イメージの一端を知りたい方
以下写経しながら取ったメモです。
この本に興味がある方、そして同じようにこの本を手に取られた方にとって何か参考になればと思い、こちらに公開します。
1章
Pandasによるデータ加工/確認
- 行ユニオン(縦に結合する、concat自体は横結合も可能):
concat
- 列ジョイン(SQLで言うところの表JOIN。内部結合と外部結合もできる):
merge
- 計算列の追加:
ds['列名']=ds['列名'] * ds['列名']
- 列合計:
ds['列名'].sum()
- 欠損値(NULL値)があるかの確認:
isnull()
- 各列の最大値、最小値:
MIN()
,MAX()
- 各種統計量の表示:
describe()
- 日付型への変更:
to_datetime()
- フォーマット変換:
strftime()
- 特定列での集計:
groupby()
- クロス集計:
pivot_table()
参考記事
matplotlibによるグラフ化
- データを2次元平面に折れ線グラフや散布図形式で描画する:
matplotlib.pyplot.plot()
参考記事
2章
Pandasによるデータ加工/確認
-
クロス集計で行列が両方存在する数をカウントする:
pivot_table() aggfunc='size'
-
ユニークデータ件数(SQLでいうdistinct)をカウントする:
unique()
-
データをソートして並び替える:
sort_values()
-
1つでも欠損値が含まれているデータがあるかを判定する(行列どちらでも判断可能):
isnull().any()
-
条件に合致するデータを抽出する:
loc()
-
SettingWithCopyWarningへの対処について:VIEWとCOPY
-
SQLで言うところの副問合せUpdate文のようなイメージ
flg_is_null = uriage_data["item_price"].isnull() for trg in list(uriage_data.loc[flg_is_null, "item_name"].unique()): price = uriage_data.loc[(~flg_is_null) & (uriage_data["item_name"] == trg), "item_price"].max() uriage_data["item_price"].loc[(flg_is_null) & (uriage_data["item_name"]==trg)] = price uriage_data.head()
-
型のキャスト(文字列から数値へなど):
astype()
-
数字化文字列かの判断:
str.isdigit()
-
シリアル値から日付に変換:
to_timedelta()
- シリアル値からの日付変換はExcelとPythonで2日異なるので注意
- 最小日付がExcelは1900/01/01だがシリアル値1
― EXCELでは、本来うるう年でない1900/02/29を有効な日付にしている
- 最小日付がExcelは1900/01/01だがシリアル値1
- シリアル値からの日付変換はExcelとPythonで2日異なるので注意
文字列加工(strオブジェクトのメソッド)
- 大文字に変換する:
str.upper()
- 文字列を置換する:
replace()
参考記事
- Pandasユーザーガイド「テーブルの整形とピボットテーブル」(公式ドキュメント日本語訳) - Qiita
- Python - pandasのpivot_tableで要素ごとにカウント|teratail
- pandas.DataFrame, Seriesをソートするsort_values, sort_index | note.nkmk.me
- pandasで欠損値NaNが含まれているか判定、個数をカウント | note.nkmk.me
- pandasで任意の位置の値を取得・変更するat, iat, loc, iloc | note.nkmk.me
- DataFrameでSettingWithCopyWarningの意味と対処法 - Qiita
- pandasのデータ型dtype一覧とastypeによる変換(キャスト) | note.nkmk.me
- Pythonで文字列が数字か英字か英数字か判定・確認 | note.nkmk.me
- Pythonで日付を変換する方法|Pandasデータフレーム | Pyhoo(パイフー)
3章
Pandas
- とりあえずデータ読み込んだらこの2点
- lenで件数確認
- head()で先頭5行を見る
- ジョインした時は件数確認
- ジョインが失敗すると自動的に欠損値が入る。欠損値確認を行うこと
- NaTはdatetime型の欠損値を指す
- ある特徴を見出しその条件に符号するデータにフラグを立てていく
- 例えば習慣化されている人
- 同じ曜日が4回以上ある月が1か月でもある人
- 曜日を知りたい:
dt.weekday()
- 欠損値を一律の値で置き換える:
fillna()
- 日付期間の計算、特に月単位でカウントする場合:
dateutil.relativedelta()
参考記事
- PandasでSeries.dt()を使って日付を変換する方法 - Qiita
- pandasで欠損値NaNを除外(削除)・置換(穴埋め)・抽出 | note.nkmk.me
- Python 日付、時刻の処理 - Qiita
4章
クラスタリング(K-means法)
- データ分析の1つの手法として対象データのグループ化がある。どうやってグループ化するかどうかには正解はない。
- そんな時は教師なし学習のクラスタリングが効果的
- scikit-learnライブラリを使用
- 最もオーソドックスなクラスタリング手法 K-means法
- 変数間の距離をベースにグルーピング
- クラスタリングにはまず対象データの「標準化」が必要
- 「標準化」とは、項目間の値の絶対値のばらつきの違いによって発生するAI(人工知能)が認識する重要性の違いを取り除くこと
- 標準化された値 = (元の値 - 平均) / 標準偏差
- sclit-learnの
standardscaler()
を使うと簡単に標準化が行える - 可視化のためには二次元まで次元を減らす。次元削除の代表的な手法が主成分分析:PCA()
- 新たな軸がどの変数から成り立っていくかを見ていくと軸の意味付けが出来る。
線形回帰
- 予測のための回帰モデルとして線形回帰モデルを利用する
- scikit-learnの
LinearRegression()
- scikit-learnの
- 予測モデルの構築には学習用データと評価用データが必要
- 所与のデータを教師データと評価データに分割する
train_test_split()
- 無指定の場合評価用が25%になる
- 所与のデータを教師データと評価データに分割する
- 作成したモデルを用意した教師データで学習させる
-
model.fit(x, y)
を利用する - 予測に使う変数x:説明変数
- 予測したい変数y:目的変数
-
- 学習用データで作成したモデルを評価用データにあてて精度を検証する
LinearRegression.score()
- 寄与している変数の寄与度(係数)を確認する
model.coef_
- 予測する
model.predict
Pandas
- グループ別の集計を行う:
groupby().cout()
- indexの見せ方を変える:
as_index=False
- indexの見せ方を変える:
- 欠損値を含むデータを削除する:
dropna()
参考記事
-
Pythonの機械学習ライブラリ「scikit-learn」で実践する「教師あり学習」「教師なし学習」:Pythonで始める機械学習入門(7)(3/3 ページ) - @IT
「KMeans」クラスのインスタンス化時の引数「n_cluster」でクラスタ数を指定しています。これで学習が終わり、結果は「labels_」というメンバ変数に入っています。
-
pythonで主成分分析(Scikit-learn版,pandas&numpy版)(【高等学校情報科 情報Ⅱ】教員研修用教材) - Qiita
-
groupby を使うと、デフォルトでグループラベルが index になる。index にしたく無い場合は as_index=False を指定する。
-
Pythonでファイル名の前後に文字列や連番を加えて一括変更 | note.nkmk.me
tmp_before.rename(columns={"count":"count_{}".format(j-1)}, inplace=True)
-
Pandasでnan値を削除、穴埋めするfillna、dropnaの使い方 - DeepAge
DataFrameだとデフォルトの設定でdropnaを適用すると欠損値を1つでも含む行は削除されます。
-
scikit-learnでデータを訓練用とテスト用に分割するtrain_test_split | note.nkmk.me
5章
決定木分析
- ノック42でエラーが出たが以下のページで解決
- 事前準備
- 退会者データと継続者データをそのまま並べると不均衡なのでバランスを取る
- 欠損値対応(機械学習は欠損値があると対応できない)
- 文字列データ(カテゴリカル変数)のダミー変数化
- 文字列データを一括でダミー変数化:
pd.get_dummies
-
pandasでカテゴリ変数をダミー変数に変換(get_dummies) | note.nkmk.me
- カテゴリの数が限定されている場合、例えば3つの場合は2つが0なら最後が1と決まる。重複した意味を持つ場合は列を削除する
- 文字列データを一括でダミー変数化:
- ここまで準備できて初めてモデル化へ「データ分析はデータ加工が8割」
- 決定木モデル構築
DecisionTreeClassifier
- scikit-learn で決定木分析 (CART 法) – Python でデータサイエンス
- モデルの評価とチューニング
- 学習データと評価データの精度を比較する。その差が少ないのが理想。
- 学習データの精度の方が高い場合はそのモデルは過学習傾向にある(学習データに寄り過ぎている)
- 今回は決定木の深さで制御する
-
max_depth
属性
-
- モデルに寄与している変数の確認
model.feature_importances_
- 決定木の可視化:
GraphViz
6章
ネットワーク最適化/NetworkX
- グラフの可視化
-
グラフオブジェクトの作成:
G=nx.Graph()
-
頂点の設定:
G.add_node()
-
辺の設定:
G.add_edge("nodeA","nodeB")
-
座標の設定:
pos["nodeA"]=(0,0)
-
描画:
nx.draw(G,pos)
、plt.show()
-
【図解】Python NetworkXの使い方【サンプルコード有】 | ネットワーク分析・可視化 - YutaKaのPython教室
-
- 最適化問題とは、「目的関数」を「制約条件」の元で解くこと
numpy
- 要素の値が全てゼロの配列を作成する:
np.zeros()
7章
Ptyhonにおける数理最適化を行う上での概要(主にPuLP)
-
Pythonを使った最適化全般に対するわかりやすい解説(参考サイト多数掲載あり)
-
主に以下のライブラリを利用する
-
pulp
-
ortoolpy
-
ライブラリのインストール
pip install -U pulp
pip install -U ortoolpy
-
PuLPについて
- PuLPは、数理モデリングのパッケージ
最適化計算とは
詳細な定義とは言えないが、非常に乱暴だが自己理解を言語化すると以下の通り。
- 数理モデルの作成
- 最大化と最小化がある
- 変数の定義
- 変数はdict形式で与える
- 目的関数の設定
- モデルに数式を追加(
+=
)していくイメージ - 輸送問題の場合は、各輸送コストと変数v1の要素の積の和として目的関数を定義する。
- モデルに数式を追加(
- 制約の追加
- 目的関数と同じくモデルに数式を追加(
+=
)していくイメージ
- 目的関数と同じくモデルに数式を追加(
- ソルバーの実行
参考記事
サンプルコードを読み解く上で参考になったサイト(特にPython文法およびメソッドの使い方関連)
-
乱数のシード:
np.random.seed(1)
コンピュータで乱数を生成する場合、ある数値をシード値(seed:種)として用い、その値を基にして特定の演算により乱数を生成していく。このため同じシード値を使用した場合、発生する乱数はまったく同じものとなる。
numpy.random.seed(seed=シードに用いる値) をシード (種) を指定することで、発生する乱数をあらかじめ固定することが可能です。乱数を用いる分析や処理で、再現性が必要な場合などに用いられます。
-
入力イテラブルのデカルト積(直積)を作る:
itertools.product()
-
連続した数字要素を作る:
range()
-
1行のforループ→辞書内包表記
-
辞書オブジェクトのすべてのKEYと値を取得する:items()
Pythonの辞書(dict)のforループ処理(keys, values, items) | note.nkmk.me -
特にノック61のサンプルソースは手ごわかったので他の方の解説記事が参考になった
8章
ネットワーク分析
-
基本は6章と同じ。
-
感覚を数式やグラフを使って可視化定型化する価値は確かに非常に高いと感じる。
-
グラフ描画する:
draw_networkx()
- リンクの多いものが中心に集まるように自動的に位置を決定
-
ヒストグラムを書く:
hist()
Python Tips
- 両端の文字を削除する:
strip()
9章(画像認識)
OpenCV
-
画像や動画を処理するための機能がまとめて実装されているオープンソースのライブラリ
-
No module named 'cv2'の解決
pip install opencv-python
-
画像ファイルを読み込む:
cv2.imread("img/img01.jpg")
-
映像データを読み込む:
cv2.VideoCapture("mov/mov01.avi")
-
ヒトの認識:HOG特徴量(輝度勾配)
- 人物を検知するための関数:
cv2.HOGDescriptor_getDefaultPeopleDetector()
- 人物を検知するための関数:
-
顔や目の検出:
CascadeClassifier()
-
OpenCV - カスケード分類器 CascadeClassifier で画像から顔や目を検出する方法について - pystyle
- 顔の正面、目やメガネ、鼻など様々なフィルターファイルがopenCVには標準で用意されている。
- フィルターファイルを
- OpenCV 使用可能なCascadeClassifierの種類と効果 - Symfoware
-
OpenCV - カスケード分類器 CascadeClassifier で画像から顔や目を検出する方法について - pystyle
-
画像から動画を作成する:
cv2.VideoWriter()
-
映像からの人の検出結果をデータフレームとして保存、可視化
- フレーム番号をFPS(一秒あたりのフレーム数)で割ると経過時間が計算できる
-
時系列データの細かなノイズを取り傾向を見るのに、移動平均を使う
-
その他参考記事
-
【入門者向け解説】openCV顔検出の仕組と実践(detectMultiScale) - Qiita
- openCVを使った画像検出の事例や解説
-
【入門者向け解説】openCV顔検出の仕組と実践(detectMultiScale) - Qiita
※なおdlib
はインストールが必要になったため割愛した
【python】Windowsにdlibをインストールする - ソースに絡まるエスカルゴ
Python Tips
-
可変長引数について:引数を変数化して受け渡す時に使える。
**
を付けるhogParams = {'winStride': (8, 8), 'padding': (32, 32), 'scale': 1.05, 'hitThreshold':0, 'finalThreshold':5} human, r = hog.detectMultiScale(gray, **hogParams)
10章(自然言語処理)
前処理
-
アンケート結果の特徴を捉え、適宜分析前加工する
- 件数
- 欠損値
- 表記ゆれ
- 回答の長さ
-
データフレームの文字列置換:
str.replace()
-
regex=True
とすることで正規表現パターンマッチングが使える
形態素解析
-
単語に分解する技術
- MeCabやJanome
-
ローカルPC環境にMeCab環境の構築が難しかったので、Google Colab上で実行することにした
-
アンケートの分析の手順
- 形態素解析
- 名詞や動詞の抽出
- 頻出する言葉の抽出、可視化、特徴量化
- 類似性
-
文書の類似性の判断→コサイン類似度を用いることが多い