[Pandas入門]コラム名の無いcsvファイルを読み込んでコラム名をつける


コラム名の無いcsvファイルにコラム名をつける

コラム名の無いcsvファイルを読み込んでコラム名をつける作業をたまにやるのだけれども、やり方をよく忘れるので備忘録としてメモっておきます。

ごめんなさい。内容は本当に大した事ないです。

使用するデータ

使用したデータはUCI machine learning repositoryで公開されている住宅データを使用しました。
housing data

データ読み込み

まずはデータを読み込みます。データはカンマではなく空白で区切られているので、sepで空白を指定します。また、housing.dataにはカラム名がないため、普通に読み込むと1行目のデータがカラム名と認識されてしまうので、それを避けるためにheader=Noneを指定します。

import pandas as pd
df = pd.read_csv("housing.data", header=None, sep="\s+")

データを読み込んだ結果は

となります。自動で0~13までの番号が割り振られてカラム名となっています。この自動で作成されたカラム名を本来のカラム名に置き換えます。まず、変換前のカラム名と変換後のカラム名を対応させる辞書(labels_dict)を作成します。データフレームのrenameメドッドでlabels_dictを指定すると、辞書で示された対応通りにカラム名が置きかわります。

labels =  ["CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE", "DIS", "RAD", "TAX", "PTRATIO", "B", "LSTAT", "MEDV"]
labels_dict = {num: label for num, label in enumerate(labels)}
df = df.rename(columns = labels_dict)
# カラム名を追加したデータフレームをcsvファイルとして保存する。
df.to_csv("housing_data.csv", index=False)

実行後dfの中を確認すると、カラム名が変更されていることがわかります。

お・ま・け(以下、本記事の本来の内容とは一切関係ありませんのでご注意ください)

せっかくなので、このデータを使用して住宅価格の予想をざっくりやってみます。

データをざっくり眺めてみます

以下のコードを実行すると、このデータが全て数値データで欠損値が無い事がわかります。また統計量を表示することができます。よかったら実行してみてください。

from IPython.display import display
# データ型表示
display(df.dtypes)
# 欠損値数の表示
display(df.isnull().sum())
# 統計量の表示
display(df.describe())

普通は、データの統計量などを確認しながらデータの前処理を行なって、その後で機械学習のアルゴリズムにデータを投入するのですが、今回は割愛します。なんて言ったって、お・ま・けですから。

線形回帰モデルでの学習

いろいろ省いています。なんて言っても、お・ま・けですから。最低限データの標準化とテストデータでの評価は行なっていますが、ハイパーパラメータの調整などは一切行なっていません。評価は単純に平均二乗誤差(RMSE)で行いました。コードを以下になります。

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline

# パイプライン設定
pipe = Pipeline([
    ("scl", StandardScaler()),
    ("pca", PCA(n_components=10)),
    ("lr", LinearRegression(normalize=False))
])

# データの分割
xtrain, xtest, ytrain, ytest = train_test_split(df[df.columns[df.columns != "MEDV"]], df["MEDV"], test_size=0.3, random_state=1)

# モデルの学習
pipe.fit(X=xtrain, y=ytrain)

# 価格の予想
ypred = pipe.predict(xtest)

# モデルの評価
display(mean_squared_error(ytest, ypred))

# 結果の表示
result = pd.DataFrame(columns=["index", "true", "pred"])
result["index"] = range(len(ytest))
result["true"] = ytest.tolist()
result["pred"] = ypred

plt.figure(figsize=(15,5))
plt.scatter(result["index"], result["true"], marker="x", label="true")
plt.scatter(result["index"], result["pred"], marker="v", label="predict")
plt.xlabel("ID")
plt.ylabel("価格の中央値")
plt.grid()
plt.legend()
plt.show()

これを実行すると、平均2乗誤差として21.19となりました。これが良いか悪いかはちゃんとデータを見ないとわかりませんが、とりあえず価格の予測と真値とのズレを評価できました。

また、予測値と真値をグラムにすると以下になります。ぱっと見、価格が高い方のズレが大きく、予測値は低く予想している事がわかります。