Pandas 入門#

Pandas はデータ操作によく用いられるパッケージであり、CSV などの一般的なデータ形式で保存されたデータの読み込みや、条件を指定しての一部データの抽出など、機械学習手法で取り扱うデータを整理するのに便利です。

今回は Pandas の以下の代表的な機能の使い方を説明します。

  • CSV ファイルの読み書き

  • 統計量の算出

  • 並べ替え

  • データの選択

  • 条件指定による選択

  • 欠損値の除去 / 補間

  • ndarray とデータフレームを相互に変換

  • グラフの描画

まず Pandas パッケージを読み込みましょう。 pandaspd という別名を与えて用いるのが一般的です。

import pandas as pd

CSV ファイルの読み書き#

データセットは Google Colaboratory で用意されているサンプルデータを使用します。 Google Colaboratory 以外で実行する場合は、こちらをダウンロードして、使用してください。

Pandas では CSV ファイルを読み込むための pd.read_csv() という関数が用意されています。 こちらを使って CSV ファイルを読み込みます。

# データセットの読み込み
df = pd.read_csv('sample_data/california_housing_train.csv')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In[2], line 2
      1 # データセットの読み込み
----> 2 df = pd.read_csv('sample_data/california_housing_train.csv')

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pandas/io/parsers/readers.py:912, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)
    899 kwds_defaults = _refine_defaults_read(
    900     dialect,
    901     delimiter,
   (...)
    908     dtype_backend=dtype_backend,
    909 )
    910 kwds.update(kwds_defaults)
--> 912 return _read(filepath_or_buffer, kwds)

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pandas/io/parsers/readers.py:577, in _read(filepath_or_buffer, kwds)
    574 _validate_names(kwds.get("names", None))
    576 # Create the parser.
--> 577 parser = TextFileReader(filepath_or_buffer, **kwds)
    579 if chunksize or iterator:
    580     return parser

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1407, in TextFileReader.__init__(self, f, engine, **kwds)
   1404     self.options["has_index_names"] = kwds["has_index_names"]
   1406 self.handles: IOHandles | None = None
-> 1407 self._engine = self._make_engine(f, self.engine)

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pandas/io/parsers/readers.py:1661, in TextFileReader._make_engine(self, f, engine)
   1659     if "b" not in mode:
   1660         mode += "b"
-> 1661 self.handles = get_handle(
   1662     f,
   1663     mode,
   1664     encoding=self.options.get("encoding", None),
   1665     compression=self.options.get("compression", None),
   1666     memory_map=self.options.get("memory_map", False),
   1667     is_text=is_text,
   1668     errors=self.options.get("encoding_errors", "strict"),
   1669     storage_options=self.options.get("storage_options", None),
   1670 )
   1671 assert self.handles is not None
   1672 f = self.handles.handle

File /opt/hostedtoolcache/Python/3.8.17/x64/lib/python3.8/site-packages/pandas/io/common.py:859, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)
    854 elif isinstance(handle, str):
    855     # Check whether the filename is to be opened in binary mode.
    856     # Binary mode does not support 'encoding' and 'newline'.
    857     if ioargs.encoding and "b" not in ioargs.mode:
    858         # Encoding
--> 859         handle = open(
    860             handle,
    861             ioargs.mode,
    862             encoding=ioargs.encoding,
    863             errors=errors,
    864             newline="",
    865         )
    866     else:
    867         # Binary mode
    868         handle = open(handle, ioargs.mode)

FileNotFoundError: [Errno 2] No such file or directory: 'sample_data/california_housing_train.csv'

df という変数名は、データフレーム (data frame) という Pandas で中心的に用いられるデータ構造 (data structure) を表すクラスの名前の頭文字に由来しています。 pd.read_csv() 関数は、CSV ファイルの内容を DataFrame オブジェクトに読み込みます。

# 型の確認
type(df)
pandas.core.frame.DataFrame

DataFrame の表示#

df に読み込まれたデータの中身の確認してみましょう。 Jupyter Notebook 上では、大きな DataFrame を表示しようとすると自動的に一部が省略されることがあります。

