※パート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から一部のデータを取り出すさまざまな方法は、下記のエントリーを参考にしてください。
なお、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