めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

機械学習のためのPython/NumPy/pandasチュートリアル(パート2)

※パート1は、こちらです。

DataFrameとは?

パート2では、pandasのDataFrameを説明します。これは、エクセルシートのように、縦横に並べたデータにラベルをつけて取り扱うことができます。R言語のデータフレームに相当するものになります。

SeriesとDataFrame

DataFrameは、RDBのテーブルのように、1つの列が特定のデータ項目、1つの行が1つのデータ(レコード)を表します。1つの列、もしくは、1つの行を取り出したものがSeriesオブジェクトです。

まず、特定のデータ項目に対応するSeriesオブジェクトを作ってみます。それぞれ、都市名、気温、湿度を表すデータです。

In [1]: city = Series(['Tokyo','Osaka','Nagoya','Okinawa'], name='City')

In [2]: temp = Series([25.0,28.2,27.3,30.9], name='Temperature')

In [3]: humid = Series([44,42,np.nan,62], name='Humidity')

In [4]: city
Out[4]: 
0      Tokyo
1      Osaka
2     Nagoya
3    Okinawa
Name: City, dtype: object

In [5]: temp
Out[5]: 
0    25.0
1    28.2
2    27.3
3    30.9
Name: Temperature, dtype: float64

In [6]: humid
Out[6]: 
0    44
1    42
2   NaN
3    62
Name: Humidity, dtype: float64

ここで、np.nan(NaN)は、データが欠損していることを示します。平均値などを計算するときは、このデータは無視されます。(仮に0を代入したとすると平均値が変わる点に注意してください。)

これらを1つにまとめたDataFrameを作成すると、次のようになります。

In [7]: df = DataFrame({'City':city, 'Temperature':temp, 'Humidity':humid})

In [8]: df
Out[8]: 
      City  Humidity  Temperature
0    Tokyo        44         25.0
1    Osaka        42         28.2
2   Nagoya       NaN         27.3
3  Okinawa        62         30.9

ハッシュを経由して定義しているので、列の順番がどうなるかは不定です。列の順番を指定したい場合は、columnsオプションを指定します。

In [9]: df = DataFrame({'City':city, 'Temperature':temp, 'Humidity':humid}, columns=['City','Temperature','Humidity'])

In [10]: df
Out[10]: 
      City  Temperature  Humidity
0    Tokyo         25.0        44
1    Osaka         28.2        42
2   Nagoya         27.3       NaN
3  Okinawa         30.9        62

Seriesを用いず、直接にDataFrameを作成することも可能です。

In [11]: data = {'City':['Tokyo','Osaka','Nagoya','Okinawa'],
   ....:         'Temperature':[25.0,28.2,27.3,30.9],
   ....:         'Humidity':[44,42,np.nan,62]}

In [12]: df = DataFrame(data)

In [13]: df
Out[13]: 
      City  Humidity  Temperature
0    Tokyo        44         25.0
1    Osaka        42         28.2
2   Nagoya       NaN         27.3
3  Okinawa        62         30.9

DataFrameは、describe()メソッドで数値データを持つ列の統計値が確認できます。

In [14]: df.describe()
Out[14]: 
        Humidity  Temperature
count   3.000000     4.000000
mean   49.333333    27.850000
std    11.015141     2.439262
min    42.000000    25.000000
25%    43.000000    26.725000
50%    44.000000    27.750000
75%    53.000000    28.875000
max    62.000000    30.900000

Humidityのcount(データ数)を見ると、欠損値(NaN)はデータとしてカウントされていないことが分かります。

DataFrameからのデータの取り出し

DataFrameから、特定の列をSeriesとして取り出すことが可能です。

In [14]: df['humidity']
Out[14]: 
0    44
1    42
2   NaN
3    62
Name: humidity, dtype: float64

次のようにAttributeとして取り出すこともできます。(まぎらわしいので、あまりお勧めしませんが。)

In [15]: df.Humidity
Out[15]: 
0    44
1    42
2   NaN
3    62
Name: Humidity, dtype: float64

次のように複数の列を取り出した場合は、DataFrameになります。

In [16]: df[['city','humidity']]
Out[16]: 
      city  humidity
0    Tokyo        44
1    Osaka        42
2   Nagoya       NaN
3  Okinawa        62

DataFrameから一部のデータを取り出すさまざまな方法は、下記のエントリーを参考にしてください。

pandasのDataFrameからのデータ選択

なお、DataFrameから取り出したオブジェクトは、値を変更しないようにしてください。取り出し方によって、値がコピーされている場合と元のデータフレームと同じオブジェクトを参照している場合があり、意図しない変更が発生する恐れがあるためです。たとえば、次のように、Seriesを取り出して要素を変更しようとすると警告が表示されます。

In [17]: df
Out[17]: 
      City  Humidity  Temperature
0    Tokyo        44         25.0
1    Osaka        42         28.2
2   Nagoya       NaN         27.3
3  Okinawa        62         30.9

In [18]: a = df['Humidity']

In [19]: a[2]
Out[19]: nan

In [20]: a[2] = 50
/home/canopy/Enthought/Canopy_64bit/User/bin/ipython:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  #!/home/canopy/Enthought/Canopy_64bit/User/bin/python

取り出した方の値を変更したい場合は、copy()メソッドで明示的にコピーを取得します。

In [21]: a = df['Humidity'].copy()

In [22]: a[2] = 50

元のDataFrameの方を変更したい場合は、locフィールドで要素を指定して変更します。

In [15]: df.loc[2,'Humidity'] = 50

In [16]: df
Out[16]: 
      City  Humidity  Temperature
0    Tokyo        44         25.0
1    Osaka        42         28.2
2   Nagoya        50         27.3
3  Okinawa        62         30.9

最後に、すこしおもしろい表現ですが、次のように、特定の条件を満たす行だけを取り出すことができます。

In [17]: df[df['Temperature'] > 28]
Out[17]: 
      City  Humidity  Temperature
1    Osaka        42         28.2
3  Okinawa        62         30.9