df
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0
3 -114.57 33.64 14.0 1501.0 337.0 515.0 226.0 3.1917 73400.0
4 -114.57 33.57 20.0 1454.0 326.0 624.0 262.0 1.9250 65500.0
... ... ... ... ... ... ... ... ... ...
16995 -124.26 40.58 52.0 2217.0 394.0 907.0 369.0 2.3571 111400.0
16996 -124.27 40.69 36.0 2349.0 528.0 1194.0 465.0 2.5179 79000.0
16997 -124.30 41.84 17.0 2677.0 531.0 1244.0 456.0 3.0313 103600.0
16998 -124.30 41.80 19.0 2672.0 552.0 1298.0 478.0 1.9797 85800.0
16999 -124.35 40.54 52.0 1820.0 300.0 806.0 270.0 3.0147 94600.0

17000 rows × 9 columns

先頭の数件だけを表示#

データを数件のみ確認したい場合は、データフレームがもつ df.head() メソッドを使用します。 df.head() はデフォルトで先頭から 5 件のデータを表示しますが、df.head(3) のように引数に表示したいデータ件数を指定すると、指定された件数だけを表示することもできます。 それでは、df.head() を実行してみましょう。

df.head()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0
3 -114.57 33.64 14.0 1501.0 337.0 515.0 226.0 3.1917 73400.0
4 -114.57 33.57 20.0 1454.0 326.0 624.0 262.0 1.9250 65500.0
df.head(3)
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0

特定の列を抽出したい場合は、df に対し、Python の辞書オブジェクトに行うように [] を使って取り出したい列の名前を指定します。

df['longitude'].head(3)
0   -114.31
1   -114.47
2   -114.56
Name: longitude, dtype: float64

CSV ファイルの保存#

Pandas ではデータフレームオブジェクトの内容を CSV ファイルとして保存するための df.to_csv() というメソッドが用意されています。

df.to_csv('sample.csv')
!ls sample.csv
sample.csv

データフレームの形#

データフレームオブジェクトの行数と列数を確認するには、df.shape() メソッドを用います。

# 形の確認
df.shape
(17000, 9)

統計量の算出#

データフレームには、中のデータに対し統計量を計算するためのメソッドも用意されています。 代表的なものを紹介します。

# 平均
df.mean()
longitude               -119.562108
latitude                  35.625225
housing_median_age        28.589353
total_rooms             2643.664412
total_bedrooms           539.410824
population              1429.573941
households               501.221941
median_income              3.883578
median_house_value    207300.912353
dtype: float64
# 分散
df.var()
longitude             4.020692e+00
latitude              4.568221e+00
housing_median_age    1.584310e+02
total_rooms           4.752169e+06
total_bedrooms        1.776618e+05
population            1.317566e+06
households            1.478563e+05
median_income         3.641061e+00
median_house_value    1.345223e+10
dtype: float64
# 各列の None, NaN, NaT のいずれでもない値の数
df.count()
longitude             17000
latitude              17000
housing_median_age    17000
total_rooms           17000
total_bedrooms        17000
population            17000
households            17000
median_income         17000
median_house_value    17000
dtype: int64

ここで、データの特徴をおおまかに調べるために便利な df.describe() メソッドを実行してみましょう。

# データの概要
df.describe()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
count 17000.000000 17000.000000 17000.000000 17000.000000 17000.000000 17000.000000 17000.000000 17000.000000 17000.000000
mean -119.562108 35.625225 28.589353 2643.664412 539.410824 1429.573941 501.221941 3.883578 207300.912353
std 2.005166 2.137340 12.586937 2179.947071 421.499452 1147.852959 384.520841 1.908157 115983.764387
min -124.350000 32.540000 1.000000 2.000000 1.000000 3.000000 1.000000 0.499900 14999.000000
25% -121.790000 33.930000 18.000000 1462.000000 297.000000 790.000000 282.000000 2.566375 119400.000000
50% -118.490000 34.250000 29.000000 2127.000000 434.000000 1167.000000 409.000000 3.544600 180400.000000
75% -118.000000 37.720000 37.000000 3151.250000 648.250000 1721.000000 605.250000 4.767000 265000.000000
max -114.310000 41.950000 52.000000 37937.000000 6445.000000 35682.000000 6082.000000 15.000100 500001.000000

また、もうひとつ便利なメソッドに相関係数を算出する df.corr() があります。 入力変数間や入出力間の相関係数を確認することができます。

