ウェブサイト検索

pandasの紹介


Pandasは、BSDライセンスの下でリリースされた無料のオープンソースのPythonライブラリです。2008年にWes McKinneyによって最初に開発され、IntelやNvidiaなどの企業によってサポートされています。データ分析と操作を目的としており、Excelスプレッドシート、カンマ区切り値(CSV)ファイルなど、さまざまなソースからデータを読み書きするのに簡単に使用できます。

このチュートリアルでは、pandasの基本概念を探求し、表形式のデータを操作し、統計やプロットを作成する方法を学びます。

このチュートリアルでは、あなたは学びます:

  • pandasライブラリのインストール方法
  • 表形式データの操作方法
  • 統計を作成する方法
  • プロットを作成する方法

インストール

pandasライブラリは、最も使用されているすべてのLinuxディストリビューションの公式リポジトリで利用可能です。Fedoraにpandasをインストールするには、dnfパッケージマネージャを使用します:

sudo dnf install python3-pandas

Debianおよびその派生版では、代わりにaptを使用できます。

sudo apt install python3-pandas

Archlinuxにパッケージをインストールするには、pacmanを使用します:

sudo pacman -S python-pandas

ソフトウェアのネイティブインストールはパッケージマネージャを介して行うことで、システム統合の最大化を提供します。しかし、ディストリビューションが維持するアプリケーションやライブラリのバージョンは、しばしば上流のバージョンに遅れをとることがあります。また、互換性の理由などで特定のバージョンが必要になる場合もあります。そのような場合、pandasをインストールするための推奨される方法は、Pythonのパッケージマネージャであるpipを使用することです:

pip install pandas

このインストール方法は汎用的で、特権昇格を必要としません。pipを使用することで、プロジェクト特有の仮想環境内にパッケージをインストールすることもできます。

データフレーム

私たちがpandasライブラリを使う際に最初に馴染む必要があるクラスはDataFrameです:これは二次元のデータ構造を表現するために使用され、SQLテーブルやExcelスプレッドシートの同等物と見なすことができます。このチュートリアルの後の方で、DataFrameオブジェクトがどのように外部ソースからデータを読み取ることによって初期化されるかを実際に見ていきます。しかしその前に、まずはゼロから作成する方法を見ていきましょう。

ゼロからDataFrameを作成するのは非常に簡単です。その方法の一つは、クラスのコンストラクタを呼び出し、辞書を最初の引数として渡すことです。この方法でデータを渡すと、辞書のキーが列ラベルとして使用され、関連する値が「列」を埋めるために使用されます。これを例で明確にしましょう。「指輪物語」のキャラクターについての以下の情報を持つDataFrameオブジェクトを作成したいとしましょう:

名前年齢レース
フロド50ホビット
ギャラドリエル8000エルフ
アラゴルン87男

名前と人種は文字列で表され、整数は各キャラクターの年齢を表すために使用されます。以下は、DataFrameを初期化する方法です:

import pandas as pd

data = {
  "Name": ["Frodo", "Galadriel", "Aragorn"],
  "Age": [50, 8000, 87],
  "Race": ["Hobbit", "Elf", "Man"]
}
characters = pd.DataFrame(data)

代替として、同じデータをリストのリストを使用して渡すことができます。それぞれが「行」を表します。この方法でオブジェクトを初期化する際には、columns パラメータを使用して列ラベルを明示的に指定する必要があります:

data = [
    ['Frodo', 50, 'Hobbit'],
    ['Galadriel', 8000, 'Elf'],
    ['Aragorn', 87, 'Man']
]
characters = pd.DataFrame(data, columns=['Name', 'Age', 'Race'])

DataFrameオブジェクトを「きれいな」形で表示するには、単に「print」するだけです。

print(characters)

結果:

	        Name   Age    Race
	0      Frodo    50  Hobbit
	1  Galadriel  8000     Elf
	2    Aragorn    87     Man

インデックスラベルとインデックス位置

特に指定がない場合、上記のように、数値ラベルが行を識別するために使用されます。これらのラベルはしばしば「インデックス」と呼ばれます。そのような場合、ラベルは0から始まる位置に対応します。ただし、インデックスラベルは初期化時にindexパラメータを介して明示的に定義することができ、またはrenameメソッドを使用して変更することができます。

