今回はテーブル型のデータを扱うデータフレームについても解説です。
C#でいうところのDataTableだと考えていただければイメージし易いでしょう。
ただ、データフレームの方が高機能であり、且つDataTableより簡単な記述でデータの抽出や更新ができます。
DataFrameの構造
最初にDataFrameの構造について、DataTableと比較してみましょう。
下記の図は左がDataTable,右がDataFrameになります。
両方ともテーブル構造のデータを保持する点は同じですが、DataFrameは次の点が異なります。
- DataFrameは行に任意の名前を付けることが出来る
- セル位置の指定は列、行の順番で指定(DataTableは行、列で指定)
- 列名を設定しなければ列番号を使えるが、設定した後は列番号が使えなくなる
- 1つの列に異なる型の値が登録できる(例:1列目1行に123,2行目に’ABC’等)

データフレームから特定の列を抜き出すことができるのですが、抜き出したデータはSeries という型になります。
この概念はC#のDataTableにはありませんが、例えるなら列名を1つだけ保持するDataTableみたいなものです。

最初の準備(インストールとインポート)
データフレームは pandas というパッケージ(ライブラリ)をインポートすることで使えます。
pandas はPythonに標準搭載しているわけではないのですが、Anaconda をインストールするとPythonと一緒にインストールされます。
従って、プログラムの先頭に次の1行を記述するだけで使えるようになります。
1 |
import pandas as pd |
もし インストールされていない場合は、次のコマンドを実行することでインストールできます。
1 2 3 4 5 |
# anaconda を使わず pythonを直接インストールしていた場合 pip install pandas #anaconda を使ってインストールする場合 conda install pandas |
だいたいどのサンプルを見ても、pandas は pd という略称で使われることが多いようです。
また、データフレームのインスタンスは df と記述されている事が多いので、この記事でも df を使います。
df の記述があれば、データフレームのインスタンスであると解釈して下さい。
データフレームの作成
空のデータフレームを作成する場合は次のようになります。
1 |
df = pd.DataFrame() |
一方、任意の行列データ初期化したデータフレームを作る場合、第一引数にリスト又はタプルの配列として値を指定します。
例えば、2行3列のデータフレームを作成する場合、1行目を[1,2,3]、2行目を[4,5,6]で初期化すると次のようになります。
1 |
df = pd.DataFrame([ [1,2,3],[4,5,6] ]) |
次に、初期化する際に列名と行名を指定してみましょう。
indexとcolumnの引数にリストまたはタプルで名前を列挙します。
この時、実際の列数、行数と同じ個数で名前を登録しないとエラーになりますのでご注意ください。
1 2 3 4 5 |
# リストを使った方法 df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=['row1','row2'],columns=['col1','col2','col3']) # タプルを使った方法 df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=('row1','row2'),columns=('col1','col2','col3')) |
結果は次のようになります。
col1 | col2 | col3 | |
row1 | 1 | 2 | 3 |
row2 | 4 | 5 | 6 |
インデックスの設定/変更/削除
インデックスはデータフレームを作成する際に作ることができますが、後から追加することも可能です。この場合、 index プロパティ、column プロパティにリスト又はタプルで名前をセットします。
1 2 |
df.index = ['RowNo1','RowNo2'] df.columns = ['ColNo1',ColNo2','ColNo3'] |
結果は次のようになります。
ColNo1 | ColNo2 | ColNo3 | |
RowNo1 | 1 | 2 | 3 |
RowNo2 | 4 | 5 | 6 |
index や column が既に設定されている場合は、新しく設定した名前に置き換えられます
インデックスはデータフレームを作成する際に作ることができますが、後から追加することも可能です。この場合、 index プロパティ、column プロパティにリスト又はタプルで名前をセットします。
1 2 |
df.index = ['row1','row2'] df.columns = ['col1',col2','col3'] |
結果は次のようになります。
col1 | col2 | col3 | |
row1 | 1 | 2 | 3 |
row2 | 4 | 5 | 6 |
インデックスをリセット(削除)する場合、reset_index() を使います。
尚、インデックスとカラムの状態(カラムが重複するなど)によってエラーが発生する場合がありますが、この時は引数に drop=True を指定します。
1 2 3 4 5 |
# インデックスをリセット df.reset_index() # リセットすると 'cannot insert xxxx, already exists' というエラーが出る場合は下記 df.reset_index(drop=True) |
col1 | col2 | col3 | |
0 | 1 | 2 | 3 |
1 | 4 | 5 | 6 |
特定の要素(セル)へのアクセス方法
冒頭にも軽く説明しましたが、列と行を指定することで任意のセルにアクセス可能です。
とはいえ、データフレームはいくつもの指定方法が用意されていますので、ここで整理しておきたいと思います。
添え字による指定
列名、行名を指定が設定されていない場合は、列番号、行番号で指定できますが、列名、行名を設定する場合は少しだけ注意が必要で、列名を登録した時点で列番号による指定ができなくなります。
これは、列名、行名の初期値として0から始まる数値の連番が設定されていると解釈できます。

列名無し | 列名有り | |
行名無し | [列番号][行番号] | [列名][行番号] |
行名有り | [列番号][行番号] [列番号][行名] | [列名][行番号] [列名][行名] |
1 2 3 4 5 |
df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=['row1','row2'],columns=['col1','col2','col3']) #データフレームから1行1列にあるセルの値を取得する記述 val = df['col1'][0] val = df['col1']['row1'] |
列名/行名のプロパティを用いた指定
列名や行名を設定すると、データフレームにその列名、行名のプロパティが自動生成されるので、それを使って値の参照や登録が可能になります。
1 2 3 4 5 6 |
df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=['row1','row2'],columns=['col1','col2','col3']) #データフレームから1行1列にあるセルの値を取得する記述 val = df.col1[0] val = df.col1['row1'] val = df.col1.row1 |
loc 、iloc を使った指定
loc の添え字で列と行を指定することも可能です。
注意点としては、loc に指定する添え字の順番は、DataTableと同様に行、列の順で指定するという点です。
df.loc [行名,列名] (尚、名前を設定していない場合は列又は行番号での指定が可能)
行名、列名を設定していなければ行番号、列番号での指定が可能ですが、行名、列名を設定してしまうと、その時点で行番号、列番号は使えなくなります。
loc を使わない場合、行については名前を設定しても行番号が使えましたので、より厳しくなっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#データフレームから1行1列にあるセルの値を取得する記述(列名、行名を設定しない場合) df = pd.DataFrame([ [1,2,3],[4,5,6] ]) val = df.loc[0,0] #データフレームから1行1列にあるセルの値を取得する記述(行名のみ設定した場合) df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=['row1','row2']) val = df.loc['row1',0] #データフレームから1行1列にあるセルの値を取得する記述(行名、列名ともに設定した場合) df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=['row1','row2'],columns=['col1','col2','col3']) val = df.loc['row1','col1'] |
一方、列名の設定有無に関わらず、行番号、列番号で指定したい場合の為に iloc が用意されています。
df.iloc [行番号,列番号]
1 2 3 4 |
#データフレームから1行1列にあるセルの値を取得する記述(行名、列名ともに設定した場合) df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=['row1','row2'],columns=['col1','col2','col3']) val = df.iloc[0,0] |
行に列に名前を付けてアクセスしたい場合は loc、単純に行番号、列番号でアクセスしたい場合は iloc という具合に使い分けましょう。
at を使った指定
at も loc と同様に行と列を指定することでセルにアクセスするのですが、 loc との違いは速度です。
at は1つのセルに対してアクセスすることに特化した作りになっています。
loc は汎用的な仕様になっており、列だけを取り出したり、スライサーを使って指定範囲を取り出す事が可能な分、at より処理速度が劣るのです。
at はloc と同様に行名、列名を使う at と、常に行番号、列番号を使う iat が用意されています。
df.at [行名,列名] (尚、名前を設定していない場合は列又は行番号での指定が可能)
df.iat[行番号,列番号]
大量のデータに対して、行と列を指定して処理するような場合は at の方が向いています。
1 2 3 4 5 |
#データフレームから1行1列にあるセルの値を取得する記述(行名、列名ともに設定した場合) df = pd.DataFrame([ [1,2,3],[4,5,6] ],index=['row1','row2'],columns=['col1','col2','col3']) val = df.at['row1','col1'] val = df.iat[0,0] |
特定の行、又は列の操作
説明の前に以下のデータフレームがあると仮定しておきます。
1 2 3 |
df = pd.DataFrame([ [10,20,30,40,50],[11,21,31,41,51],[12,22,32,42,52],[13,23,33,43,53],[14,24,34,34,54] ]) df.index=['row1','row2','row3','row4','row5'] df.columns=['col1','col2','col3','col4','col5'] |
col1 | col2 | col3 | col4 | col5 | |
row1 | 10 | 20 | 30 | 40 | 50 |
row2 | 11 | 21 | 31 | 41 | 51 |
row3 | 12 | 22 | 32 | 42 | 52 |
row2 | 13 | 23 | 33 | 43 | 53 |
row5 | 14 | 24 | 34 | 44 | 54 |
特定の列の操作
列名を指定するだけで抜き出すことが可能です。
df[列名]
返される値は Series 型になります。
1 |
val = df['col1'] |
新しい列を追加する場合は、新しい列名を指定して、行数だけ値を用意したリスト又はタプルを代入します。
下記の様に記述すれば、’col6′ という列がデータフレームの右端に新たに追加されます。
1 |
df['col6'] = [60,61,62,63,64] |
同様に、Seriesを使ってデータフレームを追加することも可能です。
この場合は、データフレームの列名とSeriesの名前、及び行数を一致させる必要があります。
もし行名を設定している場合、行名も指定しなければなりません。
従って、df[‘col6’] = [60,61,62,63,64] は次のような記述になります。
1 |
df['col6'] = pd.Series(data=[60,61,62,63,64],index=['row1','row2','row3','row4','row5'],name='col6') |
列名を指定するのは面倒ですが、データフレームへの代入時、Seriesの名前や列名が存在しているもののみ処理してくれるので、既存のデータフレームに対して一部のみを書き換える場合には便利です。
さて、既存の列だけを取り出した場合、Series 型が返され、Series 型をデータフレームを追加したり、任意の列を上書きすることができました。
この機能を利用すると、データフレームの特定の列に演算を行うことが簡単にできてしまいます。
例えば、’col5′ の内容を2乗するような場合は次のように記述すれば実現できます。
1 |
df['col5'] = df['col5'] * df['col5'] |
上記の結果df は次のようになります。