# 相関係数の算出
df.corr()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
longitude 1.000000 -0.925208 -0.114250 0.047010 0.071802 0.101674 0.059628 -0.015485 -0.044982
latitude -0.925208 1.000000 0.016454 -0.038773 -0.069373 -0.111261 -0.074902 -0.080303 -0.144917
housing_median_age -0.114250 0.016454 1.000000 -0.360984 -0.320434 -0.295890 -0.302754 -0.115932 0.106758
total_rooms 0.047010 -0.038773 -0.360984 1.000000 0.928403 0.860170 0.919018 0.195383 0.130991
total_bedrooms 0.071802 -0.069373 -0.320434 0.928403 1.000000 0.881169 0.980920 -0.013495 0.045783
population 0.101674 -0.111261 -0.295890 0.860170 0.881169 1.000000 0.909247 -0.000638 -0.027850
households 0.059628 -0.074902 -0.302754 0.919018 0.980920 0.909247 1.000000 0.007644 0.061031
median_income -0.015485 -0.080303 -0.115932 0.195383 -0.013495 -0.000638 0.007644 1.000000 0.691871
median_house_value -0.044982 -0.144917 0.106758 0.130991 0.045783 -0.027850 0.061031 0.691871 1.000000

並べ替え#

データフレームのある列を抽出し、df.sort_values() メソッドを呼び出すことで値の並べ替え (sort) を行うことができます。 なお、このメソッドは並べ替えが終わったあとの値でもとのデータフレーム内の値を置き換えることまでは行わず、結果を返します。 そこで、別の変数で結果を受け取り、始めの 5 行を表示することで並べ替えが行われたことを確認してみましょう。

df.sort_values() は、デフォルトでは昇順 (ascending) に並べ替えを行います。昇順とは、だんだん値が大きくなっていくように並べ替えるときの並べ方のことで、逆にだんだん値が小さくなっていくように並べ替えるときは、降順 (descending) に並べると言います。

df.sort_values() は並べ替えを行いたい列の名前を by という引数で受け取ります。また、デフォルトでは昇順に並べ替えを行います。

# total_rooms 列の値を昇順に並べ替え
df_as = df.sort_values(by='total_rooms')
df_as.head()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
2990 -117.79 35.21 4.0 2.0 2.0 6.0 2.0 2.3750 137500.0
16309 -122.50 37.79 52.0 8.0 1.0 13.0 1.0 15.0001 500001.0
8188 -118.44 34.28 46.0 11.0 11.0 24.0 13.0 2.8750 162500.0
15369 -122.29 37.81 46.0 12.0 4.0 18.0 7.0 0.4999 67500.0
15656 -122.37 37.60 26.0 15.0 3.0 11.0 3.0 5.0480 350000.0

降順に並べ替える場合は、ascending=False という引数の指定を行います。

# total_rooms の列の値を降順に並べ替え
df_de = df.sort_values(by='total_rooms', ascending=False)
df_de.head()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
2871 -117.74 33.89 4.0 37937.0 5471.0 16122.0 5189.0 7.4947 366300.0
12772 -121.79 36.64 11.0 32627.0 6445.0 28566.0 6082.0 2.3087 118800.0
2969 -117.78 34.03 8.0 32054.0 5290.0 15507.0 5050.0 6.0191 253900.0
8881 -118.78 34.16 9.0 30405.0 4093.0 12873.0 3931.0 8.0137 399200.0
1116 -117.12 33.52 4.0 30401.0 4957.0 13251.0 4339.0 4.5841 212300.0

データの選択#

着目したい要素や、行、列を選択する方法として、ここでは、行名や列名を用いてデータの部分選択を行う df.loc[] を紹介します。

# データの確認
df.head(3)
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0
# df.loc[行名, 列名]
# 0 行目 longitude 列の選択
df.loc[0, "longitude"]
-114.31
# 1 行目 latitude 列の選択
df.loc[1, "latitude"]
34.4

loc は NumPy の ndarray の中の値を部分的に選択するのと同様のスライス表記を用いることができます。

# すべての行を選択
t = df.loc[:, "housing_median_age"]
# 先頭3件の表示
t.head(3)
0    15.0
1    19.0
2    17.0
Name: housing_median_age, dtype: float64
# 型の確認
type(t)
pandas.core.series.Series

1 行だけ、もしくは 1 列だけ抽出した場合は、シリーズ (series) オブジェクトが返されます。

