学習方法

データサイエンティストに必須な技術を学ぼう!pandasの操作方法とは?

データサイエンスとは?  

               

データサイエンスとはデータ収集や、データから利用価値の高い情報を抽出する原理と方法をまとめた用語です。データサイエンスを利用することで、慣習や勘では解決できなかった問題解決の方法を、自動的に発見することができます。

次に情報の抽出原理と方法について紹介します。

情報の抽出は、傾向からデータパターンやモデルを作成することが最終的な目標です。情報の抽出ですが、これまでは統計学やスコアリングの手法が一般的でした。

近年では、コンピュータの性能が飛躍的に向上していることから、ディープラーニングや機械学習が注目されています。(むしろ最近のデータ分析方法はこちらの方が中心です)。

特にディープラーニングは人の脳細胞(ニューロン)を模したプロクラムが、自動的に収集したデータを学習することで、人間では発見できなかったデータの傾向を見つける方法です。

しかし、上記で紹介した事例はあくまで方法です。データを抽出した後は、パターンやモデルの評価と修正が必要です。

例えば、テストデータを使用して分析した結果が、作成したパターンと一致するか評価し、一致しない場合はデータの抽出方法を修正する必要があります。

データサイエンスにおけるデータ処理の重要性   

データサイエンスを行うためには大量のデータ利用が必須であり、データ処理には“柔軟性”と“高速性”が求められます。

柔軟性についてご説明します。

人間が分析するデータではデータフォーマットが統一されていることが多いですが、データサイエンスに用いるデータはフォーマットがバラバラでエラーの原因となり、そのままではプログラムに利用できません。

例えば、テキストデータであるstr形と数値であるint形の加算を行うとTypeErrorエラーとなり、エラー以降の処理が進みません。このようなエラーはpythonのデータ処理で頻繁に発生します。

また、webからダウンロードしたデータは欠損値が多く、NaN(Not a Number)やNoneが含まれています。データ処理方法によってはNaN値とNoneの扱いが異なったり、0除算の原因となるため事前に前処理が必要です。

上記のようになるのは、Webスクレイピングによってブラウザ上からデータをダウンロードし、異なるデータフォーマットを変換してデータを結合することが原因です。柔軟にデータを扱える方法を確立する必要があります。 

続いて高速性です。

データサイエンスに使用されるデータの項目数は数万〜数百万点に及ぶことが普通で、加減算や逆行列計算などを頻繁に行います。

そのため、一回の計算に少しでも時間がかかると、データ処理のみに多くの時間がかかってしまい、データサイエンスの本質的な業務である『データ傾向の抽出』を行えません。

pythonはインタプリタ型プログラミング言語であるため、for文や繰り返し処理を利用すると、データ処理速度が格段に遅くなるため、高速にデータ処理を行う工夫が必要です。

上記2点の問題を解決するために作成されたモジュールが『pandas』となります。次章ではpandasについて説明していきます。 

pandasの概要

pandasはNumPyと同時利用を前提に考案されたデータ処理用のモジュールです。NumPyは整理されたデータ処理には強力なツールであるものの、フォーマットが整理されていないデータに対する柔軟性や、データの結合に関しては難がありました。

pandasでは複数のDataframeやデータ構造を採用することで、データ処理の柔軟性が格段に上昇しています。

NumPyを元にしたモジュールであるため配列・ベクトル演算が扱えます。これは大量のデータに繰り返し計算を用いる必要が無い事を示しており、作業の高速化を行えます。また、データの結合や分離もpandasはスムーズに行うことができます。

pandasの操作方法を動かしながら体験してみよう

 本項目では具体的なpandasの操作方法をご説明します。プログラムを理解するには実際に手を動かすのが一番であるため、皆さんも開発環境を用意して進めてください。

なお、これから使用するプログラムは次の参考文献を参照しています。

『オライリージャパン、Jake VanderPlas著、菊池彰訳『Pythonデータサイエンスハンドブック』、ISBN978-4-87311-841-3』

事前準備

プログラムはpythonjupyter notebookを使用します。開発環境を整えるならば、Anadondaをダウンロードすればpythonとjupyter notebook、pandasを全てインストールできます。下記サイトを参考に開発環境を構築しましょう。

Anaconda のインストール: Python環境構築ガイド – python.jp

Anaconda | The World’s Most Popular Data Science Platform

pandasの操作方法

インポート

基本的にnumpyとpandasをセットでインストールします。モジュールを使用する毎に名称を記載するのが煩雑であるため、略称としてnp、pdを利用しました。この略称はプログラム毎に任意で変更可能ですが、np,pdと略称するのがデファクトスタンダードです。

インポートのコード

 “`python
import numpy as np
import pandas as pd
“`

Series 一次元インデックス付きオブジェクト

配列と同様に扱えるデータですが、インデックスによってラベル付けされています。インデックスとはデータの項目番号で、データベースにおいて索引代わりとして使用されます。

例えば、つぎの表は数値とラベルを紐づけているので、bラベルのデータを表示すると0.5が表示されます。 

一次元インデックス付きオブジェクトのコード

“`python
data = pd.Series([0.25, 0.5, 0.75, 1.0],
         index=[‘a’, ‘b’, ‘c’, ‘d’])
data
“`
“`python
data[‘b’]
“`
   0.5

スライスの配列操作もできます。例えば、data[]配列のうち最初から2要素を取り出したいときは下記のように記載します。

“`python
data[:2]
“`

逆に3要素意向を取り出したいときは、コロンの位置を変更して次のように記載しましょう。

“`python
data[2:]
“`

DataFrameオブジェクト

DataFrameはインデックス付きの2次元配列です。Seriesと同様にラベルを指定することによって、容易にデータを抽出できます。NumPyのデータをDataFrameへ変換することもできます。

データの結合(和集合、積集合、差集合)

pandasは配列間のデータ結合を手軽に行えます。これはデータの前処理に対して便利な機能です。アルファベットを利用して体験してみましょう。

“`python
# 入力用データ1
s1 = pd.Index([“A”,”B”,”C”,”D”,”E”,”F”])
s2 = pd.Index([“E”,”F”,”G”,”H”,”I”,”J”])
“`

和集合のコード

 和集合

“`python
# 和集合
s1 | s2
“`
    Index([‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘I’, ‘J’], dtype=’object’) 

積集合のコード

積集合

 “`python
# 積集合
s1 & s2
“`
    Index([‘E’, ‘F’], dtype=’object’)

差集合のコード

差集合

“`python
# 差集合
s1 ^ s2
“`
    Index([‘A’, ‘B’, ‘C’, ‘D’, ‘G’, ‘H’, ‘I’, ‘J’], dtype=’object’)

NaNとNoneの操作

pandasではNaNとNoneを同列に扱うことができます。データ分析において使用するデータには欠損値が含まれていますので、複数形式に対して柔軟性が高いのはメリットです。

NaNとNoneの操作のコード

 “`python
pd.Series([1,np.nan,2,None])
“`

Nullの検出

Null値の検出にはisnull()とnotnull()の二つの方法があります。isnull()はNull値のブール代数を返し、notnull()はNull値以外の項目を抽出できます。

Nullの検出のコード

 “`python
data = pd.Series([1, np.nan, ‘hello’, None])
data.isnull()
“`
0    False
1     True
2    False
3     True
dtype: bool

 “`python
data = pd.Series([1, np.nan, ‘hello’, None])
data[data.notnull()]
“`
0        1
2    hello
dtype: object

欠損値の除外と追記:dropna(),fillna()

欠損値であるNaNはそのまま残っているとエラーの原因になるため、除外もしくは数値で置き換えます。

dropna()はNaN値の行データを全て消去します。fillna()はNaNに任意の数値を代入します。

0除算を避けたいけれどもデータ計算に影響を与えないように、非常に小さい数値を入れる手法が取られることがあります。非常に小さい数値は浮動小数点の丸目誤差によって吸収されますが、0ではないため数値の演算エラーが発生しないからです。

欠損値の除外と追記のコード

 “`python
data = pd.Series([1, np.nan, ‘hello’, None])
“`

0    False
1     True
2    False
3     True
dtype: bool

 “`python
data.dropna()
“`