characters.rename(index={0: "r0", 1: "r1", 2: "r2"}, inplace=True)

上記のメソッドを呼び出した後の私たちの DataFrame オブジェクトはこのようになります(inplace=True を使用したため、オブジェクトはその場で変更されました):

         Name   Age    Race
r0      Frodo    50  Hobbit
r1  Galadriel  8000     Elf
r2    Aragorn    87     Man

上記のDataFrameの最初のインデックスのラベルはr0ですが、インデックスの位置は0です。インデックスラベルとインデックス位置の両方を使用して、行と列を選択することができます。たとえば、インデックスラベルで最初の行を選択するには、locプロパティを使用します:

characters.loc['r0']

位置によってインデックスで選択するためには、代わりに iloc プロパティを使用します:

characters.iloc[0]

行で作業する

特定のインデックスラベルや位置によって特定の行を選択する方法のいくつかの例を見ました。次に、条件を使用して行をフィルタリングする方法を見てみましょう。50歳以上のキャラクターに関連するすべての行を取得したいとします。「年齢」列の値が50より大きいかどうかをテストする必要があります。以下のように実行できます:

older_than_fifty = characters[characters['Age'] > 50]

上の例では、characters['Age'] > 50 条件を使用しました。この条件は DataFrame オブジェクトに適用され、Series オブジェクトを返します。pandasにおける「Series」オブジェクトは、任意のデータ型を含むことができる一次元配列を表します。この場合、「Age」列の値が条件に一致する場合は True を、それ以外の場合は False を含みます。以下はオブジェクトの「印刷された」表現です:

0    False
1     True
2     True

条件によって返される Series オブジェクトは、元の DataFrame オブジェクトに対する「フィルター」として使用されます。対応する行のみが返されます:

      	Name   Age Race
1  Galadriel  8000  Elf	
2    Aragorn    87  Man

論理演算子を使用して複数の条件を指定できます。たとえば、50歳以上で名前が「A」で始まる行を選択したい場合は、次のように書きます:

characters[(characters['Age'] > 50) & (characters['Name'].str.startswith('A'))]

各条件を括弧で囲み、pandasの論理演算子(&、|、~)のいずれかを使用しました。これはPythonのand、or、notに相当します。上の例でも、アクセサであるstrを使用したことがわかります。アクセサを使うと、Seriesの値にアクセスしたり、利用可能なメソッドを使ってそれらを変更したりできます。これは、データ型に応じて明らかに変わります。この場合、キャラクター名は文字列で表されるため、strアクセサを使用し、同名のネイティブPythonメソッドと同様に動作するstartswithメソッドを適用しました。予想通り、条件を適用すると次の結果が得られます:

      Name  Age Race
2  Aragorn   87  Man

行の追加と置き換え

既存の DataFrame オブジェクトに 行 を追加するのは非常に簡単です。特定の行を取得するために loc および iloc プロパティを使用する方法を見ましたが、これらは値を割り当てるためにも使用できます。新しい行を作成するには、新しいインデックスラベル(または iloc を使用する場合はインデックス位置)を提供し、それに対して行の値を割り当てる必要があります。私たちの DataFrame オブジェクトに新しいキャラクターを追加したいとしましょう。次のように書くことができます:

characters.loc[3] = {'Name': 'Bilbo', 'Age': 110, 'Race': 'Hobbit'}

既存のインデックスを使用する場合、既存の行は置き換えられます。たとえば、インデックスラベル1(ガラドリエルに関するもの)をテオデンキャラクターに関する情報を持つ行に置き換えるには、次のように記述します。

characters.loc[1] = {'Name': 'Theoden', 'Age': 71, 'Race': 'Man'}

複数の行を一度に追加したい場合はどうすればいいですか?そのような作業を達成するために、追加したい行を含む新しい DataFrame オブジェクトを作成し、次に concat 関数を使用して元の DataFrame とマージします:

additional_characters = pd.DataFrame({ 
  'Name': ['Boromir', 'Denethor', 'Elrond'], 
  'Age': [41, 89, 6000], 
  'Race': ['Man', 'Man', 'Elf'] 
}) 
all_characters = pd.concat([characters, additional_characters], ignore_index=True)