複数列の抽出
複数の列を同時に取り出す事も出来ます。
この場合、データフレームの添え字に列名のリストを指定します。
df[ [列名1,列名2,・・・] ]
この場合に返される値は Sries 型ではなく データフレームとなります。
例えば、’col2’と ‘col3’ の列だけを抜き出したデータフレームを作りたい場合は次のようになります。
1 |
df[ ['col2','col3'] |
指定範囲の行の抽出
データフレームの添え字に列名を指定することで、その列を取り出すことが出来ましたが、列名ではなくスライサーを使うと特定の行範囲を取り出すことが出来ます。
df[行の開始位置:行の終了位置]
この時、取り出した内容はデータフレーム型になります。
つまり、既存のデータフレームから必要な行範囲を持つデータフレームを作り出したことになります。
1 |
var = df[1:4] |
Python 場合、スライサーの終了位置は、その行を含みませんので、1行目~3行目までが抽出されることになります。

条件指定による行の抽出
データフレームの添え字部分に条件式を書くことで、その条件に一致する行を抽出できます。
df[df[列名] 比較演算子 値] 又は df.query(条件式)
例えば、’col2’の内容が22以下の行を抽出するには次のように記述します。
1 2 |
var = df[df['col2'] <= 22] var = df.query('col2 <= 22') |

query を使うと文字列として条件式を指定できるので、動的にデータを抽出したい場合に便利です。
また、queryの中は演算式も記述できるので、df.query(‘col2 * 2 <= 44’) という書き方もOKです。
DataTableでいうところの dt.Select(“条件式”) みたいなものですね。
df[df[‘col2’] <= 22]の補足ですが、df[‘col2′] は、’col2’ 列の内容を Series 型で取り出すという動作をします。
この時 <=22 という条件に一致する行は True、不一致の行は False が返されます。
この結果がdfの添え字に働くことで、結果的に条件に一致した行が取り出せるという仕組みです。
行または列の削除
行又は列を削除する場合は、 drop メソッドを使います。
この時、行を削除する場合は axis=0、列を削除する場合は axis=1 を指定します。
行を削除 df.drop(列名,axis=0) 又は df.drop([列名1,列名2,・・・],axis=0)
列を削除 df.drop(列名,axis=1) 又は df.drop([列名1,列名2,・・・],axis=1)
1 2 |
dr.drop('row2',axis=0) df.drop('col2',axis=1) |
但し、元のデータフレームから列が削除されるのではなく、列が削除されたデータフレームが新たに作られることに注意して下さい。
もし、元のデータフレームから削除したいなら、次のように記述します。
1 2 |
df = df.drop('row2',axis=0) df = df.drop('col2',axis=1) |
表形式データを縦方向に展開
表形式のデータを縦方向に展開するには melt() メソッドを使います。
例えば、下記のデータがあるとします。
1 2 3 4 5 6 7 8 |
df = pd.DataFrame([ ['2023-01-01',11,21,31], ['2023-01-02',12,22,32], ['2023-01-03',13,23,33], ['2023-01-04',14,24,34], ['2023-01-05',15,25,35], ]) df.columns=['日付','担当1','担当2','担当3'] |
melt() で id_vars に縦展開する時のキー項目を指定するだけです。
df.melt(id_vars=キー項目)
ちなみに、キー項目が複数ある場合は、id_vars=[キー項目1,キー項目2,・・・] のようにリストで指定します。
今回は日付という1つの項目を使いますので、以下の様に記述できます。
1 |
df.melt(id_vars='日付') |
結果は次の通りで、var_nameと value_nameを指定しなかったため、カラム名が自動で割り当てられ、”variable”,と “value”になっています。

vavariable と value に任意の名前を付ける場合は、var_nameとvalue_name を使います。
df.melt(id_vars=[キー項目],var_name=名前1,value_name=名前2
1 |
df.melt(id_vars='日付',var_name='担当者',value_name='契約件数') |
縦方向のデータを表形式に展開
melt() は、表形式を時系列の縦長形式に変換するメソッドでしたが、その逆で縦長形式を表形式に変換するために pivot() 、pivot_table() メソッドが用意されています。
pivot()メソッド
pivot() メソッドの書式は次の通りです。indexに「キー項目となるカラム名」を、coliumns に「横展開したいカラム名」を、values に「セルに展開したい値が格納されているカラム名」を指定します。
df.pivot(index=キー項目,columns=横展開カラム名,values=セル展開カラム名)
尚、キー項目が複数ある場合は、リスト形式で指定します。
では、次のテストデータ(meltで作成したデータと同じ)で実験してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
df = pd.DataFrame([ ['2023-01-01','担当1',11], ['2023-01-02','担当1',12], ['2023-01-03','担当1',13], ['2023-01-04','担当1',14], ['2023-01-05','担当1',15], ['2023-01-01','担当2',21], ['2023-01-02','担当2',22], ['2023-01-03','担当2',23], ['2023-01-04','担当2',24], ['2023-01-05','担当2',25], ['2023-01-01','担当3',31], ['2023-01-02','担当3',32], ['2023-01-03','担当3',33], ['2023-01-04','担当3',34], ['2023-01-05','担当3',35] ]) df.columns=['日付','担当者1','契約件数'] |
このデータに対して、下記の引数で呼び出してみます。
1 |
df.pivot(index='日付',columns='担当者',values='契約件数') |
結果は以下の通りです。

pivot() の注意点として、キー項目で指定したカラムに重複データがあると、エラーになる点です。
ValueError: Index contains duplicate entries, cannot reshape

重複しているデータを横展開したい場合は、次に紹介するpivot_table()を使います。
pivot_table()メソッド
pivot_table() は、キー項目で指定したカラムに重複データがあった場合、指定した集計を行ってくれるため、重複エラーは発生しません。
引数には、indexに「キー項目となるカラム名」、coliumns に「横展開したいカラム名」、values に「セルに展開したい値が格納されているカラム名」、aggfuncに「重複データの集計方法」を指定します。
df.pivot_table(index=キー項目,columns=横展開カラム名,values=セル展開カラム名,aggfunc=計算方法)
pivot() と同様、キー項目が複数ある場合は、リスト形式で指定します。
先ほどのテストデータに、重複データを2件登録しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
df = pd.DataFrame([ ['2023-01-01','担当1',11], ['2023-01-01','担当1',11],# 重複データ ['2023-01-02','担当1',12], ['2023-01-03','担当1',13], ['2023-01-04','担当1',14], ['2023-01-05','担当1',15], ['2023-01-01','担当2',21], ['2023-01-02','担当2',22], ['2023-01-02','担当2',88],# 重複データ ['2023-01-03','担当2',23], ['2023-01-04','担当2',24], ['2023-01-05','担当2',25], ['2023-01-01','担当3',31], ['2023-01-02','担当3',32], ['2023-01-03','担当3',33], ['2023-01-04','担当3',34], ['2023-01-05','担当3',35], ]) df.columns=['日付','担当者','契約件数'] |
引数は pivot() と同じですが、重複データが合計を計算するため aggfunc=’sum’ を指定しています。
1 |
df.pivot_table(index='日付',columns='担当者',values='契約件数',aggfunc='sum') |
結果は次の様になりました。左表の赤枠が重複データ、右表の赤枠が集計結果です。今回は sum を指定しているので、重複データが合計されました。

次に、aggfunc を省略してみます。省略すると自動的に計算式が「平均値」となります。
1 |
df.pivot_table(index='日付',columns='担当者',values='契約件数') |
平均値なので 2023-01-01 における 担当1 の値は変化がありません。一方、2023-01-02 における担当者2 は 55 になりました。

aggfuncには文字列又は関数が指定できます。主なものについて一覧にまとめておきます。
計算方式 | 文字列指定 | 関数指定 | 備考 |
---|---|---|---|
平均 | ‘mean’ | np.mean | |
合計 | ‘sum’ | np.sum | |
最大 | ‘max’ | np.max | |
最小 | ‘min’ | np.min | |
中央値 | ‘median’ | np.median | |
標準偏差 | ‘std’ | np.std | |
分散 | ‘var’ | np.var | |
歪度 | ‘skew’ | scipy.stats.skew | |
尖度 | ‘kurt’ | scipy.stats.kurtosis | |
件数 | ‘count’ | ー | |
最大値を持つインデックス | ‘idxmax’ | ー | [5,10,50,3,8] の場合、最大値50 を持つインデックスを返す。但し、 インデックスはグループ内ではなく 全データに割り当てられた番号。 |
最小値を持つインデックス | ‘idxmin’ | ー | [5,10,50,3,8] の場合、最小値3 を持つインデックスを返す。但し、 インデックスはグループ内ではなく 全データに割り当てられた番号。 |
ユニークな値の件数 | ‘nunique’ | ー | [5,10,5,3,8] の場合、5を1件 として数え、4を返す |
最初に見つかった値 | ‘first’ | ー | |
最後に見つかった値 | ‘last’ | ー | |
ラムダ式 | ー | lambda x:~ | 例:最大-最小を求めるラムダ式 lambda x: max(x) – min(x) |
カスタム関数 | ー | 任意の関数名 | 例:最大-最小を求める関数 def custom_agg(arr): val = np.max(arr) – np.min(arr) return val 例:関数の呼び出し方法 aggfunc=custom_agg |
まとめ
今回は基礎編ということで、
- データフレームの作り方
- 特定の要素(セル)へのアクセス方法
- 列の取り出し方と更新方法
- 行の取り出し方(スライサーとqueryメソッド)
- 行または列の削除方法
- 表形式データを縦方向に展開
- 縦方向のデータを表形式に展開
について解説しました。
データフレームには数多くのメソッドが用意されており、今回紹介したのはほんお一部ですが、基本的な操作については一通り解説致しました。
次回は応用編ということで、もう少し細かい部分を掘り下げてみたいと思います。