条件指定による要素の選択#

次に値に対する条件を指定してデータの選択を行う方法を紹介します。

簡単のため、まず median_house_value 列を選択し、返ってきたシリーズオブジェクトに対して、比較演算子を使って各要素に対する条件を指定し、条件を満たすかどうかを全要素に対して調べた結果を取得してみましょう。

# median_house_value 列を選択し、全要素に対し 70000 より大きいかどうかを計算
mask = df['median_house_value'] > 70000
mask.head()
0    False
1     True
2     True
3     True
4    False
Name: median_house_value, dtype: bool

このように、比較演算子の片方の辺にデータフレームやシリーズをおくと、指定された条件を満たすかどうかを全ての要素に対して計算することができます。 結果は、各要素が条件を満たすか、満たさないかを表す TrueFalse が各要素の位置に格納されたデータフレームやシリーズとなります。 これをマスク (mask) と呼ぶことがあります。

そして、データフレームやシリーズも NumPy の ndarray と同様に、マスクを使って要素を選択することができます。 上の maskdf[] を使って与えることで、指定した条件を満たす要素だけを取り出すことができます。

# df[mask] の先頭 5 行を表示
df[mask].head()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0
3 -114.57 33.64 14.0 1501.0 337.0 515.0 226.0 3.1917 73400.0
5 -114.58 33.63 29.0 1387.0 236.0 671.0 239.0 3.3438 74000.0
6 -114.58 33.61 25.0 2907.0 680.0 1841.0 633.0 2.6768 82400.0

複数の条件指定による要素の選択#

複数の条件を組み合わせて要素を選択することも出来ます。 その場合は条件式を () でくくって用います。 論理和 (or)|論理積 (and)& を用いて表します。

# 70000 より小さい または 80000 より大きい
mask2 = (df['median_house_value'] < 70000) | (df['median_house_value'] > 80000)
mask2.head()
0     True
1     True
2     True
3    False
4     True
Name: median_house_value, dtype: bool
df[mask2].head()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0
4 -114.57 33.57 20.0 1454.0 326.0 624.0 262.0 1.9250 65500.0
6 -114.58 33.61 25.0 2907.0 680.0 1841.0 633.0 2.6768 82400.0

このように複雑な条件で要素を選択する際は query メソッドを使用すると簡潔に書くことができます。

# 70000 より小さい または 80000 より大きい
df.query("median_house_value < 70000 | 80000 < median_house_value")
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0
4 -114.57 33.57 20.0 1454.0 326.0 624.0 262.0 1.9250 65500.0
6 -114.58 33.61 25.0 2907.0 680.0 1841.0 633.0 2.6768 82400.0
... ... ... ... ... ... ... ... ... ...
16993 -124.23 40.54 52.0 2694.0 453.0 1152.0 435.0 3.0806 106700.0
16995 -124.26 40.58 52.0 2217.0 394.0 907.0 369.0 2.3571 111400.0
16997 -124.30 41.84 17.0 2677.0 531.0 1244.0 456.0 3.0313 103600.0
16998 -124.30 41.80 19.0 2672.0 552.0 1298.0 478.0 1.9797 85800.0
16999 -124.35 40.54 52.0 1820.0 300.0 806.0 270.0 3.0147 94600.0

16495 rows × 9 columns

# 70000 より大きい かつ 80000 より小さい
df.query("70000 < median_house_value < 80000")
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value
3 -114.57 33.64 14.0 1501.0 337.0 515.0 226.0 3.1917 73400.0
5 -114.58 33.63 29.0 1387.0 236.0 671.0 239.0 3.3438 74000.0
13 -114.61 34.83 31.0 2478.0 464.0 1346.0 479.0 3.2120 70400.0
23 -114.98 33.82 15.0 644.0 129.0 137.0 52.0 3.2097 71300.0
26 -115.37 32.82 30.0 1602.0 322.0 1130.0 335.0 3.5735 71100.0
... ... ... ... ... ... ... ... ... ...
16983 -124.19 41.78 15.0 3140.0 714.0 1645.0 640.0 1.6654 74600.0
16990 -124.22 41.73 28.0 3003.0 699.0 1530.0 653.0 1.7038 78300.0
16991 -124.23 41.75 11.0 3159.0 616.0 1343.0 479.0 2.4805 73200.0
16994 -124.25 40.28 32.0 1430.0 419.0 434.0 187.0 1.9417 76100.0
16996 -124.27 40.69 36.0 2349.0 528.0 1194.0 465.0 2.5179 79000.0