上記の例では、concatを呼び出し、マージしたいDataFrameオブジェクトのリストを最初の引数として渡しました。また、ignore_index引数をTrueに設定することで、既存のインデックスラベルを保持しないことを指定しました。

行を削除する

行を削除するには、DataFrameクラスのdropメソッドを使用できます。dropメソッドはインデックスラベルに基づいて動作するため、テーブルの最初の行(インデックスラベル0)を削除したい場合は、次のように実行します:

characters.drop(0, inplace=True)

メソッドが受け付ける最初で唯一の位置引数は、単一のラベルまたはインデックスラベルのリストであることができます。デフォルトでは、dropメソッドは元のオブジェクトをその場で変更せず、新しいオブジェクトを返します。この動作を変更したい場合は、上記の例のようにinplaceパラメーターをTrueに設定する必要があります。

列で作業する

データフレームオブジェクトから「年齢」列の値のみを取得したいとします。これは非常に簡単な操作です。私たちがする必要があるのは、列ラベルを辞書のキーとして使用することだけです:

ages = characters['Age']

このように DataFrame オブジェクトの列にアクセスすると、すでに見たように Series オブジェクトが返されます:

0      50
1    8000
2      87
Name: Age, dtype: int64

複数の列は、DataFrameオブジェクトから一度に「スライス」することができます。例えば:

subset = characters[['Name', 'Age']]

複数の列を選択すると、新しいDataFrameオブジェクトが返されます(Seriesオブジェクトは一次元です)。

列を追加する

さて、DataFrameオブジェクトにキャラクターの住居に関する情報を保持するための新しい列を追加したいとしましょう。再び、辞書に新しいキーを追加するかのように行うことができます。次のように書きます:

characters['Residence'] = ['The Shire', 'Lothlorien', 'Minas Tirith']

元の DataFrame は今次のようになっているはずです。

        Name   Age    Race     Residence
0      Frodo    50  Hobbit     The Shire
1  Galadriel  8000     Elf    Lothlorien
2    Aragorn    87     Man  Minas Tirith

上記の方法は、DataFrameオブジェクトをインプレースで修正します。代わりに、結果を新しいオブジェクトに割り当てたい場合は、assignメソッドを使用します:

result = characters.assign(Residence=['The Shire', 'Lothlorien', 'Minas Tirith'])

特定の位置に列を挿入するには、代わりに insert メソッドを使用できます。例えば、「名前」とラベル付けされた列の後、つまり最初の列(位置 0)の後に列を挿入したいとします。その場合、次のように書きます:

characters.insert(1, "Residence", ['The Shire', 'Lothlorien', 'Minas Tirith'])

列を削除する

列を削除するには、行を削除するのと同じ方法を使用できます。変更が必要なのは axis パラメータだけで、それを 1 に設定します(デフォルトは 0 です)。これにより、列を操作することを指定します。たとえば、「Name」ラベルの列を削除するには、次のように書きます:

characters.drop("Name", axis=1, inplace=True)

あるいは、columnsパラメータを使って削除する列の名前を指定することもできます:

characters.drop(columns=["Name"], inplace=True)

単一の値にアクセスする

これまでに、全体の行や列を管理する方法のいくつかの例を見てきました。代わりに、DataFrameオブジェクトの「フロド」キャラクターの年齢だけを読み取ったり変更したりしたいとします。行/列ペアの単一の値(スプレッドシート用語で「セル」)を取得するには、atプロパティを使用できます。

frodo_age = characters.at[0, 'Age'] 

代わりに新しい値を割り当てるには:

characters.at[0, 'Age'] = 51 

atプロパティは、locと同様に「ラベル」で動作します。そのため、上記の例で使用した最初の引数は、角括弧内にあるのは行インデックスの位置ではなく、インデックスラベルです。インデックスの位置で作業をしたい場合は、代わりにiatを使用する必要があります。「フロド」に関連する行は最初の行(位置0)であり、「年齢」列は2番目の列(位置1)であるため、次のように書きます:

characters.iat[0, 1] = 51

計算を行う

既存のデータに基づいて計算を行うことが重要です。pandasライブラリは、そのような操作を非常に簡単に実行させてくれます。ここに例があります。"all_characters"というDataFrameオブジェクトで、エルフ以外のキャラクターの平均年齢を計算したいとします。以下のように進めることができます。まず、「Race」列の値が「Elf」でない行を選択します。この操作は新しいDataFrameオブジェクトを返します。それから、そこから「Age」列を"スライス"し、Seriesオブジェクトを取得し、その上でmeanメソッドを呼び出します:

