Pandas は、データ解析のためのオープンソースの Python ライブラリです。構造化されたデータを効率的かつ直感的に取り扱い、処理するために設計されています。
Pandas の主要なデータ構造は Series
と DataFrame
の 2 つです。Series は基本的に任意の種類のデータを一次元でラベル付けした配列であり、DataFrame は二次元で、異種データの可能性があり、任意の種類のデータをラベル付けした配列である。異種混合とは、すべての「行」が同じ大きさである必要はないことを意味します。
この記事では、DataFrame
を作成する最も一般的な方法と、その構造を変更する方法について説明します。
Jupyter NotebookはDataFrame
を視覚的に表現するのに適しているので、これを使用することにします。しかし、どのIDEでも DataFrame
オブジェクトに対して print()
ステートメントを呼び出すだけで、この作業を行うことができます。
DataFrameの作成
手動で作成する場合でも、ファイルなどのデータソースから生成する場合でも、DataFrame
を作成するときは常に、データを含む行のシーケンスとして、表形式で順序付ける必要があります。
つまり、人の名前と年齢の情報を含む DataFrame
を作成する場合、すべての行が同じように情報を保持していることを確認する必要があります。
不一致があると DataFrame
に不具合が生じ、エラーが発生します。
空のデータフレームを作成する
空のDataFrame
を作るには、次のようにすればよい。
import pandas as pd
dataFrame1 = pd.DataFrame()
この空の DataFrame
に行と列を追加し、その構造を操作する方法を見ていきましょう。
リストからのデータフレームの作成
フィールドの順序が同じ行のシーケンス」の原則に従って、そのようなシーケンスを含むリスト、またはそのようなシーケンスを提供するように zip()
– 連結した複数のリストから DataFrame
を作成することができます。
import pandas as pd
listPepper = [
[50, "Bell pepper", "Not even spicy"],
[5000, "Espelette pepper", "Uncomfortable"],
[500000, "Chocolate habanero", "Practically ate pepper spray"]
]
dataFrame1 = pd.DataFrame(listPepper)
dataFrame1
# If you aren't using Jupyter, you'll have to call `print()`
# print(dataFrame1)
この結果、以下のようになります。
同じ効果は、データを複数のリストにして、それらを一緒に zip()
– することによっても得ることができます。この方法は、前述したような、特定の行ごとのデータを1つの単位としてリストに格納する方法ではなく、1つの列(フィールド)の値をリストにしてデータを提供する場合に使用することができる。
つまり、列のデータをすべて(順番に)個別に持っていて、それをまとめると行になるということです。
作成した DataFrame
では、カラムや行のラベルがあまり情報を含んでいないことにお気づきかもしれません。DataFrame` を作成する際に、追加情報を渡すことができます。その1つが、使用したい行と列のラベルを指定することです。
import pandas as pd
listScoville = [50, 5000, 500000]
listName = ["Bell pepper", "Espelette pepper", "Chocolate habanero"]
listFeeling = ["Not even spicy", "Uncomfortable", "Practically ate pepper spray"]
dataFrame1 = pd.DataFrame(zip(listScoville, listName, listFeeling), columns = ['Scoville', 'Name', 'Feeling'])
# Print the dataframe
dataFrame1
この場合、先ほどと同じ出力が得られますが、より意味のあるカラム名を指定する必要があります。
もう一つのデータ表現として、次のような形式の辞書のリストとしてデータを提供することもできる。
listPepper = [
{ columnName1 : valueForRow1, columnName2: valueForRow1, ... },
{ columnName1 : valueForRow2, columnName2: valueForRow2, ... },
...
]
この例では、次のような表現になる。
listPepper = [
{'Scoville' : 50, 'Name' : 'Bell pepper', 'Feeling' : 'Not even spicy'},
{'Scoville' : 5000, 'Name' : 'Espelette pepper', 'Feeling' : 'Uncomfortable'},
{'Scoville' : 500000, 'Name' : 'Chocolate habanero', 'Feeling' : 'Practically ate pepper spray'},
]
そして、先ほどと同じように DataFrame
を作成します。
dataFrame1 = pd.DataFrame(listPepper)
辞書からデータフレームを作成する
辞書は、列単位でデータを提供するもうひとつの方法である。各カラムには、そのカラムに含まれる値の行のリストが順番に与えられます。
dictionaryData = {
'columnName1' : [valueForRow1, valueForRow2, valueForRow3...],
'columnName2' : [valueForRow1, valueForRow2, valueForRow3...],
....
}
先ほどと同じデータを、辞書の形式を使って表現してみよう。
import pandas as pd
dictionaryData = {
'Scoville' : [50, 5000, 500000],
'Name' : ["Bell pepper", "Espelette pepper", "Chocolate habanero"],
'Feeling' : ["Not even spicy", "Uncomfortable", "Practically ate pepper spray"]
}
dataFrame1 = pd.DataFrame(dictionaryData)
# Print the dataframe
dataFrame1
この場合、期待される出力は次のようになります。
ファイルからデータフレームを読み込む
データフレームを読み書きするために、多くのファイルタイプがサポートされています。それぞれのファイルタイプの関数は、 read_csv()
, read_excel()
, read_json()
, read_html()
など、同じ構文で定義されています。
非常に一般的なファイルタイプは .csv
(Comma-Separated-Values) です。行は行として提供され、そこに含まれるはずの値はデリミタ (多くの場合、カンマ) で区切られています。sep` 引数で別のデリミタを指定することもできます。
もし、 .csv
というファイル形式に馴染みがなければ、次のような例をご覧ください。
Scoville, Name, Feeling
50, Bell pepper, Not even spicy
5.000, Espelette pepper, Uncomfortable
10.000, Serrano pepper, I regret this
60.000, Bird's eye chili, 4th stage of grief
500.000, Chocolate habanero, Practically ate pepper spray
2.000.000, Carolina Reaper, Actually ate pepper spray
このファイルの最初の行はカラム名であることに注意してください。もちろん、Pandas がどの行からデータを読み込み始めるかを指定することもできますが、デフォルトでは Pandas は最初の行をカラム名として扱い、2 行目からデータを読み込み始めます。
import pandas as pd
pepperDataFrame = pd.read_csv('pepper_example.csv')
# For other separators, provide the `sep` argument
# pepperDataFrame = pd.read_csv('pepper_example.csv', sep=';')
pepperDataFrame
#print(pepperDataFrame)
という出力が得られます。
DataFrameの操作
このセクションでは、 DataFrame
の構造を変更するための基本的なメソッドについて説明します。しかし、このトピックに入る前に、個々の行や行のグループ、そしてカラムにアクセスする方法を知っておく必要があります。
要素へのアクセス/位置決め
Pandasはデータを選択する方法として、loc[]
とiloc[]
の2種類の方法があります。
loc[]では、row['Value'] や column['Other Value'] のようにラベルを使用して行や列を選択することが可能です。一方、
iloc[]`は、選択したい項目のインデックスを渡す必要があるため、数値のみを使用することができます。また、列の名前を括弧で囲んで渡すだけで選択することもできます。実際にどのように動作するか見てみましょう。
# Location by label
# Here, '5' is treated as the *label* of the index, not its value
print(pepperDataFrame.loc[5])
# Location by index
print(pepperDataFrame.iloc[1])
出力します。
Scoville 2.000.000
Name Carolina Reaper
Feeling Actually ate pepper spray
Name: 5, dtype: object
Scoville 5.000
Name Espelette pepper
Feeling Uncomfortable
Name: 1, dtype: object
これは、0からnまでの行のグループに対しても有効である。
print(pepperDataFrame.loc[:1])
これは出力する。
重要なことは、iloc[]
は常に整数を想定していることです。loc[]`は他のデータ型もサポートしています。ここでも整数を使うことができますが、文字列のような他のデータ型も使うことができます。
また、要素の特定の値にアクセスすることもできます。例えば、2行目の要素にアクセスして、その値 Name
だけを返したい場合です。
print(pepperDataFrame.loc[2, 'Name'])
この場合、次のような値が返されます。
Chocolate habanero
列へのアクセスは、 dataFrameName.ColumnName
または dataFrameName['ColumnName']
と記述することで簡単に行うことができます。カラムはあらかじめ定義されたPandasのメソッドと同じ名前を持つことができ、そのような場合に最初のオプションを使用するとバグを引き起こす可能性があるので、2番目のオプションが推奨されます。
print(pepperDataFrame['Name'])
# Same output as print(pepperDataFrame.Name)
これは次のように出力されます。
0 Bell pepper
1 Espelette pepper
2 Chocolate habanero
Name: Name, dtype: object
カラムは loc[]
と iloc[]
を使用してアクセスすることもできます。例えば、 0...n
(n
は行数) からすべての行にアクセスし、最初のカラムを取得することにします。これは、前の行のコードと同じ出力になります。
dataFrame1.iloc[:, 1] # or dataFrame1.loc[:, 'Name']
インデックスを操作する
インデックスは DataFrame
の行のラベルであり、行にアクセスするときに使用するものです。Pandas が DataFrame
を作成するときに割り当てるデフォルトのインデックスを変更しなかったので、すべての行は 0 以上の整数値でラベル付けされています。
最初に DataFrame
のインデックスを変更する方法は、 set_index()
メソッドを使用することです。このメソッドに DataFrame
内の任意のカラムを渡すと、それが新しいインデックスになります。つまり、自分でインデックスを作成することもできますし、単純にカラムをインデックスとして割り当てることもできます。
このメソッドは元の DataFrame
を変更するのではなく、新しいインデックスを持つ新しい DataFrame
を返すので、変更を保持したい場合は、戻り値を DataFrame
変数に代入するか、 inplace
フラグを True
にセットしなければならないことに注意ください。
import pandas as pd
listPepper = [
{'Scoville' : 50, 'Name' : 'Bell pepper', 'Feeling' : 'Not even spicy'},
{'Scoville' : 5000, 'Name' : 'Espelette pepper', 'Feeling' : 'Uncomfortable'},
{'Scoville' : 500000, 'Name' : 'Chocolate habanero', 'Feeling' : 'Practically ate pepper spray'},
]
dataFrame1 = pd.DataFrame(listPepper)
dataFrame2 = dataFrame1.set_index('Scoville')
dataFrame2
出力
これも同じように動作します。
dataFrame1 = pd.DataFrame(listPepper)
dataFrame1.set_index('Scoville', inplace=True)
dataFrame1
デフォルトでないインデックスができたので、新しい値のセットを使うことができます。 reindex()
を使用すると、既存の行とマッチしないインデックスに対して、Pandas は自動的に NaN
で値を埋めてくれます。
new_index = [50, 5000, 'New value not present in the data frame']
dataFrame1.reindex(new_index)
出力します。
オプションのパラメータ fill_value
を設定することで、Pandas が欠損値を埋めるためにどのような値を使うかを制御することができます。
dataFrame1.reindex(new_index, fill_value=0)
出力
DataFrameに新しいインデックスを設定したので、
loc[]` はそのインデックスで動作するようになりました。
dataFrame1.loc[5000]
# dataFrame1.iloc[5000] outputs the same in this case
この結果、次のようになります。
Name Espelette pepper
Feeling Uncomfortable
Name: 5000, dtype: object
行の操作
行の追加と削除は、loc[]
の使い方に慣れていれば簡単にできます。存在しない行を設定すると、その行が作成されます。
dataFrame1.loc[50] = [10000, 'Serrano pepper', 'I regret this']
dataFrame1
出力される。
行を削除したい場合は、drop()
関数にそのインデックスを指定します。この関数には、オプションのパラメータとして axis
が渡されます。この axis
には、 0
/index
または 1
/columns
を指定することができます。この値に応じて、 drop()
関数は呼び出された行を削除するか、呼び出された列を削除します。
パラメータ axis
に値を指定しないと、デフォルトでは axis
が 0
であるため、対応する行が削除されます。
dataFrame1.drop(1, inplace=True)
# Same as dataFrame1.drop(1, axis=0)
出力されます。
テーブルの中に既に存在する行の名前を変更することもできます。rename()` 関数は、変更したい行の辞書を受け取ります。
dataFrame1.rename({0:"First", 1:"Second"}, inplace=True)
出力されます。
出力:
drop()と
rename()はオプションのパラメータ -
inplaceも受け付けることに注意してください。これを
True(デフォルトは
False) に設定すると、Pandas は新しいものを返す代わりに、元の
DataFrameを変更するように指示します。もし未設定の場合、変更を持続させるために、結果の
DataFrame` を新しいものにパックする必要があります。
もう一つ知っておくと便利なメソッドが drop_duplicates()
関数で、 DataFrame
から重複した行をすべて削除することができます。重複する2つの行を追加することで、これを実演してみましょう。
dataFrame1.loc[3] = [60.000, "Bird's eye chili", "4th stage of grief"]
dataFrame1.loc[4] = [60.000, "Bird's eye chili", "4th stage of grief"]
dataFrame1
すると、次のような出力が得られます。
ここで、 drop_duplicates()
を呼び出すことができます。
dataFrame1.drop_duplicates(inplace=True)
dataFrame1
そして、重複する行は削除されます。
列の操作
行の追加と同じように、新しい列を追加することができます。
dataFrame1['Color'] = ['Green', 'Bright Red', 'Brown']
dataFrame1
出力
唯一の違いは、オプションのパラメータ axis
を 1
に設定することで、Pandas が行ではなく列を削除したいことを認識できるようにすることです。
dataFrame1.drop('Feeling', axis=1, inplace=True)
出力
カラムの名前を変更する場合、 rename()
関数に対して、オプションのパラメータ columns
に “change dictionary” の値をセットして、カラムを変更することを明確に伝える必要があります。
dataFrame1.rename(columns={"Feeling":"Measure of Pain"}, inplace=True)
出力します。
この関数が新しい DataFrame
を返す代わりに、元の DataFrame
を変更したい場合は、オプションのパラメータ inplace
を True
に設定することができます。
結論
この記事では、Pandas の DataFrame
がどのようなものか、データを保存するために使用される Pandas フレームワークの重要なクラスであることを説明しました。
リストと辞書を使用して手動で DataFrame
を作成する方法を学び、その後ファイルからデータを読み込みました。
loc[]と
iloc[]` を使って、データの位置を決め、新しい行と列を作成し、既存の行と列の名前を変更し、そしてそれらを削除しています。