0        1
2    hello
dtype: object

 “`python
data = pd.Series([1, np.nan, 2, None, 3], index=list(‘abcde’))
data
 “`

a    1.0
b    NaN
c    2.0
d    NaN
e    3.0
dtype: float64

 “`python
data.fillna(0)
 “`

a    1.0
b    0.0
c    2.0
d    0.0
e    3.0
dtype: float64

多重インデックス MultiIndex

現実世界でも複数属性ごとに項目を分けることがあります。

次の表ではプードルとチワワの平均体重を記載していますが、大きなくくりである『犬』の下に犬種であるプードルとチワワが配置されています。

通常のNumPyでは2次元配列しか扱えませんので、この操作はできませんがpandasではMuntiIndexを使って解決できます。最終結果として次の表をデータフレーム形式で再現してみます。

多重インデックスのコード

 “`python
index = [(‘dog’, “poodle”), (‘dog’, “Chihuahua”)]
average_weight = [5, 4]
dogs= pd.Series(average_weight, index=index)
dogs
 “`

(dog, poodle)       5
(dog, Chihuahua)    4
dtype: int64

 “`python
index = pd.MultiIndex.from_tuples(index)
index
 “`

MultiIndex([(‘dog’,    ‘poodle’),
            (‘dog’, ‘Chihuahua’)],
           )

 “`python
dogs = dogs.reindex(index)
dogs
 “`

dog  poodle       5
     Chihuahua    4
dtype: int64 

データセットの連結

複数のデータセットを連結するための動作をご紹介します。異なるデータ形式を結合できる前提でSeriesとDataFrameは設計されているので、ケアレスミスをしなければエラーは発生しないはずです。 

joinによる結合では、共通の項目によって行列が拡張されます。空の配列にはNaNが入ります。これは和集合と同じです。

データセットの連結のコード

 “`python
df_ab = pd.DataFrame({‘a’: [‘a1’, ‘a2’, ‘a3’], ‘b’: [‘b1’, ‘b2’, ‘b3’]})
df_ac = pd.DataFrame({‘a’: [‘a1’, ‘a2’, ‘a4’], ‘c’: [‘c1’, ‘c2’, ‘c4’]})
pd.concat([df_ab,df_ac])
 “`

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border=”1″ class=”dataframe”>
  <thead>
    <tr style=”text-align: right;”>
      <th></th>
      <th>a</th>
      <th>b</th>
      <th>c</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>a1</td>
      <td>b1</td>
      <td>NaN</td>
    </tr>
    <tr>
      <th>1</th>
      <td>a2</td>
      <td>b2</td>
      <td>NaN</td>
    </tr>
    <tr>
      <th>2</th>
      <td>a3</td>
      <td>b3</td>
      <td>NaN</td>
    </tr>
    <tr>
      <th>0</th>
      <td>a1</td>
      <td>NaN</td>
      <td>c1</td>
    </tr>
    <tr>
      <th>1</th>
      <td>a2</td>
      <td>NaN</td>
      <td>c2</td>
    </tr>
    <tr>
      <th>2</th>
      <td>a4</td>
      <td>NaN</td>
      <td>c4</td>
    </tr>
  </tbody>
</table>
</div>

join = innerと指定すれば積集合となります。

“`python
pd.concat([df_ab,df_ac],join = “inner”)
“`
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

 

    .dataframe tbody tr th {
        vertical-align: top;
    }

 

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border=”1″ class=”dataframe”>
  <thead>
    <tr style=”text-align: right;”>
      <th></th>
      <th>a</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>a1</td>
    </tr>
    <tr>
      <th>1</th>
      <td>a2</td>
    </tr>
    <tr>
      <th>2</th>
      <td>a3</td>
    </tr>
    <tr>
      <th>0</th>
      <td>a1</td>
    </tr>
    <tr>
      <th>1</th>
      <td>a2</td>
    </tr>
    <tr>
      <th>2</th>
      <td>a4</td>
    </tr>
  </tbody>
</table>
</div>

pd.marge()関数を使用して結合することができます。merge関数では1対1結合、1対多結合、多対多結合がスムーズにできます。例として従業員と役職の表を使って示してみましょう。

データセットの連結の例

 “`python
df1 = pd.DataFrame({‘employee’: [‘Bob’, ‘Jake’, ‘Lisa’, ‘Sue’],
                    ‘group’: [‘Accounting’, ‘Engineering’, ‘Engineering’, ‘HR’]})
df2 = pd.DataFrame({‘employee’: [‘Lisa’, ‘Bob’, ‘Jake’, ‘Sue’],
                    ‘hire_date’: [2004, 2008, 2012, 2014]})
display(‘df1’, ‘df2’)
“`

 

<div style=”float: left; padding: 10px;”>
    <p style=’font-family:”Courier New”, Courier, monospace’>df1</p><div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

 

    .dataframe tbody tr th {
        vertical-align: top;
    }

 

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border=”1″ class=”dataframe”>
  <thead>
    <tr style=”text-align: right;”>
      <th></th>
      <th>employee</th>
      <th>group</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>Bob</td>
      <td>Accounting</td>
    </tr>
    <tr>
      <th>1</th>
      <td>Jake</td>
      <td>Engineering</td>
    </tr>
    <tr>
      <th>2</th>
      <td>Lisa</td>
      <td>Engineering</td>
    </tr>
    <tr>
      <th>3</th>
      <td>Sue</td>
      <td>HR</td>
    </tr>
  </tbody>
</table>
</div>
    </div>
<div style=”float: left; padding: 10px;”>
    <p style=’font-family:”Courier New”, Courier, monospace’>df2</p><div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

 

    .dataframe tbody tr th {
        vertical-align: top;
    }

 

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border=”1″ class=”dataframe”>
  <thead>
    <tr style=”text-align: right;”>
      <th></th>
      <th>employee</th>
      <th>hire_date</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>Lisa</td>
      <td>2004</td>
    </tr>
    <tr>
      <th>1</th>
      <td>Bob</td>
      <td>2008</td>
    </tr>
    <tr>
      <th>2</th>
      <td>Jake</td>
      <td>2012</td>
    </tr>
    <tr>
      <th>3</th>
      <td>Sue</td>
      <td>2014</td>
    </tr>
  </tbody>
</table>
</div>

 

“`python
df3 = pd.merge(df1, df2)
df3
“`

 

<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

 

    .dataframe tbody tr th {
        vertical-align: top;
    }

 

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border=”1″ class=”dataframe”>
  <thead>
    <tr style=”text-align: right;”>
      <th></th>
      <th>employee</th>
      <th>group</th>
      <th>hire_date</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>Bob</td>
      <td>Accounting</td>
      <td>2008</td>
    </tr>
    <tr>
      <th>1</th>
      <td>Jake</td>
      <td>Engineering</td>
      <td>2012</td>
    </tr>
    <tr>
      <th>2</th>
      <td>Lisa</td>
      <td>Engineering</td>
      <td>2004</td>
    </tr>
    <tr>
      <th>3</th>
      <td>Sue</td>
      <td>HR</td>
      <td>2014</td>
    </tr>
  </tbody>
</table>
</div>

 

まとめ

 本記事ではデータサイエンスにおけるデータ処理の重要性とpandasの説明を行いました。分析に使用するデータはWeb上や異なるデータフォーマットから収集してくるため、データ形式を合わせるために適切に処理する必要があります。pandasはデータの欠陥に対する耐性が高く、エラーを出すことなく様々なデータ処理を行うことが可能でした。

・オライリージャパン、Jake VanderPlas 著、菊池彰 訳、『Pythonデータサイエンスハンドブック』、ISBN:978-4-87311-841-3

 ・オライリージャパン、Wes McKinney 著、瀬戸山雅人、小林 儀匡、滝口開資 訳、『Pythonによるデータ分析入門 第2版』、ISBN: 978-4-87311-845-1

 ・オライリージャパン、斎藤康毅 著、『ゼロから作るDeep

Learning』、ISBN: 978-4-87311-758-4

 ・オライリージャパン、Aurélien Géron著、下田倫大 監訳、長尾高弘 訳、『scikit-learn、Keras、TensorFlowによる実践機械学習 第2版』、ISBN: 978-4-87311-928-1