all_characters[all_characters['Race'] != 'Elf']['Age'].mean() 

予想通り、結果として66.75を得ました。もう一つの例です。今回は最も若い非エルフキャラクターを見つけたいと思います:

characters[characters['Race'] != 'Elf']['Age'].min()

人種に基づいてキャラクターの平均年齢を取得したい場合はどうしますか?そのような場合、groupbyメソッドを使用する必要があります。

all_characters.groupby('Race')['Age'].mean()

私たちは次の結果を得ました:

Race
Elf          7000.000000
Hobbit         50.000000
Man            72.333333

これは、私たちのDataFrameに含まれるデータに対して実行できる計算の基本的な例のいくつかです!

外部ソースからデータを読み書きすること

以前の例では、DataFrameオブジェクトをゼロから作成しました。しかし、ほとんどの場合、ExcelスプレッドシートやCSVファイルなどの外部ソースからデータを読み取る必要があります。このような操作は、専用のread_*およびto_*メソッドを使用して実行できます。いくつかの例を見てみましょう。

Microsoft Excel スプレッドシート「characters.xlsx」に含まれているデータから DataFrame オブジェクトを作成したいとしましょう。最初に、openpyxl ライブラリがインストールされていることを確認する必要があります。

pip install openpyxl

その後、スプレッドシートを読み込み、DataFrameを作成するためには、次のように書きます:

characters = pd.read_excel('characters.xlsx')

同様に、CSVファイルからデータをインポートするには、次のように書きます:

characters = pd.read_csv('characters.csv')

DataFrameのデータをExcelスプレッドシートにエクスポートするのは、同様に簡単です:

characters.to_excel('characters.xlsx')

代わりにCSVファイルに書き込むには、

characters.to_csv('characters.csv')

それらのメソッドは、多くのパラメータを受け入れ、データがファイルにどのように読み込まれるか、または書き込まれるかをカスタマイズできます。明らかな理由から、ここですべてのパラメータを探ることはできませんので、詳細についてはpandasのAPIリファレンスを参照してください。

プロットを作成する

プロットを作成するために、matplotlibライブラリがバックエンドとして使用されるため、インストールする必要があります。

pip install matplotlib

デフォルトでは、matplotlibはプロットをファイルに書き込むための「agg」バックエンドを使用します。作成したプロットをグラフィカルインターフェースを使用して可視化したい場合は、対応するバックエンドをインストールする必要があります。この例では、Qt5バックエンドを使用します。

pip install pyqt5

プロットには数値データのみが報告されます。以下は、DataFrame内のキャラクター間の年齢差を可視化するためのプロットを作成する方法です。

import matplotlib.pyplot as plt
all_characters.plot(x="Name")  

plot メソッドは、DataFrame オブジェクトと Series オブジェクトの両方に適用できます。例では、x パラメータを使用して x 軸に使用するラベルを指定しました。これは、数値ラベルの代わりにキャラクターの名前を使用するために行いました。プロットを視覚化するために、plt モジュールが提供する show 関数を呼び出します:

plt.show()

作成できるプロットの種類は多くありますが、デフォルトは「線」プロットです。どのプロットを使用するかは、plotメソッドのkindパラメータを指定することで決めることができるか、専用のメソッドを直接使用することができます。私たちのケースでは、「棒」縦プロットを作成するために、次のように書くことができます:

all_characters.plot(x="Name", kind="bar")

または、ただ電話してください:

all_characters.plot.bar(x="Name")  

プロットをファイルに直接保存するには、pltモジュールのsavefig関数を呼び出し、引数としてファイル名を渡します:

plt.savefig('lotr_characters_age_comparison')

締めくくりの考え

このチュートリアルでは、Pythonのpandasライブラリの使用に関する基本的な概念を学びました。私たちは、表形式のデータを作成し管理する方法や、統計とプロットを作成する方法を見ました。この素晴らしいライブラリを使用して達成できることの表面をほんの少し触れただけです。マスターする最良の方法は、それを使用し、もちろん公式ドキュメントを読むことです。

関連記事: