Pythonプログラミング(ステップ7・統計計算・CSV形式のデータ)
このページでは、統計処理の際によく使われるCSV形式のデータの扱いについて紹介する。
CSVデータ
行と列の区画の表(テーブル)の形式で表現されるデータは多く、表計算ソフト(Microsoft Excel, Google Spreadsheet等)は、表形式のデータを扱う専用ツールとも言える。
こうした表データを扱うためのファイル形式のひとつにCSV(Comma-Separated Values)フォーマットがある。 CSVは表計算ソフトはもちろん、テーブル形式のデータをやりとりする際の、事実上の標準フォーマットのひとつである。
CSVの内容はいたって簡単で、各項目がコンマで区切られ、
身長,体重,年齢,推定年俸 205,115,31,15000 195,95,31,1200 194,92,25,800 191,118,33,7000 ...
のように並んでいるだけである。1行目はヘッダで、各列の表題を表す。2行目以降がデータである。 なお、ヘッダーが無く、データ(値)のみで構成される場合もある。
データ項目の区切りは、コンマ以外に、タブ(TAB)文字や空白文字が使われる場合もある。タブで区切られたデータを特に TSV と呼ぶこともある。
文字列データを扱う場合は、途中に空白やコンマを含む場合もあるので、両側をダブルクォーテーションで挟むのが「正しい」作法である。 例えば上記のデータを
"身長","体重","年齢","推定年俸" 205,115,31,15000 195,95,31,1200 194,92,25,800 191,118,33,7000 ...
としても、同様に解釈される。ダブルクォーテーションで挟まれた文字列中でのダブルクォーテーションは""
で表現する。また、
文字列中のTABは\t
、改行は\n
で表現する。
CSVの中の文字列の文字コードはさまざまで紛らわしい。それを判別するために、先頭にBOM(byte order mark)と呼ばれるデータが付加されている場合がある。 データの先頭に「ゴミ」のような文字が見える場合は、BOM付きのCSVの可能性がある。
以下に、1行目がラベルで、コンマ区切りの整数値の表をリストに読み込むコードの例を示す。 各列のデータの形式(整数、実数、文字列)が異なっていたりする場合でも対応できるようなコードを書くのは(かなり)面倒なので、 次節のような専用のモジュールを用いるのが簡単で確実である。
# coding: utf-8 with open('rakuten.csv',mode='r',encoding='utf-8') as file: lines = file.readlines() data=[ ] cnt=0 for line in lines: if cnt>0 and len(line.strip())>0: # skip first and empty line data.append( list(map(int,line.split(','))) ) cnt += 1 print(data)
pandasを使ったCSVの読み込み
上記のとおり、CSVはよく使われるので、それを操作するためのライブラリが流通している。中でもデータ解析でよく使われるのがpandasで、CSVに限らず、様々なフォーマットのデータを扱う機能が提供されている。
以下は、あるプロ野球球団の選手の体重、身長、年齢、推定年俸のCSVデータを、 pandasを使って読み込み、散布図をプロットするコードの例である。
コードの補足説明
CSVデータの取り込むにはファイル名(あるいはURL)を指定して
import pandas as pd ... data = pd.read_csv('rakuten.csv')
のように書くだけで、DataFrameと呼ばれるオブジェクトとして内容が得られる。あるいは、DataFrameのvalues属性を参照して、
array = pd.read_csv('rakuten.csv').values
のように書くと、すべての値をNumPyの二次元配列(ndarray)で取得することができる。
各列のラベルとデータ形式は オブジェクト名.dtypes
で得ることができる。
DataFrameオブジェクトで読み込んだデータの各列(コラム)は オブジェクト名['ラベル名']
で参照できる。さらに、.tolist()
によってその内容の標準リストが得られる。
推定年俸は、list(map(math.log10,data['推定年俸'].tolist()))
の箇所で、常用対数を取った値のリストに変換している。
map(関数, リスト)
で、リストに関数を作用させ、mapオブジェクトを生成。それをlist( )
でリストに変換。
なお、DataFrameオブジェクトを行毎に処理したい場合は、イテレータを使って
for n,cols in data.iterrows(): print("行番号=",n, cols['年齢'], cols['推定年俸'])
のような記述が可能である。
# coding: utf-8 import math import pandas as pd import matplotlib.pyplot as plt data = pd.read_csv('rakuten.csv') print(data.dtypes) wt = data['体重'].tolist() ht = data['身長'].tolist() age = data['年齢'].tolist() wage = list(map(math.log10,data['推定年俸'].tolist())) fig = plt.figure() ax1 = fig.add_subplot(2, 2, 1) ax1.scatter(wt, wage) ax1.set_xlabel("Weight [kg]") ax1.set_ylabel("LOG Wage[10000 JPY]") ax2 = fig.add_subplot(2, 2, 2) ax2.scatter(ht, wage) ax2.set_xlabel("Height [cm]") ax2.set_ylabel("LOG Wage[10000 JPY]") ax3 = fig.add_subplot(2, 2, 3) ax3.scatter(age, wage) ax3.set_xlabel("Age") ax3.set_ylabel("LOG Wage[10000 JPY]") ax4 = fig.add_subplot(2, 2, 4) ax4.scatter(wt, ht) ax4.set_xlabel("Weight [kg]") ax4.set_ylabel("Height [cm]") plt.show()
実行結果