488 rows × 9 columns

条件指定による要素の置換#

条件を指定して選択した要素に対し、値の書き換えを行うことができます。 例えば、median_house_value 列に対していくつかの条件を別々に調べ、それぞれの条件を満たしている場合に特定の値を持つような新しい列を df に追加してみます。 median_house_value

  • 60000 より小さい場合は 0

  • 60000 以上 70000未満は 1

  • 70000 以上 80000未満は 2

  • 80000 以上は 3

となる値を持つ target という列を追加します。

まず、何も値の入っていない target という列を df に追加します。

# 新しい列 target を None で初期化
df['target'] = None
df.head()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value target
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0 None
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0 None
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0 None
3 -114.57 33.64 14.0 1501.0 337.0 515.0 226.0 3.1917 73400.0 None
4 -114.57 33.57 20.0 1454.0 326.0 624.0 262.0 1.9250 65500.0 None

target という列の全ての要素は None となっています。 この値を、条件指定によって書き換えます。

まず各条件に対応するマスクを作成します。選択まではせずに、マスクだけ作成する場合は、query ではなく eval が使用できます。

mask1 = df.eval("median_house_value < 60000")
mask2 = df.eval("60000 <= median_house_value < 70000")
mask3 = df.eval("70000 <= median_house_value < 80000")
mask4 = df.eval("80000 <= median_house_value")

それでは、上で計算したマスクと名前による列指定を組み合わせて、各条件を満たす行の target 列の値を書き換えます。

df.loc[mask1, 'target'] = 0
df.loc[mask2, 'target'] = 1
df.loc[mask3, 'target'] = 2
df.loc[mask4, 'target'] = 3

結果を確認してみましょう。

# 先頭から 5 番目までを表示
df.head()
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value target
0 -114.31 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0 1.0
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0 3.0
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0 3.0
3 -114.57 33.64 14.0 1501.0 337.0 515.0 226.0 3.1917 73400.0 2.0
4 -114.57 33.57 20.0 1454.0 326.0 624.0 262.0 1.9250 65500.0 1.0

欠損値の除去・補間#

欠損値を含むデータの場合、一部の行の値が欠損している列に NaN (Not a Number)、NoneNaT (Not a Time) などが含まれる場合があります。 欠損値への対策としては、欠損値を含む行、または列を除去するか、欠損値を特定の値で補完するという方法が考えられます。

まずは、欠損値の除去の方法を紹介します。

# 欠損値を人為的に作成
df.loc[0, "longitude"] = None
# (0, 'longitude') の要素が NaN になっていることを確認
df.head(3)
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value target
0 NaN 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0 1
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0 3
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0 3
# 欠損値のあるレコードを削除
df_dropna = df.dropna()

# 先頭から 3 件を表示
df_dropna.head(3)
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value target
1 -114.47 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0 3
2 -114.56 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0 3
3 -114.57 33.64 14.0 1501.0 337.0 515.0 226.0 3.1917 73400.0 2

上の結果と見比べると、NaN を含んでいた 0 行目のデータが取り除かれていることが分かります。

次に、平均を使った欠損値の補完を行ってみましょう。 まずは、補完に使用する平均値の計算を行います。

mean = df.mean()
mean
longitude               -119.562417
latitude                  35.625225
housing_median_age        28.589353
total_rooms             2643.664412
total_bedrooms           539.410824
population              1429.573941
households               501.221941
median_income              3.883578
median_house_value    207300.912353
target                     2.808412
dtype: float64

計算した各列の値の平均が格納されている mean を、df.fillna() メソッドに渡すことで、mean を用いた欠損値の補完を行うことができます。

# 欠損値を mean で補完
df_fillna =  df.fillna(mean)

# 先頭から 3 件を表示
df_fillna.head(3)
longitude latitude housing_median_age total_rooms total_bedrooms population households median_income median_house_value target
0 -119.562417 34.19 15.0 5612.0 1283.0 1015.0 472.0 1.4936 66900.0 1
1 -114.470000 34.40 19.0 7650.0 1901.0 1129.0 463.0 1.8200 80100.0 3
2 -114.560000 33.69 17.0 720.0 174.0 333.0 117.0 1.6509 85700.0 3

