Python pandasの覚書
・表形式のデータとDataFrame
次のような表を、pythonプログラムで使用するには Pandasでつくるデータフレームが便利である。基本的な使い方をメモしておく。
$$
\begin{array}{|l|c|c|} \hline
\text{} & \text{国語} & \text{数学} \\ \hline
\text{A} & \text{65} & \text{60} \\ \hline
\text{B} & \text{80} & \text{85} \\ \hline
\text{C} & \text{95} & \text{75} \\ \hline
\end{array}
$$
データフレームは、インデックス(行)、カラム(列)につけられたキーをマトリクスにした中にデータを収める構造となっている。
DataFrame は、
columns( 'pandas.core.indexes.base.Index' )、
index ( 'pandas.core.indexes.base.Index' )、
values ( numpyの2次元配列 )
で構成されている
上の表の例では、
A,B,C が インデックスのキーで、
国語、数学 が カラムのキーとなっている。
収めるデータは、数値、文字列、または混在、欠損(NaNとなる)があっ
ても問題なし。dictionayの2次元版みたいなものかな。さらに、要素は、
配列の要素番号の扱いと同じようにしても参照できる。
・データフレームの作成
2次元配列のデータから作成(行データ)
import pandas as pd
''' 行データからデータフレームを作る
dataは、2次元配列の1行が1人のデータ。
1行のデータは左から詰められ、不足するときはNaN。多すぎるときはエラーとなる。
df --->> <class 'pandas.core.frame.DataFrame'>
国語 数学
A 65 60
B 80 85
C 95 75
'''
col = ["国語", "数学"] # カラム名の作成
idx = ["A", "B", "C"] # インデックス名の作成
data = [ # データ
[65, 60], # 国語、数学
[80, 85],
[95, 75]
]
df = pd.DataFrame(data, columns=col, index=idx) # DataFrameの作成
Dictionaryのデータから作成(列データ)
''' 列データからデータフレームを作る
dataは、(Dictionary) columns 名と key 名は、一致しているものが取り込まれる。
キー名が一致しないものは NaN となる。インデックスの数と要素の数が、過不足のときはエラーとなる。
'''
col = ["国語", "数学"] # カラム名の作成
idx = ["A", "B", "C"] # インデックス名の作成
data = { # データ
"国語" : [65, 80, 95],
"数学" : [60, 85, 75]
}
df = pd.DataFrame(data, columns=col, index=idx) # DataFrameの作成
・CSVファイルとして保存
# 保存
df.to_csv("output_pd2.csv") # UTF-8
'''
文字コードを,"shift_jis"とする場合
OSによって、使用されている文字コードが異なるので注意
動作環境
OS:debian
開発環境:VSCODE
df.to_csv("output_pd2.csv", encoding="shift_jis")
保存されたファイル
,国語,数学
A,65,60
B,80,85
C,95,75
'''
・CSVファイルの読み込み
# 読み込み
df = pd.read_csv('output_pd2.csv', index_col=0)
'''
index_col=0 を省略すると、インデックス名もデータの中に入る
Unnamed: 0 国語 数学
0 A 65 60
1 B 80 85
2 C 95 75
なお、タブ区切りのファイルの読み込みは delimiter='\t', header=0 をつける
df = pd.read_csv("output_pd3.tsv", delimiter='\t', header=0)
データフレームの出力例(インデックスの設定ができなかった)
国語 数学
0 A 65 60
1 B 80 85
2 C 95 75
'''
・データフレームからデータを抽出
データフレームよりデータを抽出したとき、その方法によって、
<class 'pandas.core.frame.DataFrame'> 2次元
<class 'pandas.core.series.Series'> 1次元
<class 'numpy.int64'> 数値など
のオブジェクトとなるので、注意が必要。
* 1行または1列だけのデータを、DataFrameで参照したいときは
df.loc[ [ 'A' ] ] のようにする(下記のソースを参照)
# 読み込み
df = pd.read_csv('output_pd2tokei.csv', index_col=0)
'''
ファイル名 --> path/ファイル名.csv
index_col=0 --> csvファイルの1行目をカラム名とする
'''
# ---------------------------------------------------------------------
# データフレーム
df # <class 'pandas.core.frame.DataFrame'> .shape (5,3)
'''
国語 数学 クラス
A 65 60 1A
B 80 85 NaN
C 95 75 1C
D 65 75 1A
E 65 60 1B
DataFrame は、columns、index、values で構成されている
'''
# ---------------------------------------------------------------------
# キー(列)
df.columns # <class 'pandas.core.indexes.base.Index'> .shape (3,)
'''
Index(['国語', '数学', 'クラス'], dtype='object')
'''
# ---------------------------------------------------------------------
# キー(行)
df.index # <class 'pandas.core.indexes.base.Index'> .shape (5,)
'''
Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
'''
# ---------------------------------------------------------------------
# データフレームの値 2次元のnumpy.ndarray
df.values # <class 'numpy.ndarray'> .shape (5,3)
'''
array([[65, 60, '1A'],
[80, 85, nan],
[95, 75, '1C'],
[65, 75, '1A'],
[65, 60, '1B']], dtype=object)
'''
# ---------------------------------------------------------------------
# values のデータ型
df.dtypes # <class 'pandas.core.series.Series'> .shape (3,)
'''
国語 int64
数学 int64
クラス object
dtype: object
'''
# ---------------------------------------------------------------------
# キーを使わず取り出す
# 2列目の数学を、データフレームとして取り出す(2次元)
df.iloc[:,[1]] # <class 'pandas.core.frame.DataFrame'>
'''
数学
A 60
B 85
C 75
D 75
E 60
'''
# 2列目の数学を、Seriesとして取り出す(1次元)
df.iloc[:,1] # <class 'pandas.core.series.Series'>
'''
A 60
B 85
C 75
D 75
E 60
Name: 数学, dtype: int64
--->> Seriesの参照
dd=df.iloc[:,1]
dd[0] <-- 0行の 60 を参照(警告がでる。 dd.iloc[0] と記述してね。)
dd['A'] <-- これは警告なしで参照できる
DataFrameではエラーとなるので注意
'''
# ---------------------------------------------------------------------
# キーを使って取り出す
# 2列目の数学を、データフレームとして取り出す(2次元)
df.loc[:,['数学']] # <class 'pandas.core.frame.DataFrame'>
'''
数学
A 60
B 85
C 75
D 75
E 60
'''
# 2列目の数学を、Seriesとして取り出す(1次元)
df.loc[:,'数学'] # <class 'pandas.core.series.Series'>
'''
A 60
B 85
C 75
D 75
E 60
Name: 数学, dtype: int64
=====
1列全てを取り出すときは、df['数学'] でOK
1行分は、df['A'] で取り出せない --> df.loc['A'] または df.loc['A',:]
'''
# ---------------------------------------------------------------------
# AとBの数学と国語をDataFrameとして取り出す
df.loc['A':'B',['数学','国語'] ]
'''
数学 国語
A 60 65
B 85 80
'''
・データフレームからデータを代入で抽出するときの注意
pandasは、設定や挙動が options にまとめられている。
= (代入演算子)を使ってデータを抽出したときは、
参照渡しとなっている。(デフォルト)
完全なコピーを作成するときは、
options の設定を変更する(pd.options.mode.copy_on_write=True)か、
copy() メソッドを利用すること。
import pandas as pd
df = pd.read_csv('output_pd2tokei.csv', index_col=0)
'''
国語 数学 クラス
A 65 60 1A
B 80 85 NaN
C 95 75 1C
D 65 75 1A
E 65 60 1B
'''
pd.options.mode.copy_on_write = False # デフォルト。True にすると copy。
print(pd.options.mode.copy_on_write)
d=df['国語']
d.iloc[0]=100
print(df.iloc[0,0],d.iloc[0]) # 100 100
'''
pandas の options
.options.mode.copy_on_write は、デフォルトで False
d は df の view(参照渡し) になっているので
d の値を変更 --> df の値も変化
print(df.iloc[0,0],d.iloc[0]) --> 100 100
d の値を変更 --> df の値が変化しないようにするには、(d と df は独立の変数としたい)
pd.options.mode.copy_on_write = True
d=df['国語']
d.iloc[0]=100
print(df.iloc[0,0],d.iloc[0]) --> 65 100
または、copy()メソッドを利用する
d=df['国語'].copy()
補足
Jupyterを利用しているとき、 pd.options.mode.copy_on_write=True の設定を行うと、
カーネルの再起動がされるまで有効。デフォルトのFalseに戻すには、
pd.options.mode.copy_on_write=False を実行すること。
'''
・データフレームの統計
# ---------------------------------------------------------------------
# 統計
df.describe(include='all') # 全ての情報 include='all'
'''
国語 数学 クラス
count 3.0 3.000000 2
unique NaN NaN 2
top NaN NaN 1A
freq NaN NaN 1
mean 80.0 73.333333 NaN
std 15.0 12.583057 NaN
min 65.0 60.000000 NaN
25% 72.5 67.500000 NaN
50% 80.0 75.000000 NaN
75% 87.5 80.000000 NaN
max 95.0 85.000000 NaN
'''
df.describe() # 数値の情報が出力される
'''
国語 数学
count 3.0 3.000000
mean 80.0 73.333333
std 15.0 12.583057
min 65.0 60.000000
25% 72.5 67.500000
50% 80.0 75.000000
75% 87.5 80.000000
max 95.0 85.000000
'''
df.describe(exclude='number') # 数値以外の情報が出力される
'''
クラス
count 2
unique 2
top 1A
freq 1
'''
df.astype(object).describe() # objectとしての統計
'''
国語 数学 クラス
count 3 3.0 2
unique 3 3.0 2
top 65 60.0 1A
freq 1 1.0 1
'''
# その他の例
df.describe(include=int) # int型データのみ
df.astype({'国語': int, '数学': str}).describe() # 型を変換して
# 個々の統計
df['国語'].count() # 個数 国語の個数: 5
df['国語'].max() # 最大値 国語の最大値: 95
df['国語'].min() # 最小値 国語の最小値: 65
df['国語'].mean() # 平均 国語の平均: 74.0
df['国語'].median() # 中央値 国語の中央値: 65.0
df['国語'].std() # 標準偏差 国語の標準偏差: 13.416407864998739
df['国語'].nunique() # 国語のユニークな値の数: 3
df['国語'].value_counts() # 度数分布(結果は Series 型)
'''
国語
65 3
80 1
95 1
Name: count, dtype: int64
'''
df['数学'].mode() # 最頻値 (結果は Series 型)
'''
0 60
1 75
Name: 数学, dtype: int64
'''
・データに欠損値があるかを確認し、埋める
# ---------------------------------------------------------------------
# 欠損値の個数
df.isnull().sum() # 列
'''
国語 0
数学 0
クラス 1
dtype: int64
'''
df.isnull().sum(axis=1) # 行
'''
A 0
B 1
C 0
D 0
E 0
dtype: int64
'''
df.isnull()
'''
国語 数学 クラス
A False False False
B False False True
C False False False
D False False False
E False False False
.isnull() は、上のような真偽の DataFrame となる
'''
# ---------------------------------------------------------------------
# 欠損値を埋める .fillna(値)
df["クラス"] = df["クラス"].fillna('1E') # クラス列にある全ての欠損値が'1E'となる
'''
個別に設定するときは、.isnull()と条件を組み合わせること
'''
・相関係数、クロス集計、ピボットテーブル
import pandas as pd
# 読み込み
df = pd.read_csv('output_pd2tokei.csv', index_col=0)
'''
国語 数学 クラス
A 65 60 1A
B 80 85 NaN
C 95 75 1C
D 65 75 1A
E 65 60 1B
'''
# ---------------------------------------------------------------------
# 相関係数
df.loc[:,['国語','数学']].corr()
'''
国語 数学
国語 1.000000 0.567282
数学 0.567282 1.000000
'''
# クロス集計
pd.crosstab(df['クラス'], df['国語'])
'''
国語 65 95
クラス
1A 2 0
1B 1 0
1C 0 1
'''
pd.crosstab(df['クラス'], df['国語'], margins=True, normalize='index') # 列ごとの正規化 normalize='columns'
'''
国語 65 95
クラス
1A 1.00 0.00
1B 1.00 0.00
1C 0.00 1.00
All 0.75 0.25
'''
# ピボットテーブル
df.pivot_table(index='クラス',columns=None, values=['国語','数学'],aggfunc='count') #sum
'''
国語 数学
クラス
1A 2 2
1B 1 1
1C 1 1
'''
・ピボットテーブルとグラフの作成
import seaborn as sns
import matplotlib.pyplot as plt
import japanize_matplotlib
# ピボットテーブルの作成
pivot=df.pivot_table(index='クラス',columns=None, values=['国語','数学'],aggfunc='count')
# グラフの表示設定
sns.set(style='darkgrid',font='IPAexGothic') # seaborn の設定
plt.rcParams['figure.figsize'] = (10, 5)
plt.rcParams['font.size'] = 12
# print(plt.rcParams['font.family']) # ['IPAexGothic']
plt.ylabel("人")
# グラフ作成
pivot.plot.bar(title="クラス別国語、数学の受験者数") # bar pie
plt.show()
この記事が気に入ったらサポートをしてみませんか?