【学習記録】Python データサイエンスハンドブック(45)
オライリーの「Pythonデータサイエンスハンドブック」の学習記録
3.12.7 事例:シアトル市の自動車数を可視化する。
#ファイル名を指定してcurlで保存する場合は「-o」を使う。備忘録参照。 In [69]: !curl -o FremontBridge.csv https://data.seattle.gov/api/views/65db-xm6k/ro ...: ws.csv?accessType=DOWNLOAD % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1679k 0 1679k 0 0 347k 0 --:--:-- 0:00:04 --:--:-- 378k In [71]: data=pd.read_csv('FremontBridge.csv') In [79]: data.columns Out[79]: Index(['Date', 'Fremont Bridge East Sidewalk', 'Fremont Bridge West Sidewalk'], dtype='object') #Dateをdataのインデクスに指定する。 In [81]: data=data.set_index('Date') In [82]: data.head() Out[82]: Fremont Bridge East Sidewalk \ Date 01/01/2019 12:00:00 AM 0.0 01/01/2019 01:00:00 AM 2.0 01/01/2019 02:00:00 AM 1.0 01/01/2019 03:00:00 AM 1.0 01/01/2019 04:00:00 AM 2.0 Fremont Bridge West Sidewalk Date 01/01/2019 12:00:00 AM 9.0 01/01/2019 01:00:00 AM 22.0 01/01/2019 02:00:00 AM 11.0 01/01/2019 03:00:00 AM 2.0 01/01/2019 04:00:00 AM 1.0 #列名を短くする。 In [83]: data.columns=['West','East'] #WestとEastの合計の列(TOtal)を追加する。 In [84]: data['Total']=data.eval('West+East') In [85]: data.head() Out[85]: West East Total Date 01/01/2019 12:00:00 AM 0.0 9.0 9.0 01/01/2019 01:00:00 AM 2.0 22.0 24.0 01/01/2019 02:00:00 AM 1.0 11.0 12.0 01/01/2019 03:00:00 AM 1.0 2.0 3.0 01/01/2019 04:00:00 AM 2.0 1.0 3.0 #dataの要約統計を見てみる。 In [86]: data.dropna().describe() Out[86]: West East Total count 59823.000000 59823.000000 59823.000000 mean 52.619795 60.262324 112.882119 std 67.734326 87.871363 143.101423 min 0.000000 0.000000 0.000000 25% 6.500000 7.000000 15.000000 50% 29.000000 30.000000 61.000000 75% 70.000000 73.000000 147.000000 max 698.000000 850.000000 1097.000000
3.12.7.1 データの可視化を行う。
#単純にプロットしてみる。 #インデクスが見た目は時系列だけど、dypeはobjectになっているので、思ったようなグラフにならない。 In [87]: %matplotlib Using matplotlib backend: TkAgg In [88]: import seaborn; seaborn.set() In [89]: data.plot() Out[89]: <matplotlib.axes._subplots.AxesSubplot at 0x7f7e7aa4bfd0> In [90]: plt.ylabel('Hourly Bicycle Count') Out[90]: Text(27.625, 0.5, 'Hourly Bicycle Count') In [93]: data.index Out[93]: Index(['01/01/2019 12:00:00 AM', '01/01/2019 01:00:00 AM', '01/01/2019 02:00:00 AM', '01/01/2019 03:00:00 AM', '01/01/2019 04:00:00 AM', '01/01/2019 05:00:00 AM', '01/01/2019 06:00:00 AM', '01/01/2019 07:00:00 AM', '01/01/2019 08:00:00 AM', '01/01/2019 09:00:00 AM', ... '12/06/2016 12:00:00 AM', '01/22/2016 08:00:00 PM', '04/04/2017 01:00:00 AM', '01/18/2013 04:00:00 AM', '01/12/2017 04:00:00 AM', '02/29/2016 12:00:00 AM', '09/13/2013 03:00:00 AM', '12/07/2016 12:00:00 AM', '03/29/2013 04:00:00 AM', '05/24/2017 01:00:00 AM'], dtype='object', name='Date', length=59832)
#インデクスの dtypeをdatetime64に変換してからプロットする。 #思い通りのグラフができる。 In [95]: data.index=pd.DatetimeIndex(data.index) In [96]: data.index Out[96]: DatetimeIndex(['2019-01-01 00:00:00', '2019-01-01 01:00:00', '2019-01-01 02:00:00', '2019-01-01 03:00:00', '2019-01-01 04:00:00', '2019-01-01 05:00:00', '2019-01-01 06:00:00', '2019-01-01 07:00:00', '2019-01-01 08:00:00', '2019-01-01 09:00:00', ... '2016-12-06 00:00:00', '2016-01-22 20:00:00', '2017-04-04 01:00:00', '2013-01-18 04:00:00', '2017-01-12 04:00:00', '2016-02-29 00:00:00', '2013-09-13 03:00:00', '2016-12-07 00:00:00', '2013-03-29 04:00:00', '2017-05-24 01:00:00'], dtype='datetime64[ns]', name='Date', length=59832, freq=None) In [97]: data.plot() Out[97]: <matplotlib.axes._subplots.AxesSubplot at 0x7f7e593aaa20> In [98]: plt.ylabel('Hourly Bicycle Count') Out[98]: Text(22.375, 0.5, 'Hourly Bicycle Count')
#毎時データではギザギザなので、毎週データに再サンプリングする。 In [99]: weekly=data.resample('W').sum() In [100]: weekly.plot(style=[':','--','-']) Out[100]: <matplotlib.axes._subplots.AxesSubplot at 0x7f7e4c597b38> In [101]: plt.ylabel('Weekly bicycle count') Out[101]: Text(12.500000000000002, 0.5, 'Weekly bicycle count') In [102]: weekly.head() Out[102]: West East Total Date 2012-10-07 7297.0 6995.0 14292.0 2012-10-14 8679.0 8116.0 16795.0 2012-10-21 7946.0 7563.0 15509.0 2012-10-28 6901.0 6536.0 13437.0 2012-11-04 6408.0 5786.0 12194.0
#30日間の移動平均を行い、1日当たりの平均を求める #30日間の合計のグラフを作成する。 In [103]: daily=data.resample('D').sum() In [104]: daily.head() Out[104]: West East Total Date 2012-10-03 1760.0 1761.0 3521.0 2012-10-04 1708.0 1767.0 3475.0 2012-10-05 1558.0 1590.0 3148.0 2012-10-06 1080.0 926.0 2006.0 2012-10-07 1191.0 951.0 2142.0 In [105]: daily.rolling(30,center=True).sum().plot(style=[':','--','-']) Out[105]: <matplotlib.axes._subplots.AxesSubplot at 0x7f7e4c4c2828> In [106]: daily.rolling(30,center=True).sum().plot(style=[':','--','-']) Out[106]: <matplotlib.axes._subplots.AxesSubplot at 0x7f7e7acbbf60> In [107]: plt.ylabel('mean hourly count') #これはたぶん図書の誤植で、mean every 30 days countが正しい。 Out[107]: Text(2.8750000000000018, 0.5, 'mean hourly count')
#窓関数をガウス窓にすると、滑らかな移動平均を求めることが可能。 #↓のコードでは、ウィンドウの幅(50日)とウインドウ内のガウスの幅(10日)の両方を指定している(←要学習。) In [108]: daily.rolling(50,center=True, win_type='gaussian').sum(std=10).plot(style ...: =[':','--','-']) Out[108]: <matplotlib.axes._subplots.AxesSubplot at 0x7f7e4c1f4898>
Pythonデータサイエンスハンドブック ―Jupyter、NumPy、pandas、Matplotlib、scikit-learnを使ったデータ分析、機械学習
- 作者: Jake VanderPlas,菊池彰
- 出版社/メーカー: オライリージャパン
- 発売日: 2018/05/26
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
【備忘録】curl optionのo(小文字)とO(大文字)の違い
ダウンロードしたファイルに任意のファイル名を付けて保存
・ !curl -o XXXX.csv https://XXXXXXX
【備忘録】IPythonのターミナルを一時中断してシェルに戻って、再びIPythonを途中から再開する方法
IPythonのターミナルを一時中断してシェルに戻る方法
・IPython上でCtrl+Z
シェルから中断していたIPythonを途中から再開する方法
・シェル上でfgとタイプしてエンターする。
【備忘録】Bash on Windowsのルートディレクトリの場所とhomeの場所
ルートディレクトリの場所
C:\Users\%WindowsUSERNAME%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs
bashのhomeとユーザーの場所
C:\Users\%WindowsUSERNAME%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home\%LinuxUSERNAME%
メモ:Bash on Windows上でAnaconda3をインストールしてIPythonを使用している場合、Anaconda3のデータは↑のbash上のhome\%LinuxUSERNAME%にある。
参考にしたサイト
WSL(旧:Bash on Windows)のルートディレクトリが無い - しらとりのブログ
How to Access Your Ubuntu Bash Files in Windows (and Your Windows System Drive in Bash)
【備忘録】Python(2) lambdaの使い方
lambdaの使い方。
引用したサイト
【Python入門】lambda(ラムダ式)の使い方 | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト
#lambda式の形式 lambda 引数:処理内容 #税込み価格を求めるlambda式 prices = [3000,2500,10500,4300] paymentList = list(map(lambda price:price * 1.08 , prices)) print(paymentList) #if文処理のlambda式 prices = [3000,2500,10500,4300] priceList = list(filter(lambda price:price > 3500, prices)) priceList.sort() print(priceList)
【kaggle】タイタニックのコンペ(5)
Kaggleで定番のタイタニック号の生存者の分析をPythonで行う記録。
↓コンペのサイトはここです。
Titanic: Machine Learning from Disaster | Kaggle
Pythonによる分析の一例をManav Sehgalさんのカーネルを参考に(と言いうかこれに沿って)行います。
↓Manav Sehgalさんの分析手順はここで確認ができます。
Titanic Data Science Solutions | Kaggle
17.データラングリング
・今までの分析の結果、様々な予想を立てることができた。
・データはいじらずに分析をしてきたが、ここではデータ自体をいじる。
17.1.不要な属性を取り除く
・部屋番号(Cabin)とチケット(Ticket)はそこまで重要じゃなさそう。
・データラングリングするときは、トレーニングデータセットとテストデータセットの両方に対して同じ操作を行う。
In [18]: train_df.shape Out[18]: (891, 12) In [20]: test_df.shape Out[20]: (418, 11) In [22]: train_df=train_df.drop(['Ticket','Cabin'],axis=1) In [23]: train_df.shape Out[23]: (891, 10) In [24]: test_df=test_df.drop(['Ticket','Cabin'],axis=1) In [25]: test_df.shape Out[25]: (418, 9) In [27]: combine[1].shape Out[27]: (418, 11) In [28]: combine=[train_df, test_df] In [29]: combine[1].shape Out[29]: (418, 9)
17.2.新しい属性を既存のデータから抽出、作成する。
・名前の肩書と生存率の相関を調べたい。
・The RegEx pattern (\w+\.)を使って肩書を抽出する。
In [32]: for dataset in combine: ...: dataset['Title']=dataset.Name.str.extract('([A-Za-z]+)\.',expand=False) ...: pd.crosstab(train_df['Title'],train_df['Sex']) Out[32]: Sex female male Title Capt 0 1 Col 0 2 Countess 1 0 Don 0 1 Dr 1 6 Jonkheer 0 1 Lady 1 0 Major 0 2 Master 0 40 Miss 182 0 Mlle 2 0 Mme 1 0 Mr 0 517 Mrs 125 0 Ms 1 0 Rev 0 6 Sir 0 1 In [33]: for dataset in combine: ...: dataset['Title']=dataset.Name.str.extract('([A-Za-z]+)\.',expand=False) In [42]: for dataset in combine: ...: dataset['Title']=dataset['Title'].replace(['Lady','Countess','Capt',\ ...: 'Col','Don','Dr','Major','Rev','Sir','Jonkheer','Dona'],'Rare') ...: dataset['Title']=dataset['Title'].replace('Mlle','Miss') ...: dataset['Title']=dataset['Title'].replace('Ms','Miss') ...: dataset['Title']=dataset['Title'].replace('Mme','Mrs') In [43]: train_df[['Title','Survived']].groupby(['Title'],as_index=False).mean() Out[43]: Title Survived 0 Master 0.575000 1 Miss 0.702703 2 Mr 0.156673 3 Mrs 0.793651 4 Rare 0.347826 In [44]: title_mapping={'Mr':1,'Miss':2,'Mrs':3,'Master':4,'Rare':5} In [45]: for dataset in combine: ...: dataset['Title']=dataset['Title'].map(title_mapping) ...: dataset['Title']=dataset['Title'].fillna(0) ...: In [46]: train_df.head() Out[46]: PassengerId Survived Pclass \ 0 1 0 3 1 2 1 1 2 3 1 3 3 4 1 1 4 5 0 3 Name Sex Age SibSp \ 0 Braund, Mr. Owen Harris male 22.0 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 2 Heikkinen, Miss. Laina female 26.0 0 3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 4 Allen, Mr. William Henry male 35.0 0 Parch Fare Embarked Title 0 0 7.2500 S 1 1 0 71.2833 C 3 2 0 7.9250 S 2 3 0 53.1000 S 3 4 0 8.0500 S 1 #敬称を抽出したので、名前は不要になった。なので、取り除く。 #トレーニングデータからID番号も不要なので取り除く。 #テストデータでは最後の予測にIDと紐づけるためそのままにしておく。 In [47]: train_df=train_df.drop(['Name','PassengerId'],axis=1) In [48]: test_df=test_df.drop(['Name'],axis=1) In [49]: combine=[train_df,test_df] In [50]: train_df.shape, test_df.shape Out[50]: ((891, 9), (418, 9))
17.3.定性型属性を数字に変換する。
・文字列データを数字データに変換する。多くの予測モデルのアルゴリズムでは数字データにしておく必要がある。
・性別を男性0、女性1に変換する。
In [52]: for dataset in combine: ...: dataset['Sex']=dataset['Sex'].map({'female':1,'male':0}).astype(int) In [53]: train_df.head() Out[53]: Survived Pclass Sex Age SibSp Parch Fare Embarked Title 0 0 3 0 22.0 1 0 7.2500 S 1 1 1 1 1 38.0 1 0 71.2833 C 3 2 1 3 1 26.0 0 0 7.9250 S 2 3 1 1 1 35.0 1 0 53.1000 S 3 4 0 3 0 35.0 0 0 8.0500 S 1
【kaggle】タイタニックのコンペ(4)
Kaggleで定番のタイタニック号の生存者の分析をPythonで行う記録。
↓コンペのサイトはここです。
Titanic: Machine Learning from Disaster | Kaggle
Pythonによる分析の一例をManav Sehgalさんのカーネルを参考に(と言いうかこれに沿って)行います。
↓Manav Sehgalさんの分析手順はここで確認ができます。
Titanic Data Science Solutions | Kaggle
14.今までの分析結果から、生存の有無について予測する。
14.1.相関(Correlating)
・予測したいことは各乗客の生存の有無である。よって、各属性データと生存の有無の相関を早い段階で確認する。
14.2.補完(Completing)
・生存の有無を予測する際に、年齢が重要な属性の場合、その欠損値を埋める必要があるかもしれない。
・乗船港も生存の有無や他の要素と相関がある可能性がるため、欠損値を埋める必要があるかもしれない。
14.3.補正(Correcting)
・チケットの属性はデータセットから取り除いてもよいかもしれない。22%のチケットに同じ名称であり、チケットの名称は生存の有無に関係ないかもしれないから。
・客室の情報も取り除いてもよかもしれない。客室の情報の多くは、トレーニングデータセットとテストデータセットにおいて、未完またはNull値であるため、
・乗客のID番号も取り除いてもよいかもしれない。ID番号は生存の有無とは関係が関係ない可能性があるため。
・乗客の名前のデータも取り除いてもよいかもしれない。全員が違う名前であり、標準化されていないため。
14.4.作成(Creating)
・ParchとSibSbデータを元に、家族(Family)のデータを作りたい可能性がある。
・名前のデータから、肩書(Mr.など)を抽出したいかもしれない。
・年齢をカテゴリー化したデータを作りたいかもしれない。つまり、定量データを順序尺度の定性データに変更したい。
・料金をカテゴリー化したデータを作りたいかもしれない。つまり、定量データを順序尺度の定性データに変更したい。
14.5.分類(Classifying)
・問題の背景や条件から、予測をすることもできる。
・女性は男性よりも生存率が高い。
・何歳以下の子どもは生存率が高い。
・等級が高い乗客(Pclass=1)は生存率が高い。
15.属性をピボットして分析する。
・今までの観測と推測を確かめるために、属性同士をピボットして簡単に分析することができる。
・この時点では、Null値がないデータのみを扱う。
・この時点では、名義尺度(性別)、順序尺度(等級)、離散変数(兄弟姉妹・配偶者の数、両親・子供の数)のみ扱う。
#データフレームの引数に属性を入れると、その属性のみを示したデータセットが表示される。 In [27]: train_df[['Pclass','Survived']] Out[27]: Pclass Survived 0 3 0 1 1 1 2 3 1 3 1 1 4 3 0 .. ... ... 886 2 0 887 1 1 888 3 0 889 1 1 890 3 0 [891 rows x 2 columns] #等級と生存率には高い相関が確認された。 #よって、等級を予測モデルの属性に含める。 In [30]: train_df[['Pclass','Survived']].groupby(['Pclass'],as_index=False).mean(). ...: sort_values(by='Survived', ascending=False) Out[30]: Pclass Survived 0 1 0.629630 1 2 0.472826 2 3 0.242363 #性別と生存率も高い相関が確認された。 In [31]: train_df[['Sex','Survived']].groupby(['Sex'],as_index=False).mean().sort_v ...: alues(by='Survived',ascending=False) Out[31]: Sex Survived 0 female 0.742038 1 male 0.188908 #兄弟姉妹・配偶者の数(SibSp)と両親・子供の数(Parch)は幾つかの属性値で、相関が0である。 #そのため、14.4.作成(Creating)に示したとおり、家族(Family)という新しい属性を作ってから分析した方がいいかもしれない。 In [34]: train_df[['SibSp','Survived']].groupby(['SibSp'],as_index=False).mean().so ...: rt_values(by='Survived',ascending=False) Out[34]: SibSp Survived 1 1 0.535885 2 2 0.464286 0 0 0.345395 3 3 0.250000 4 4 0.166667 5 5 0.000000 6 8 0.000000 In [36]: train_df[['Parch','Survived']].groupby(['Parch'],as_index=False).mean().so ...: rt_values(by='Survived',ascending=False) Out[36]: Parch Survived 3 3 0.600000 1 1 0.550847 2 2 0.500000 0 0 0.343658 5 5 0.200000 4 4 0.000000 6 6 0.000000
16.データを視覚化する。
・視覚化によって、引き続き今までの観測と推測を確認する。
#定量型属性の相関を確認する。 #生存率と年齢の関係を確認する。 In [51]: g=sns.FacetGrid(train_df,col='Survived') In [52]: g.map(plt.hist, 'Age',bins=20) Out[52]: <seaborn.axisgrid.FacetGrid at 0x7f3d106e34e0> #4歳以下の子どもの生存率は高い。 #80歳の乗客は生き残った。 #15歳から25歳の乗客の多くは亡くなった。 #★この分析の結論 #年齢を予測モデルに組み込むべき。 #年齢がNull値のデータは補完する必要がある。 #年齢を一定のグループ分けにするべき。
#定量型属性と順序尺度属性の相関を確認する。 In [54]: grid=sns.FacetGrid(train_df,col='Survived',row='Pclass',height=2.2,aspect= ...: 1.6) In [55]: grid.map(plt.hist,'Age',alpha=.5,bins=20) Out[55]: <seaborn.axisgrid.FacetGrid at 0x7f3cfb63f390> In [56]: grid=sns.FacetGrid(train_df,col='Survived',row='Pclass',height=2.2,aspect= ...: 1.6) In [57]: grid.map(plt.hist,'Age',alpha=.5,bins=20) Out[57]: <seaborn.axisgrid.FacetGrid at 0x7f3cfb63f5f8> In [58]: grid.add_legend() Out[58]: <seaborn.axisgrid.FacetGrid at 0x7f3cfb63f5f8> #乗客は等級3が最も多く、亡くなった乗客も等級3が多い。 #等級2と3の幼児の大半は生き残った。 #等級1の乗客の多くは生き残った。 #各等級内の年齢の分布は異なる。 #★この分析の結論 #等級を予測モデルに取り込む。
#定性データの相関 In [60]: grid=sns.FacetGrid(train_df, row='Embarked',height=2.2,aspect=1.6) In [61]: grid.map(sns.pointplot,'Pclass','Survived','Sex',palette='deep',order=[1,2,3],hue_order=['male','female']) Out[61]: <seaborn.axisgrid.FacetGrid at 0x7f3cfb775ac8> In [62]: grid.add_legend() Out[62]: <seaborn.axisgrid.FacetGrid at 0x7f3cfb775ac8> #女性は男性よりも生存率が高い。 #港Cからの乗客は例外的に男性の方が生存率が高い。これは、港と等級の相関がある可能性を示唆している。 #港Cと港Qの等級3の生存率は比較的高い。 #港と生存率を大きく相関している。 #★この分析の結論 #性別を予測モデルに取り入れる。 #港属性のデータのNull値を埋め、港属性を予測モデルに取り入れる。
#定性型属性と定量型属性の相関を確認する。 In [64]: grid=sns.FacetGrid(train_df,row='Embarked',col='Survived',height=2.2,aspec ...: t=1.6) In [65]: grid.map(sns.barplot,'Sex','Fare',alpha=.5,ci=None,order=['female','male']) Out[65]: <seaborn.axisgrid.FacetGrid at 0x7f3cfb25f320> In [66]: grid.add_legend() Out[66]: <seaborn.axisgrid.FacetGrid at 0x7f3cfb25f320> #高い料金を支払っている乗客は生存率が高い。料金をカテゴリー化したデータを作る。 #港と生存率は相関がある。港のNull値を埋める。 #★この分析の結論 #定量データの料金を区分化したデータを新たに作成する。