0 行目のデータの longitude 列に、meanlongitude 行の値が表示されていることが分かります。

今回は欠損値が 1 箇所にだけあるデータを用いましたが、df.dropna()df.fillna() は、対象の全ての欠損値に対して上記のような操作を行うメソッドです。

ndarray とデータフレームを相互に変換#

scikit-learn では、データフレームやシリーズをそのまま扱うことができます。 しかし、他のライブラリやフレームワークではそのままでは扱うことができない場合もあります。 そこで、データフレームを NumPy の ndarray に変換する方法を紹介します。

まず、df がデータフレームであることを確認します。

type(df)
pandas.core.frame.DataFrame

次に、dfvalues という属性の型を調べてみます。

type(df.values)
numpy.ndarray

NumPy の ndarray になっています。 データフレームやシリーズは、values という属性に値を ndarray として格納しています。

df.values
array([[        nan,  3.4190e+01,  1.5000e+01, ...,  1.4936e+00,
         6.6900e+04,  1.0000e+00],
       [-1.1447e+02,  3.4400e+01,  1.9000e+01, ...,  1.8200e+00,
         8.0100e+04,  3.0000e+00],
       [-1.1456e+02,  3.3690e+01,  1.7000e+01, ...,  1.6509e+00,
         8.5700e+04,  3.0000e+00],
       ...,
       [-1.2430e+02,  4.1840e+01,  1.7000e+01, ...,  3.0313e+00,
         1.0360e+05,  3.0000e+00],
       [-1.2430e+02,  4.1800e+01,  1.9000e+01, ...,  1.9797e+00,
         8.5800e+04,  3.0000e+00],
       [-1.2435e+02,  4.0540e+01,  5.2000e+01, ...,  3.0147e+00,
         9.4600e+04,  3.0000e+00]])
type(df['longitude'])
pandas.core.series.Series
type(df['longitude'].values)
numpy.ndarray

逆に、Python のリストや ndarray からシリーズやデータフレームを作ることもできます。 NumPy で乱数を要素にもつ ndarray を生成し、これをデータフレームに変換してみましょう。

pd.DataFrame のインスタンス化の際に、data 引数に元にしたい ndarray を与えます。

import numpy as np

# ndarray -> pd.DataFrame
df = pd.DataFrame(
    data=np.random.randn(10, 10)
)

df
0 1 2 3 4 5 6 7 8 9
0 0.235076 -0.025952 0.635551 -1.233459 1.875983 0.471026 -0.846990 -0.727128 0.535281 -0.662937
1 1.232096 0.327020 0.073412 -0.291659 -0.835771 -1.806214 -0.840970 -0.731787 -0.773722 -0.657064
2 0.540820 0.140009 1.351297 2.709533 0.469056 -0.573746 -0.135772 0.352596 0.233631 -0.658191
3 1.527199 -1.129577 0.240729 -0.352903 -0.052596 -0.013748 -0.025188 1.117134 -0.308465 -1.696524
4 -1.171764 0.503813 2.424457 0.262115 2.149916 0.984207 -1.187516 1.079167 -0.717449 -0.347563
5 0.278999 -0.892611 0.429661 -2.511540 0.536308 0.811684 1.774007 1.392216 1.726091 0.561226
6 0.724094 0.804228 1.049159 0.348018 -2.106214 0.185539 -0.556945 -1.541576 -0.614728 0.809802
7 -0.773019 1.327983 0.802475 -1.562232 -0.046259 -0.536498 -1.331944 0.280377 -1.572351 1.142880
8 1.388867 0.551502 -0.372442 -0.093690 1.388269 -1.969065 1.312570 1.141520 -1.110659 0.704427
9 -1.660362 0.081545 0.332048 -1.252397 0.525961 0.352583 1.480100 1.378975 -1.596351 -0.642919

グラフの描画#

データフレームオブジェクトから直接可視化のための機能を呼び出すことができます。 次の章で紹介する Matplotlib というグラフ描画ライブラリを df.plot() 機能を用いて利用することができます。

# グラフの描画
df.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x121ee8cc0>
../_images/37f8325f7596f3f7e0f8ba3b7f639d327458f55fb4748155e1116adec5d4abec.png

Matplotlib の使い方は、次章で説明します。