まずはここから!Pandasのimport方法と最初のステップ の詳細な解説
データ分析、機械学習、データサイエンスの世界に足を踏み入れると、必ずと言っていいほど耳にする、あるいは実際に使うことになるライブラリがあります。それが「Pandas」です。Pythonでデータ操作を行う上で、Pandasはもはやデファクトスタンダードと言える存在です。表形式データの扱いに非常に長けており、複雑なデータ処理も直感的かつ効率的に行うことができます。
この記事では、Pandasを使い始めるにあたっての「最初の最初」である、Pandasのimport方法から、基本的なデータ構造、そして簡単なデータ操作までを、徹底的に詳しく解説します。この記事を読み終える頃には、Pandasを使ってデータを読み込み、その概要を把握し、基本的な操作を行うための基礎がしっかりと身についているはずです。
データ分析の旅を始める準備はいいですか?さあ、Pandasの世界へ飛び込みましょう!
1. はじめに:Pandasとは?なぜ学ぶ必要があるのか?
Pandasは、Pythonプログラミング言語用のオープンソースのデータ分析および操作ツールです。特に、表形式データ(スプレッドシートやデータベースのテーブルのような構造)や時系列データの扱いに強力な機能を提供します。
Pandasの主要な特徴
- 高速で柔軟なデータ構造:
Series
(1次元)とDataFrame
(2次元)という主要なデータ構造を提供し、大量のデータを効率的に扱うことができます。 - データの読み書き: CSV、Excel、SQLデータベース、JSON、HDF5など、様々な形式のデータを簡単に読み込み、書き出すことができます。
- データのクリーニングと前処理: 欠損値の処理、データの結合、変換、重複の削除など、データ分析において必須となる前処理作業を効率的に行えます。
- データの探索と分析: データの統計量の計算、グループ化、ピボットテーブルの作成など、データの特性を理解し、分析するための多様な機能があります。
- 時系列データ分析: 時系列データの生成、変換、リサンプリングなど、時系列分析に特化した便利な機能も備えています。
なぜPandasを学ぶ必要があるのか?
現実世界のデータは、ほとんどの場合、きれいに整理された単一のファイルとして存在することは稀です。複数のファイルに分かれていたり、欠損値が含まれていたり、フォーマットが統一されていなかったりと、分析の前に「前処理」が必要になります。Pandasは、このような現実のデータに立ち向かうための強力な武器となります。
- データサイエンスの必須ツール: データ分析、機械学習、統計モデリングなど、データサイエンスのあらゆる分野でPandasは標準的に使用されています。
- 効率的なデータ操作: Pythonのリストや辞書を使ってデータ操作を行うよりも、Pandasのデータ構造と機能を使うことで、より簡潔に、そしてより高速に処理を行うことができます。
- NumPyとの連携: Pandasは内部的にNumPyという数値計算ライブラリを利用しており、高速な数値計算の恩恵を受けつつ、より高レベルなデータ操作が可能です。
- 他のライブラリとの連携: MatplotlibやSeaborn(データの可視化)、Scikit-learn(機械学習)など、他の主要なPythonライブラリとシームレスに連携できます。
Pandasをマスターすることは、Pythonを使ったデータ分析のスキルを飛躍的に向上させることと同義です。それでは、その第一歩を踏み出しましょう。
2. Pandasのインストール
Pandasを使うためには、まずPython環境にPandasライブラリをインストールする必要があります。Pythonのインストールがまだ済んでいない場合は、先にPythonをインストールしてください。公式ウェブサイトからダウンロードするか、Anacondaのようなディストリビューションを利用するのが一般的です。
Python環境の準備(推奨:Anaconda/Miniconda)
データ分析を行う多くの人々は、AnacondaまたはMinicondaの使用を推奨しています。これらはPython本体に加えて、データ分析によく使われるライブラリ(NumPy, SciPy, Matplotlib, Pandasなど)や、パッケージ管理ツールであるconda
、仮想環境管理機能などが一括で提供される便利なディストリビューションです。
- Anaconda: Python本体、conda、そしてデータサイエンスに必要な多くのライブラリが最初から含まれています。容量は大きいですが、環境構築の手間が省けます。
- Miniconda: Python本体とcondaのみが含まれています。必要なライブラリは後から個別にインストールします。容量は小さいです。
公式サイトからインストーラーをダウンロードし、指示に従ってインストールしてください。インストール後、ターミナル(コマンドプロンプト)を開き、python --version
やconda --version
を実行して、正しくインストールされたか確認できます。
Anaconda/Minicondaを使う場合、多くの場合Pandasはデフォルトでインストールされています。念のため、インストール済みか確認する方法は後述します。
pipを使ったインストール方法
Pythonの標準的なパッケージ管理システムであるpip
を使ってPandasをインストールすることもできます。Pythonだけを単体でインストールした場合や、仮想環境に個別にライブラリをインストールしたい場合に利用します。
ターミナル(Windowsの場合はコマンドプロンプトまたはPowerShell、macOS/Linuxの場合はターミナル)を開き、以下のコマンドを実行します。
bash
pip install pandas
これにより、最新版のPandasライブラリがインストールされます。もし特定のバージョンをインストールしたい場合は、以下のようにバージョン番号を指定します。
bash
pip install pandas==1.5.3
(1.5.3
の部分をインストールしたいバージョン番号に置き換えてください)
pip
コマンドが見つからない場合や、Pythonのバージョンが複数インストールされている場合は、以下のように特定のPythonインタープリタに関連付けられたpip
を使う必要があるかもしれません(環境によります)。
bash
python -m pip install pandas
インストール確認方法
Pandasが正しくインストールされたかどうかは、Pythonのインタラクティブシェルやスクリプトから確認できます。
ターミナルでpython
と入力してPythonのインタラクティブシェルを起動するか、またはJupyter NotebookやJupyterLab、VS Codeなどの開発環境を開いて、以下のコードを実行します。
python
import pandas as pd
print(pd.__version__)
もしPandasがインストールされていれば、エラーは発生せず、インストールされているPandasのバージョン番号(例: 1.5.3
)が表示されるはずです。
1.5.3
もしModuleNotFoundError: No module named 'pandas'
のようなエラーが表示された場合は、インストールができていないか、Python環境が間違っている可能性があります。pip install pandas
コマンドを再実行するか、使用しているPython環境を確認してみてください。
これで、Pandasを使うための準備が整いました!
3. Pandasのimport方法:import pandas as pd
の秘密
PandasライブラリをPythonプログラムの中で使うためには、まずそれを「インポート」する必要があります。インポートとは、外部のモジュールやライブラリを現在のプログラムで利用可能にする手続きです。
Pandasをインポートする最も一般的で推奨される方法は、以下のコードです。
python
import pandas as pd
この一行のコードが、これからPandasを使ったデータ分析の始まりとなります。では、このコードは何を意味しているのでしょうか?
import pandas
これは、Pythonの標準的なimport構文です。import pandas
と書くことで、pandas
という名前のライブラリ全体をインポートします。インポート後、Pandasが提供する関数やクラスを利用する際には、その名前の前にpandas.
というプレフィックス(接頭辞)を付ける必要があります。例えば、CSVファイルを読み込むための関数はread_csv
ですが、これを呼び出すときはpandas.read_csv()
のように書きます。
as pd
as pd
の部分は、インポートしたモジュールに「別名(エイリアス)」を付けるための構文です。ここでは、pandas
というライブラリにpd
という別名を付けています。
なぜこのような別名を付けるのでしょうか?主な理由は以下の通りです。
- コードの簡潔性:
pandas.
と毎回書くのは少し長くて手間がかかります。pd.
と書くだけで済むようになり、タイピング量を減らせます。 - コードの可読性:
pd
はPandasライブラリのエイリアスとして、データサイエンスコミュニティで最も広く、普遍的に使われている慣習です。pd.
というプレフィックスを見れば、それがPandasの機能を使っていることが誰にでもすぐに分かります。他の人が書いたコードを読む際にも、この慣習を知っていると理解が容易になります。 - エラーの削減: 長い名前を何度も手で入力すると、スペルミスなどのヒューマンエラーが発生しやすくなります。短いエイリアスを使うことで、このようなエラーを減らすことができます。
このimport pandas as pd
という書き方は、Pandasを使用する際の標準的なお作法です。データ分析関連のコード例やチュートリアルでは、ほとんどの場合この形式が使われています。したがって、あなた自身のコードでもこの慣習に従うことを強く推奨します。これにより、あなたのコードは他のPandasユーザーにとって読みやすく、理解しやすいものになります。
その他のimport方法(非推奨)
理論的には、他にもPandasをインポートする方法はあります。しかし、これらは通常推奨されません。
-
from pandas import *
:
python
from pandas import *
これはPandasライブラリ内のすべての名前(関数名、クラス名など)を現在の名前空間に直接インポートする方法です。この方法を使うと、pd.read_csv()
ではなく単にread_csv()
のように、プレフィックスなしでPandasの機能を利用できるようになります。
しかし、これは非常に非推奨です。 どのような名前がインポートされるのかコードを読んだだけでは分かりにくくなり、他のライブラリやプログラム内で定義されている名前と衝突(名前の競合)する可能性が高まります。コードの可読性と保守性を著しく損なうため、避けるべきです。 -
特定の機能のみをインポート:
python
from pandas import DataFrame, read_csv
これはPandasライブラリの中から特定の機能(ここではDataFrame
クラスとread_csv
関数)だけをインポートする方法です。この方法を使うと、DataFrame(...)
やread_csv(...)
のように、pd.
プレフィックスなしで利用できます。
もし使う機能がごくわずかであればこの方法も考えられますが、Pandasは多機能なライブラリであり、通常は様々な機能を使います。使うたびに個別にインポートするのは手間がかかりますし、やはりpd.
プレフィックスがないと、その機能がPandas由来なのか他のライブラリ由来なのかがコードを読んだだけでは判別しにくくなります。したがって、特別な理由がない限りimport pandas as pd
を使うのが最善です。
まとめ:import pandas as pd
がベストプラクティス
Pandasを使う準備ができたら、コードの冒頭で必ずimport pandas as pd
と記述しましょう。これはPandasを扱う上での基本的なルールであり、データ分析コミュニティにおける共通言語のようなものです。
“`python
Pandasをインポートする
import pandas as pd
これでpdという別名を使ってPandasの機能にアクセスできる
例:CSVファイルを読み込む
df = pd.read_csv(‘data.csv’)
“`
インポート方法を理解したところで、いよいよPandasの最も重要なデータ構造について見ていきましょう。
4. Pandasの主要なデータ構造:SeriesとDataFrame
Pandasの強力さの根源は、その提供する高速で柔軟なデータ構造にあります。主に以下の二つがあります。
Series
(シリーズ): 1次元のラベル付き配列DataFrame
(データフレーム): 2次元のラベル付きデータ構造(スプレッドシートやデータベースのテーブルのようなもの)
これらを理解することが、Pandasを使ったデータ操作の基礎となります。
4.1. Series (シリーズ):1次元のラベル付き配列
Series
は、一次元の配列のようなデータ構造です。NumPyの一次元配列(ndarray
)に似ていますが、各要素に「インデックス(ラベル)」を付けることができる点が大きく異なります。インデックスは、データの各要素を識別するための名前や番号のようなものです。
Seriesは、例えば「ある日の株価の終値のリスト」「あるクラスの生徒のテストの点数リスト」「ある商品の売上データ」といった、単一の属性を持つデータの集まりを表現するのに適しています。
Seriesの作成
様々な方法でSeriesを作成できます。最も一般的なのは、PythonのリストやNumPy配列、または辞書から作成する方法です。
A. リストやNumPy配列から作成
単純なリストやNumPy配列からSeriesを作成する場合、デフォルトでは0から始まる整数がインデックスとして自動的に割り当てられます。
“`python
Pandasをインポート
import pandas as pd
import numpy as np # NumPyも一緒に使うことが多いのでインポート
リストからSeriesを作成
data_list = [10, 20, 30, 40, 50]
s1 = pd.Series(data_list)
print(“リストから作成したSeries:”)
print(s1)
print(“-” * 20)
NumPy配列からSeriesを作成
data_numpy = np.array([100, 200, 300, 400])
s2 = pd.Series(data_numpy)
print(“NumPy配列から作成したSeries:”)
print(s2)
“`
実行結果例:
“`
リストから作成したSeries:
0 10
1 20
2 30
3 40
4 50
dtype: int64
NumPy配列から作成したSeries:
0 100
1 200
2 300
3 400
dtype: int64
“`
左側に表示されている0, 1, 2, ...
がインデックス、右側に表示されているのが各要素の値です。dtype
はデータの型を示しています(ここでは64ビット整数)。
カスタムインデックスを指定して作成
Seriesを作成する際に、任意のリストや配列をindex
引数に渡すことで、独自のインデックスを設定できます。インデックスは、数値だけでなく文字列なども指定可能です。
“`python
カスタムインデックスを指定してSeriesを作成
data = [100, 200, 300, 400]
custom_index = [‘a’, ‘b’, ‘c’, ‘d’]
s3 = pd.Series(data, index=custom_index)
print(“カスタムインデックス付きSeries:”)
print(s3)
print(“-” * 20)
異なる型のデータを含むSeries(Pandasが適切なdtypeを推測)
mixed_data = [10, ‘apple’, True, 3.14]
s4 = pd.Series(mixed_data)
print(“異なる型のデータを含むSeries:”)
print(s4)
“`
実行結果例:
“`
カスタムインデックス付きSeries:
a 100
b 200
c 300
d 400
dtype: int64
異なる型のデータを含むSeries:
0 10
1 apple
2 True
3 3.14
dtype: object
“`
カスタムインデックスを使うと、インデックス名で直感的にデータにアクセスできるようになります。異なる型のデータが混在する場合、dtype
はそれらを包括できる型(例: object
)になります。
B. 辞書から作成
Pythonの辞書からSeriesを作成することもできます。この場合、辞書のキーがSeriesのインデックスに、辞書の値がSeriesの値になります。
“`python
辞書からSeriesを作成
data_dict = {‘東京’: 1400, ‘大阪’: 880, ‘名古屋’: 230, ‘福岡’: 160} # 人口データ(単位:万人)
s5 = pd.Series(data_dict)
print(“辞書から作成したSeries:”)
print(s5)
“`
実行結果例:
辞書から作成したSeries:
東京 1400
大阪 880
名古屋 230
福岡 160
dtype: int64
辞書から作成すると、インデックス名が最初から設定されたSeriesを簡単に作ることができます。
Seriesの基本操作と属性
作成したSeriesに対して、様々な操作を行うことができます。
-
インデックスを使った要素へのアクセス: インデックスを指定して個々の要素にアクセスできます。デフォルトの整数インデックスでも、カスタムインデックスでも同様です。
“`python
print(“s1[0]:”, s1[0]) # デフォルトの整数インデックス
print(“s3[‘b’]:”, s3[‘b’]) # カスタムインデックス
print(“s5[‘大阪’]:”, s5[‘大阪’]) # 辞書から作成したSeriesのインデックス存在しないインデックスを指定するとエラーになる
print(s3[‘z’]) # エラー:KeyError
“`
-
スライシング: インデックスの範囲を指定して、複数の要素を選択できます。PythonのリストやNumPy配列のスライシングに似ていますが、カスタムインデックスの場合は終了位置が含まれる点が異なります(デフォルトの整数インデックスの場合はPythonのスライスと同じで含まれません)。
“`python
print(“s1[1:3]:”) # デフォルトインデックス: インデックス1から3の直前まで
print(s1[1:3])print(“-” * 20)
print(“s3[‘a’:’c’]:”) # カスタムインデックス: インデックス’a’から’c’まで 含まれる
print(s3[‘a’:’c’])
“`実行結果例:
“`
s1[1:3]:
1 20
2 30
dtype: int64
s3[‘a’:’c’]:
a 100
b 200
c 300
dtype: int64
“` -
条件を使った選択: Seriesの要素に対して条件を指定し、条件を満たす要素のみを選択できます(ブールインデックス)。
“`python
値が200より大きい要素を選択
print(“s3[s3 > 200]:”)
print(s3[s3 > 200])値が100または300の要素を選択
print(“s3[(s3 == 100) | (s3 == 300)]:”)
print(s3[(s3 == 100) | (s3 == 300)])
“`実行結果例:
s3[s3 > 200]:
c 300
d 400
dtype: int64
s3[(s3 == 100) | (s3 == 300)]:
a 100
c 300
dtype: int64 -
属性: Seriesはいくつかの便利な属性を持っています。
index
: Seriesのインデックスを取得します。values
: Seriesの値のみをNumPy配列として取得します。dtype
: Seriesのデータ型を取得します。name
: Seriesに名前を付けることができます(DataFrameの列名のようなもの)。
“`python
print(“s5.index:”, s5.index)
print(“s5.values:”, s5.values)
print(“s5.dtype:”, s5.dtype)Seriesに名前を付ける
s5.name = “主要都市人口(万人)”
print(“s5.name:”, s5.name)
“`実行結果例:
s5.index: Index(['東京', '大阪', '名古屋', '福岡'], dtype='object')
s5.values: [1400 880 230 160]
s5.dtype: int64
s5.name: 主要都市人口(万人)
SeriesはDataFrameの「列」として非常によく利用されます。次に、より複雑なデータを扱うためのDataFrameを見ていきましょう。
4.2. DataFrame (データフレーム):2次元のラベル付きデータ構造
DataFrame
はPandasの最も重要なデータ構造であり、表形式データを扱うための中心的なオブジェクトです。スプレッドシート(Excelなど)やデータベースのテーブルを想像すると理解しやすいでしょう。
DataFrameは、複数の列(カラム)と複数の行(ロウ)で構成される二次元の構造です。各列は異なるデータ型(数値、文字列、ブール値など)を持つことができます。DataFrameには、行を識別するための「インデックス」と、列を識別するための「列名(カラム名)」があります。
DataFrameは、CSVファイルやデータベーステーブルから読み込んだデータ、複数の属性(例: 氏名、年齢、性別、職業)を持つ個々の観測値の集まりなどを表現するのに最適です。
DataFrameの作成
DataFrameも様々な方法で作成できます。最も一般的なのは、辞書やNumPy配列、またはSeriesの辞書から作成する方法です。
A. 辞書から作成
キーを列名、値を列データ(リストやNumPy配列、Seriesなど)とする辞書を使ってDataFrameを作成するのが非常に一般的です。
“`python
辞書からDataFrameを作成
data = {
‘名前’: [‘佐藤’, ‘田中’, ‘山田’, ‘山本’],
‘年齢’: [25, 30, 22, 35],
‘都市’: [‘東京’, ‘大阪’, ‘名古屋’, ‘福岡’]
}
df1 = pd.DataFrame(data)
print(“辞書から作成したDataFrame:”)
print(df1)
“`
実行結果例:
辞書から作成したDataFrame:
名前 年齢 都市
0 佐藤 25 東京
1 田中 30 大阪
2 山田 22 名古屋
3 山本 35 福岡
デフォルトでは、行のインデックスは0から始まる整数になります。
カスタムインデックスを指定して作成
DataFrameを作成する際に、index
引数に行のインデックスとして使用したいリストや配列を指定できます。
“`python
カスタムインデックスを指定してDataFrameを作成
data = {
‘名前’: [‘佐藤’, ‘田中’, ‘山田’, ‘山本’],
‘年齢’: [25, 30, 22, 35],
‘都市’: [‘東京’, ‘大阪’, ‘名古屋’, ‘福岡’]
}
custom_index = [‘A’, ‘B’, ‘C’, ‘D’]
df2 = pd.DataFrame(data, index=custom_index)
print(“カスタムインデックス付きDataFrame:”)
print(df2)
“`
実行結果例:
カスタムインデックス付きDataFrame:
名前 年齢 都市
A 佐藤 25 東京
B 田中 30 大阪
C 山田 22 名古屋
D 山本 35 福岡
B. Seriesの辞書から作成
各列がSeriesであるような辞書からDataFrameを作成することもできます。これにより、各列に異なるインデックスを事前に持たせた状態でDataFrameを作成することも可能です(Pandasが自動的にインデックスを揃えようとします)。
“`python
Seriesの辞書からDataFrameを作成
s_名前 = pd.Series([‘佐藤’, ‘田中’, ‘山田’, ‘山本’], index=[‘A’, ‘B’, ‘C’, ‘D’])
s_年齢 = pd.Series([25, 30, 22, 35], index=[‘A’, ‘B’, ‘C’, ‘D’])
s_都市 = pd.Series([‘東京’, ‘大阪’, ‘名古屋’, ‘福岡’], index=[‘A’, ‘B’, ‘C’, ‘D’])
data_series_dict = {‘名前’: s_名前, ‘年齢’: s_年齢, ‘都市’: s_都市}
df3 = pd.DataFrame(data_series_dict)
print(“Seriesの辞書から作成したDataFrame:”)
print(df3)
“`
実行結果例:
Seriesの辞書から作成したDataFrame:
名前 年齢 都市
A 佐藤 25 東京
B 田中 30 大阪
C 山田 22 名古屋
D 山本 35 福岡
DataFrameを作成する際のデータソースとして、リスト、NumPy配列、辞書、Series、他のDataFrameなど、様々なものが利用できます。
DataFrameの基本操作と属性
DataFrameに対しても、様々な操作や情報取得が可能です。
-
列(カラム)の選択: DataFrameから特定の列を選択すると、その列はSeriesとして取得されます。複数の列を選択する場合は、列名のリストを指定します。
“`python
単一の列を選択(Seriesとして取得)
名前の列 = df1[‘名前’]
print(“df1[‘名前’] (Series):”)
print(名前の列)
print(“型:”, type(名前の列))print(“-” * 20)
複数の列を選択(DataFrameとして取得)
名前と年齢の列 = df1[[‘名前’, ‘年齢’]]
print(“df1[[‘名前’, ‘年齢’]] (DataFrame):”)
print(名前と年齢の列)
print(“型:”, type(名前と年齢の列))
“`実行結果例:
“`
df1[‘名前’] (Series):
0 佐藤
1 田中
2 山田
3 山本
Name: 名前, dtype: object
型:
df1[[‘名前’, ‘年齢’]] (DataFrame):
名前 年齢
0 佐藤 25
1 田中 30
2 山田 22
3 山本 35
型:
“` -
行の選択 (
loc
とiloc
): DataFrameから行を選択するには、主にloc
とiloc
というアクセサを使います。loc
: ラベル(インデックス名や列名) を使って行や列を選択します。iloc
: 整数位置(0から始まる番号) を使って行や列を選択します。
“`python
df2 (カスタムインデックス ‘A’, ‘B’, ‘C’, ‘D’ を持つDataFrame) を使用
print(“df2 (カスタムインデックス付き):”)
print(df2)
print(“-” * 20)ラベルを使って行を選択 (loc)
print(“df2.loc[‘A’] (Series):”) # インデックスラベル ‘A’ の行
print(df2.loc[‘A’])print(“-” * 20)
print(“df2.loc[[‘A’, ‘C’]] (DataFrame):”) # インデックスラベル ‘A’ と ‘C’ の行
print(df2.loc[[‘A’, ‘C’]])print(“-” * 20)
整数位置を使って行を選択 (iloc)
print(“df2.iloc[0] (Series):”) # 0番目の行 (インデックスラベル ‘A’ の行)
print(df2.iloc[0])print(“-” * 20)
print(“df2.iloc[[0, 2]] (DataFrame):”) # 0番目と2番目の行 (インデックスラベル ‘A’ と ‘C’ の行)
print(df2.iloc[[0, 2]])
“`実行結果例:
“`
df2 (カスタムインデックス付き):
名前 年齢 都市
A 佐藤 25 東京
B 田中 30 大阪
C 山田 22 名古屋
D 山本 35 福岡
df2.loc[‘A’] (Series):
名前 佐藤
年齢 25
都市 東京
Name: A, dtype: object
df2.loc[[‘A’, ‘C’]] (DataFrame):
名前 年齢 都市
A 佐藤 25 東京
C 山田 22 名古屋
df2.iloc[0] (Series):
名前 佐藤
年齢 25
都市 東京
Name: A, dtype: object
df2.iloc[[0, 2]] (DataFrame):
名前 年齢 都市
A 佐藤 25 東京
C 山田 22 名古屋
“`loc
とiloc
は、行と列の両方を指定して特定のセルや範囲を選択する際にも使います。構文はdf.loc[行セレクタ, 列セレクタ]
またはdf.iloc[行セレクタ, 列セレクタ]
です。“`python
ラベルを使って行と列を選択 (loc)
print(“df2.loc[‘A’, ‘名前’]:”, df2.loc[‘A’, ‘名前’]) # ‘A’行 ‘名前’列の単一要素
print(“-” * 20)
print(“df2.loc[[‘A’, ‘C’], [‘名前’, ‘年齢’]] (DataFrame):”) # ‘A’,’C’行 と ‘名前’,’年齢’列
print(df2.loc[[‘A’, ‘C’], [‘名前’, ‘年齢’]])
print(“-” * 20)
print(“df2.loc[‘A’:’C’, ‘年齢’:’都市’] (DataFrame – スライス):”) # ‘A’から’C’行、’年齢’から’都市’列(ラベルスライスは終端を含む)
print(df2.loc[‘A’:’C’, ‘年齢’:’都市’])print(“=” * 30)
整数位置を使って行と列を選択 (iloc)
print(“df2.iloc[0, 0]:”, df2.iloc[0, 0]) # 0行 0列の単一要素
print(“-” * 20)
print(“df2.iloc[[0, 2], [0, 1]] (DataFrame):”) # 0,2行目 と 0,1列目
print(df2.iloc[[0, 2], [0, 1]])
print(“-” * 20)
print(“df2.iloc[0:3, 1:3] (DataFrame – スライス):”) # 0から3未満行目、1から3未満列目(整数スライスは終端を含まない)
print(df2.iloc[0:3, 1:3])
“`loc
とiloc
の使い分け、特にスライスで終端を含むか含まないかは、初心者が混乱しやすいポイントです。慣れるまで意識して使い分けるようにしましょう。 -
属性: DataFrameもSeriesと同様に便利な属性を多数持っています。
index
: DataFrameの行インデックスを取得します。columns
: DataFrameの列名のリストを取得します。values
: DataFrameの値のみをNumPy配列として取得します。shape
: DataFrameの次元(行数, 列数)をタプルで取得します。info()
: DataFrameの列ごとの情報(データ型、欠損値の数など)を表示します(メソッドなので括弧が必要です)。describe()
: 数値列の基本的な統計量(平均、標準偏差、最小値、最大値など)を計算します(メソッドなので括弧が必要です)。
“`python
print(“df1.index:”, df1.index)
print(“df1.columns:”, df1.columns)
print(“df1.values:”)
print(df1.values)
print(“df1.shape:”, df1.shape)print(“-” * 20)
print(“df1.info():”)
df1.info() # メソッドなので出力は改行されるprint(“-” * 20)
df1には数値列が ‘年齢’ しかないため、それだけが表示される
print(“df1.describe():”)
print(df1.describe())
“`実行結果例:
“`
df1.index: RangeIndex(start=0, stop=4, step=1)
df1.columns: Index([‘名前’, ‘年齢’, ‘都市’], dtype=’object’)
df1.values:
[[‘佐藤’ 25 ‘東京’]
[‘田中’ 30 ‘大阪’]
[‘山田’ 22 ‘名古屋’]
[‘山本’ 35 ‘福岡’]]
df1.shape: (4, 3)
df1.info():
RangeIndex: 4 entries, 0 to 3
Data columns (total 3 columns):
# Column Non-Null Count Dtype
0 名前 4 non-null object
1 年齢 4 non-null int64
2 都市 4 non-null object
dtypes: int64(1), object(2)
memory usage: 200.0+ bytes
None
df1.describe():
年齢
count 4.000000
mean 28.000000
std 5.773503
min 22.000000
25% 24.250000
50% 27.500000
75% 31.250000
max 35.000000
``
info()は、データ分析の最初のステップでデータ構造と欠損値の有無を素早く確認するのに非常に役立ちます。
describe()`は数値データの分布を把握するのに便利です。
SeriesとDataFrameは、Pandasを使ったデータ分析の根幹をなすものです。これらの構造を理解し、基本的な作成方法やアクセス方法を習得することが、次のステップである「データの読み込み」に進むための準備となります。
5. 最初のステップ:データの読み込み
実際のデータ分析では、多くの場合、データはファイルとして保存されています。Pandasは様々なファイル形式からデータをDataFrameとして読み込むための便利な関数を提供しています。最も一般的で重要なのは、CSVファイルを読み込む関数です。
様々なデータ形式への対応
Pandasは以下のようないくつかの一般的なファイル形式の読み込み・書き出しに対応しています(読み込み関数はread_
、書き出し関数はto_
で始まります)。
- CSV (Comma Separated Values):
pd.read_csv()
,df.to_csv()
- Excel:
pd.read_excel()
,df.to_excel()
- JSON (JavaScript Object Notation):
pd.read_json()
,df.to_json()
- HTML:
pd.read_html()
- SQL Databases:
pd.read_sql()
,df.to_sql()
- Parquet, ORC, Feather: 大規模データ分析で使われる高速なバイナリ形式
- その他多数…
ここでは、最も頻繁に使われるpd.read_csv()
に焦点を当てて詳しく解説します。
pd.read_csv()
の詳細
pd.read_csv()
関数は、CSVファイルやその他の区切り文字付きテキストファイルからデータを読み込み、DataFrameとして返します。この関数には非常に多くの引数があり、様々な形式のテキストファイルを柔軟に読み込むことができます。
最も基本的な使い方は、ファイルのパス(ファイルがある場所を示す文字列)を指定するだけです。
“`python
例として、以下のような内容の ‘sample.csv’ というファイルがあると仮定します。
name,age,city
Alice,25,Tokyo
Bob,30,Osaka
Charlie,22,Nagoya
David,35,Fukuoka
まず、この内容をファイルとして保存する必要があります。
Pythonコードでファイルを作成することもできますし、手動でテキストエディタで作成しても構いません。
例として、コードで作成します。
import os
csv_content = “””name,age,city
Alice,25,Tokyo
Bob,30,Osaka
Charlie,22,Nagoya
David,35,Fukuoka
“””
file_path = ‘sample.csv’
with open(file_path, ‘w’, encoding=’utf-8′) as f:
f.write(csv_content)
print(f”‘{file_path}’ を作成しました。”)
“`
(※ 上記のファイル作成コードは、Pandasのimport方法やread_csvの使い方の本体ではありませんが、実行可能なサンプルコードとしてファイルが必要なため含まれています。)
基本的な読み込み
“`python
Pandasをインポート
import pandas as pd
CSVファイルを読み込む
ファイルは現在のスクリプトと同じディレクトリにあると仮定します。
df_from_csv = pd.read_csv(file_path) # 作成した ‘sample.csv’ を指定
print(“\nCSVファイルから読み込んだDataFrame:”)
print(df_from_csv)
“`
実行結果例:
“`
‘sample.csv’ を作成しました。
CSVファイルから読み込んだDataFrame:
name age city
0 Alice 25 Tokyo
1 Bob 30 Osaka
2 Charlie 22 Nagoya
3 David 35 Fukuoka
“`
デフォルトでは、CSVファイルの最初の行をヘッダー(列名)として解釈し、行インデックスは0から始まる整数になります。
pd.read_csv()
の主要な引数
pd.read_csv()
は非常に多機能であり、多くの引数を持ちます。データファイルが標準的なCSV形式から少し外れている場合でも、これらの引数を適切に指定することで正確に読み込むことができます。よく使われる重要な引数をいくつか紹介します。
filepath_or_buffer
: 必須。読み込むファイルのパスを示す文字列、またはURL、ファイルオブジェクトなどを指定します。sep
(separator): 区切り文字を指定します。デフォルトはコンマ(‘,’)です。タブ区切りファイルならsep='\t'
、スペース区切りファイルならsep='\s+'
(一つ以上の空白文字)などを指定します。header
: ヘッダー行として使用する行の番号(0から始まる)を指定します。デフォルトは'infer'
で、ファイルの最初の行をヘッダーと見なします。ヘッダー行がない場合はheader=None
を指定します(この場合、列名は自動的に整数になります)。複数のヘッダー行がある場合はリストで指定することもできます。index_col
: DataFrameの行インデックスとして使用する列を指定します。列の名前または列の整数位置(0から始まる)を指定できます。例えば、1番目の列をインデックスにしたい場合はindex_col=0
とします。複数の列をインデックスにしたい場合はリストで指定します(MultiIndexになります)。names
: ヘッダー行がない場合や、デフォルトの列名を上書きしたい場合に、列名のリストを指定します。header=None
と併用することが多いです。dtype
: 各列のデータ型を指定します。辞書形式で{'列名': 型}
のように指定できます。dtype={'age': 'int64', 'name': 'object'}
など。明示的に型を指定することで、メモリ使用量を最適化したり、意図しない型推測を防ぐことができます。na_values
: 欠損値(NaNなど)として解釈する値を指定します。単一の値、値のリスト、または列ごとに異なる値を指定する辞書を指定できます。例えば、na_values=['', 'N/A', 'None', '-999']
とすると、これらの文字列を読み込んだ際にNaNに変換します。encoding
: ファイルのエンコーディング(文字コード)を指定します。日本語環境では'utf-8'
や'cp932'
(Shift_JISのMicrosoft独自拡張)、'euc-jp'
などが使われます。指定しないと環境に応じたデフォルトのエンコーディングが使われますが、文字化けする場合はこの引数を試してみてください。encoding='utf-8'
を指定することが多いです。skiprows
: ファイルの先頭から読み飛ばしたい行数、または読み飛ばしたい行番号のリストを指定します。ファイルにコメント行やメタデータが含まれている場合に便利です。nrows
: ファイルの先頭から読み込む行の最大数を指定します。大規模なファイルの一部だけを確認したい場合などに便利です。parse_dates
: 日付/時刻として解釈したい列を指定します。列名や列番号のリスト、または辞書形式で指定できます。文字列として読み込まれた日付データをPandasのdatetime型に変換してくれます。
使用例:
区切り文字がタブで、2番目の列(age)をインデックスとして読み込み、”N/A”という文字列を欠損値として扱いたい場合を考えます。
(例示用にタブ区切りファイルを作成します)
“`python
tsv_content = “””id\tname\tage\tcity
1\tAlice\t25\tTokyo
2\tBob\tN/A\tOsaka
3\tCharlie\t22\tNagoya
4\tDavid\t35\tFukuoka
“””
tsv_file_path = ‘sample.tsv’
with open(tsv_file_path, ‘w’, encoding=’utf-8′) as f:
f.write(tsv_content)
print(f”‘{tsv_file_path}’ を作成しました。”)
“`
“`python
タブ区切り、インデックス指定、欠損値指定で読み込む
df_from_tsv = pd.read_csv(
tsv_file_path,
sep=’\t’, # 区切り文字をタブに指定
index_col=’id’, # ‘id’ 列を行インデックスとして使用
na_values=[‘N/A’] # ‘N/A’ という文字列を欠損値(NaN)として扱う
)
print(“\nTSVファイルから読み込んだDataFrame (オプション指定):”)
print(df_from_tsv)
“`
実行結果例:
“`
‘sample.tsv’ を作成しました。
TSVファイルから読み込んだDataFrame (オプション指定):
name age city
id
1 Alice 25.0 Tokyo
2 Bob NaN Osaka
3 Charlie 22.0 Nagoya
4 David 35.0 Fukuoka
“`
ご覧のように、id
列が行インデックスになり、age
列の”N/A”はNaN
(Not a Number, 欠損値を表す特別な浮動小数点値)に変換されています。age列のdtype
が自動的にfloat型になっているのは、NaN
が浮動小数点型であるためです。
その他の読み込み関数
pd.read_excel()
, pd.read_json()
なども同様に直感的に使用できます。
“`python
Excelファイルから読み込む (例、ファイルがないため実行はできません)
df_excel = pd.read_excel(‘data.xlsx’, sheet_name=’Sheet1′)
JSONファイルから読み込む (例、ファイルがないため実行はできません)
df_json = pd.read_json(‘data.json’)
“`
これらの関数も、read_csv
と同様に多くの引数を持っており、柔軟な読み込みが可能です。詳しくはPandasの公式ドキュメントを参照してください。
これで、外部ファイルからデータをPandasのDataFrameとして読み込む方法を学びました。データ分析の最初の、そして最も重要なステップの一つです。
6. 読み込んだデータの概要把握
データを読み込んだら、すぐに分析に入る前に、そのデータの「中身」を簡単に把握することが非常に重要です。データの形、各列の種類、欠損値の有無、数値データの分布などを確認することで、その後の分析や前処理の計画を立てやすくなります。
Pandas DataFrameは、このための便利なメソッドや属性をいくつか提供しています。
先ほど読み込んだ df_from_tsv
を例に進めます。
python
print("現在のDataFrame:")
print(df_from_tsv)
実行結果例:
現在のDataFrame:
name age city
id
1 Alice 25.0 Tokyo
2 Bob NaN Osaka
3 Charlie 22.0 Nagoya
4 David 35.0 Fukuoka
head()
と tail()
:データの先頭・末尾を確認
データの最初の数行や最後の数行を見ることで、データが正しく読み込めているか、どのような形式になっているかを確認できます。
df.head(n=5)
: データの先頭からn
行(デフォルトは5行)を表示します。df.tail(n=5)
: データの末尾からn
行(デフォルトは5行)を表示します。
“`python
print(“\nデータの先頭2行 (head(2)):”)
print(df_from_tsv.head(2))
print(“\nデータの末尾1行 (tail(1)):”)
print(df_from_tsv.tail(1))
“`
実行結果例:
“`
データの先頭2行 (head(2)):
name age city
id
1 Alice 25.0 Tokyo
2 Bob NaN Osaka
データの末尾1行 (tail(1)):
name age city
id
4 David 35.0 Fukuoka
“`
info()
:データ型と欠損値の概要を確認
info()
メソッドは、DataFrame全体の簡潔な要約を表示します。各列のデータ型、非欠損値(Nullでない値)の数、使用メモリ量などが確認できます。データ型が想定通りか、欠損値がどれくらいあるか(特に非欠損値の数が総行数より少ない列)を素早く把握するのに非常に役立ちます。
python
print("\nDataFrameの情報 (info()):")
df_from_tsv.info()
実行結果例:
“`
DataFrameの情報 (info()):
Int64Index: 4 entries, 1 to 4
Data columns (total 3 columns):
# Column Non-Null Count Dtype
0 name 4 non-null object
1 age 3 non-null float64
2 city 4 non-null object
dtypes: float64(1), object(2)
memory usage: 276.0 bytes
``
Int64Index: 4 entries, 1 to 4は、行インデックスが整数で、1から4までの4つのエントリがあることを示しています。
Data columns (total 3 columns):の下の表で、各列の名前、非欠損値の数(
Non-Null Count)、データ型(
Dtype)を確認できます。
age列の
Non-Null Countが
3 non-null` となっており、合計4行に対して1つの欠損値があることが分かります。
describe()
:数値列の統計量を確認
describe()
メソッドは、DataFrameの数値列の基本的な記述統計量(カウント、平均、標準偏差、最小値、最大値、四分位数など)を計算して表示します。数値データの分布や範囲を把握するのに役立ちます。
python
print("\n数値列の統計量 (describe()):")
print(df_from_tsv.describe())
実行結果例:
数値列の統計量 (describe()):
age
count 3.000000
mean 27.333333
std 6.506407
min 22.000000
25% 23.500000
50% 25.000000
75% 30.000000
max 35.000000
age
列について、非欠損値が3つあること(count)、平均値、中央値(50%)、四分位数などが計算されています。
文字列やカテゴリ型の列についても、include='all'
引数を指定することで同様の概要を表示できます。
python
print("\n全列の統計量 (describe(include='all')):")
print(df_from_tsv.describe(include='all'))
実行結果例:
全列の統計量 (describe(include='all')):
name age city
count 4 3.000000 4
unique 4 NaN 4
top Alice NaN Tokyo
freq 1 NaN 1
mean NaN 27.333333 NaN
std NaN 6.506407 NaN
min NaN 22.000000 NaN
25% NaN 23.500000 NaN
50% NaN 25.000000 NaN
75% NaN 30.000000 NaN
max NaN 35.000000 NaN
非数値列 (name
, city
) に対しては、要素数 (count
)、ユニークな値の数 (unique
)、最も頻繁に出現する値 (top
)、その出現頻度 (freq
)が表示されます。
shape
, columns
, index
:DataFrameの構造を確認
DataFrameの基本的な構造を把握するための属性です。
python
print("\nDataFrameの形状 (shape):", df_from_tsv.shape) # (行数, 列数)
print("DataFrameの列名 (columns):", df_from_tsv.columns) # Indexオブジェクト
print("DataFrameの行インデックス (index):", df_from_tsv.index) # Indexオブジェクト
実行結果例:
DataFrameの形状 (shape): (4, 3)
DataFrameの列名 (columns): Index(['name', 'age', 'city'], dtype='object')
DataFrameの行インデックス (index): Int64Index([1, 2, 3, 4], dtype='int64', name='id')
これにより、データの「外形」を素早く把握できます。
isnull().sum()
:列ごとの欠損値数を正確に確認
info()
でも欠損値の概要は分かりますが、各列に具体的にいくつ欠損値があるかを正確に知るには、isnull()
メソッドとsum()
メソッドを組み合わせるのが一般的です。
df.isnull()
: DataFrameと同じ形状のDataFrameを返します。元のDataFrameで値が欠損しているセルに対応する位置がTrue
、それ以外がFalse
になります。df.sum()
: デフォルトでは各列ごとに合計を計算します。ブール値 (True
/False
) に対してsum()
を行うと、True
は1、False
は0として扱われるため、結果として各列のTrue
の数、つまり欠損値の数を計算できます。
python
print("\n各列の欠損値数 (isnull().sum()):")
print(df_from_tsv.isnull().sum())
実行結果例:
各列の欠損値数 (isnull().sum()):
name 0
age 1
city 0
dtype: int64
これにより、name
列とcity
列には欠損値がなく、age
列に1つだけ欠損値があることが明確に分かります。これは、データの前処理(欠損値の補完や削除など)を行う上で非常に重要な情報です。
value_counts()
:カテゴリ列のユニークな値と出現頻度を確認
カテゴリ型の列(ユニークな値の種類が少ない列)については、どのような値が、それぞれいくつ含まれているかを知りたい場合があります。value_counts()
メソッドは、Seriesに対して呼び出すことができ、ユニークな値とその出現頻度を降順で表示します。
“`python
‘city’列はカテゴリ的なデータ
print(“\n’city’列の値の出現頻度 (value_counts()):”)
print(df_from_tsv[‘city’].value_counts())
‘age’列(欠損値を含む数値列)にも適用できる
print(“\n’age’列の値の出現頻度 (value_counts()):”)
print(df_from_tsv[‘age’].value_counts()) # デフォルトではNaNはカウントしない
“`
実行結果例:
“`
‘city’列の値の出現頻度 (value_counts()):
Tokyo 1
Osaka 1
Nagoya 1
Fukuoka 1
Name: city, dtype: int64
‘age’列の値の出現頻度 (value_counts()):
25.0 1
22.0 1
35.0 1
Name: age, dtype: int64
``
city列は全ての都市が1回ずつ出現していることが分かります。
age列では、非欠損値である25.0, 22.0, 35.0がそれぞれ1回ずつ出現しており、欠損値(NaN)はデフォルトではカウントに含まれません。
dropna=False`引数を指定すると欠損値もカウントできます。
python
print("\n'age'列の値の出現頻度 (value_counts(dropna=False)):")
print(df_from_tsv['age'].value_counts(dropna=False))
実行結果例:
'age'列の値の出現頻度 (value_counts(dropna=False)):
25.0 1
NaN 1
22.0 1
35.0 1
Name: age, dtype: int64
これでNaNが1つ含まれていることが確認できました。
これらのメソッドと属性を組み合わせることで、読み込んだデータセットの全体像を効率的に把握し、その後の分析や前処理の方向性を定めることができます。これはデータ分析パイプラインにおいて非常に重要な初期ステップです。
7. データの選択とフィルタリング
DataFrameを読み込んで概要を把握したら、次に必要となるのは、特定のデータ(特定の列、特定の行、特定の条件を満たす行など)を取り出す操作です。Pandasでは、このデータの選択(Selection)とフィルタリング(Filtering)を非常に柔軟に行うことができます。
先ほど使用した df_from_tsv
を再び使用します。
python
print("元のDataFrame:")
print(df_from_tsv)
実行結果例:
元のDataFrame:
name age city
id
1 Alice 25.0 Tokyo
2 Bob NaN Osaka
3 Charlie 22.0 Nagoya
4 David 35.0 Fukuoka
7.1. 列(カラム)の選択
DataFrameから列を選択するには、列名を指定します。結果はSeriesになります。複数の列を選択する場合は、列名のリストを指定し、結果はDataFrameになります。
- 単一列の選択:
df['列名']
- 複数列の選択:
df[['列名1', '列名2', ...]]
“`python
単一列を選択
name_column = df_from_tsv[‘name’]
print(“\n’name’列:”)
print(name_column)
print(“型:”, type(name_column))
複数列を選択
subset_df = df_from_tsv[[‘name’, ‘city’]]
print(“\n’name’列と’city’列:”)
print(subset_df)
print(“型:”, type(subset_df))
“`
実行結果例:
“`
‘name’列:
id
1 Alice
2 Bob
3 Charlie
4 David
Name: name, dtype: object
型:
‘name’列と’city’列:
name city
id
1 Alice Tokyo
2 Bob Osaka
3 Charlie Nagoya
4 David Fukuoka
型:
“`
DataFrameの列名が有効なPythonの変数名として使える場合(スペースを含まない、予約語でないなど)、属性アクセスのように.
を使って単一列を選択することもできます。df.列名
。ただし、列名にスペースが含まれる場合や、.
が他のメソッドと紛らわしい場合は使えません。df['列名']
の記法の方が汎用的で推奨されます。
“`python
属性アクセスによる列選択 (name列の場合)
name_column_attr = df_from_tsv.name # この例では列名 ‘name’ なので可能
print(“\n属性アクセスによる ‘name’ 列:”)
print(name_column_attr)
“`
7.2. 行(ロウ)の選択 (loc
と iloc
を再び)
DataFrameから行を選択する方法は、データ構造の説明で触れた loc
と iloc
アクセサが中心となります。改めて詳しく見ていきましょう。
df.loc[行ラベル]
またはdf.loc[[行ラベル1, 行ラベル2, ...]]
df.iloc[行位置]
またはdf.iloc[[行位置1, 行位置2, ...]]
また、行と列を同時に指定する場合は、df.loc[行セレクタ, 列セレクタ]
または df.iloc[行セレクタ, 列セレクタ]
の形式です。
“`python
loc: ラベルによる選択
print(“\nlocによる行選択 (id=1 の行):”)
print(df_from_tsv.loc[1]) # インデックスラベルが 1 の行
print(“\nlocによる複数行選択 (id=1 と id=3 の行):”)
print(df_from_tsv.loc[[1, 3]]) # インデックスラベルが 1 と 3 の行
print(“\nlocによる行と列の選択 (id=1 の行の name と age 列):”)
print(df_from_tsv.loc[1, [‘name’, ‘age’]])
print(“\nlocによる行と列の範囲選択 (id=1 から 3 の行の age から city 列):”)
print(df_from_tsv.loc[1:3, ‘age’:’city’]) # ラベルスライスは終端を含む
“`
実行結果例:
“`
locによる行選択 (id=1 の行):
name Alice
age 25.0
city Tokyo
Name: 1, dtype: object
locによる複数行選択 (id=1 と id=3 の行):
name age city
id
1 Alice 25.0 Tokyo
3 Charlie 22.0 Nagoya
locによる行と列の選択 (id=1 の行の name と age 列):
name Alice
age 25.0
Name: 1, dtype: object
locによる行と列の範囲選択 (id=1 から 3 の行の age から city 列):
age city
id
1 25.0 Tokyo
2 NaN Osaka
3 22.0 Nagoya
“`
“`python
iloc: 整数位置による選択
print(“\nilocによる行選択 (0番目の行):”)
print(df_from_tsv.iloc[0]) # 0番目の行 (id=1)
print(“\nilocによる複数行選択 (0番目と2番目の行):”)
print(df_from_tsv.iloc[[0, 2]]) # 0番目 (id=1) と 2番目 (id=3) の行
print(“\nilocによる行と列の選択 (0番目の行の 0番目と1番目の列):”)
print(df_from_tsv.iloc[0, [0, 1]])
print(“\nilocによる行と列の範囲選択 (0番目から3未満の行の 1番目から3未満の列):”)
print(df_from_tsv.iloc[0:3, 1:3]) # 整数スライスは終端を含まない
“`
実行結果例:
“`
ilocによる行選択 (0番目の行):
name Alice
age 25.0
city Tokyo
Name: 1, dtype: object
ilocによる複数行選択 (0番目と2番目の行):
name age city
id
1 Alice 25.0 Tokyo
3 Charlie 22.0 Nagoya
ilocによる行と列の選択 (0番目の行の 0番目と1番目の列):
name Alice
age 25.0
Name: 1, dtype: object
ilocによる行と列の範囲選択 (0番目から3未満の行の 1番目から3未満の列):
age city
id
1 25.0 Tokyo
2 NaN Osaka
3 22.0 Nagoya
“`
loc
とiloc
はDataFrameの操作で頻繁に使うため、この違いと使い方をしっかりと理解することが重要です。
7.3. 条件に基づいたフィルタリング (ブールインデックス)
データ分析では、「特定の条件を満たすデータだけを取り出したい」というケースが非常に多いです。例えば、「年齢が30歳以上の人だけ」「都市が東京の人だけ」といったフィルタリングです。Pandasでは、ブールインデックス(Boolean Indexing)という強力な機能を使ってこれを行います。
ブールインデックスとは、DataFrameと同じ形状のTrue/Falseの配列(またはSeries)を使って、Trueに対応する行(または列)だけを選択する方法です。
例として、「年齢が30歳以上の行だけ」を取り出してみましょう。
-
まず、条件式を書きます。
df_from_tsv['age'] >= 30
これはDataFrameのage
列(Series)に対して「>= 30」という条件を適用しています。結果は、各行のageが条件を満たすかどうかに応じたTrue/FalseのSeriesになります。python
condition = df_from_tsv['age'] >= 30
print("\n条件式の結果 (ブールSeries):")
print(condition)実行結果例:
条件式の結果 (ブールSeries):
id
1 False
2 False # NaN >= 30 は False になる
3 False
4 True
Name: age, dtype: bool -
このTrue/FalseのSeriesを、DataFrameの選択のためのセレクタとして使います。
python
filtered_df = df_from_tsv[condition]
print("\n年齢が30歳以上の行:")
print(filtered_df)または、ワンライナーで書くのが一般的です。
python
filtered_df_oneliner = df_from_tsv[df_from_tsv['age'] >= 30]
print("\n年齢が30歳以上の行 (ワンライナー):")
print(filtered_df_oneliner)実行結果例:
“`
年齢が30歳以上の行:
name age city
id
4 David 35.0 Fukuoka年齢が30歳以上の行 (ワンライナー):
name age city
id
4 David 35.0 Fukuoka
“`
このブールインデックスは非常に柔軟です。
複数条件でのフィルタリング
複数の条件を組み合わせることも可能です。条件式は論理演算子(&
:AND、|
:OR、~
:NOT)で結合します。ただし、Pythonの標準的なand
, or
, not
ではなく、Pandas(NumPy)が提供する要素ごとの論理演算子&
, |
, ~
を使う必要があることに注意してください。また、各条件式は括弧()
で囲む必要があります。
例:「年齢が25歳以上 かつ 都市が東京または大阪の行」
“`python
条件1: 年齢 >= 25
condition1 = df_from_tsv[‘age’] >= 25
条件2: 都市が東京 または 大阪
condition2 = (df_from_tsv[‘city’] == ‘Tokyo’) | (df_from_tsv[‘city’] == ‘Osaka’)
二つの条件を AND (&) で結合
filtered_df_multiple = df_from_tsv[condition1 & condition2]
print(“\n年齢が25歳以上かつ都市が東京または大阪の行:”)
print(filtered_df_multiple)
“`
実行結果例:
年齢が25歳以上かつ都市が東京または大阪の行:
name age city
id
1 Alice 25.0 Tokyo
Bobは年齢がNaNのため条件1を満たさず、Charlieは都市が名古屋のため条件2を満たしません。Davidは都市が福岡のため条件2を満たしません。結果としてAliceのみが抽出されます。
isin()
メソッドを使ったフィルタリング
特定の列の値が、指定した値のリストに含まれているかどうかでフィルタリングしたい場合、isin()
メソッドが便利です。これは複数のOR条件を簡潔に記述できます。
例:「都市が東京または大阪の行」は、df_from_tsv['city'].isin(['Tokyo', 'Osaka'])
と書けます。
“`python
isin() を使ったフィルタリング
cities_to_filter = [‘Tokyo’, ‘Osaka’]
filtered_df_isin = df_from_tsv[df_from_tsv[‘city’].isin(cities_to_filter)]
print(“\n都市が東京または大阪の行 (isin):”)
print(filtered_df_isin)
“`
実行結果例:
都市が東京または大阪の行 (isin):
name age city
id
1 Alice 25.0 Tokyo
2 Bob NaN Osaka
query()
メソッドを使ったフィルタリング
より複雑な条件式を文字列として記述したい場合、query()
メソッドを使うとコードが読みやすくなることがあります。特に、複数の列を使ったフィルタリングに適しています。列名にスペースが含まれる場合はバッククォート `
で囲む必要があります。
例:「年齢が25歳以上かつ都市が東京または大阪の行」をquery()
で記述
“`python
query() を使ったフィルタリング
文字列の中で列名と値を指定
都市のリストは @ 変数名 で外部の変数を参照
filtered_df_query = df_from_tsv.query(‘age >= 25 and city in @cities_to_filter’) # @cities_to_filter で外部変数参照
print(“\n年齢が25歳以上かつ都市が東京または大阪の行 (query):”)
print(filtered_df_query)
“`
実行結果例:
年齢が25歳以上かつ都市が東京または大阪の行 (query):
name age city
id
1 Alice 25.0 Tokyo
query()
は文字列の中で条件を記述するため、特に複数の条件や、文字列比較、リスト内の値チェックなどを行う場合に直感的に記述できることがあります。ただし、パフォーマンスはブールインデックスの方が一般的に優れているとされています。どちらを使うかは、可読性や処理対象のデータ規模によって判断すると良いでしょう。
データの選択とフィルタリングは、データ分析において最も基本的な操作の一つです。これらの方法をマスターすることで、必要なデータだけを効率的に取り出し、その後の分析に進むことができます。
8. 簡単なデータ操作:列の追加、削除、名前変更など
データを読み込み、概要を把握し、必要なデータをフィルタリングできるようになったら、次にデータの構造自体に変更を加える基本的な操作が必要になることがあります。例えば、新しい計算列を追加したり、不要な列を削除したり、列名を分かりやすいものに変更したりといった作業です。
再び df_from_tsv
を使用します。
python
print("元のDataFrame:")
print(df_from_tsv)
実行結果例:
元のDataFrame:
name age city
id
1 Alice 25.0 Tokyo
2 Bob NaN Osaka
3 Charlie 22.0 Nagoya
4 David 35.0 Fukuoka
8.1. 新しい列の追加
DataFrameに新しい列を追加するのは非常に簡単です。新しい列名に対して、Seriesやリスト、定数などを代入するだけです。
“`python
全ての行で同じ値を持つ新しい列を追加
df_from_tsv[‘country’] = ‘Japan’
print(“\n’country’列を追加したDataFrame:”)
print(df_from_tsv)
既存の列を使って計算した新しい列を追加
例えば、年齢を10で割った列を追加
age列にNaNが含まれているため、計算結果もNaNになる行がある点に注意
df_from_tsv[‘age_div_10’] = df_from_tsv[‘age’] / 10
print(“\n’age_div_10’列を追加したDataFrame:”)
print(df_from_tsv)
リストやSeriesを使って新しい列を追加(行インデックスを揃える必要がある)
例えば、ランク付けの列を追加
DataFrameの行インデックス (1, 2, 3, 4) とリストのインデックス (0, 1, 2, 3) はデフォルトでは一致しない
インデックスを揃えるか、リストの順番がDataFrameの行の順番と厳密に一致していることを確認する必要がある
ranks = [1, 3, 2, 4] # 例として、年齢の若い順にランク付けされていると仮定 (実際には年齢順ではないが例として)
df_from_tsv[‘rank’] = ranks # この代入は、行インデックスが0,1,2,3の時のみ意図通りになる
現在のDataFrameはインデックスが1,2,3,4なので、以下のようにSeriesとして代入し、インデックスを揃えるのがより安全
ranks_series = pd.Series(ranks, index=df_from_tsv.index)
df_from_tsv[‘rank’] = ranks_series
print(“\n’rank’列を追加したDataFrame:”)
print(df_from_tsv)
“`
実行結果例:
“`
‘country’列を追加したDataFrame:
name age city country
id
1 Alice 25.0 Tokyo Japan
2 Bob NaN Osaka Japan
3 Charlie 22.0 Nagoya Japan
4 David 35.0 Fukuoka Japan
‘age_div_10’列を追加したDataFrame:
name age city country age_div_10
id
1 Alice 25.0 Tokyo Japan 2.5
2 Bob NaN Osaka Japan NaN
3 Charlie 22.0 Nagoya Japan 2.2
4 David 35.0 Fukuoka Japan 3.5
‘rank’列を追加したDataFrame:
name age city country age_div_10 rank
id
1 Alice 25.0 Tokyo Japan 2.5 1
2 Bob NaN Osaka Japan NaN 3
3 Charlie 22.0 Nagoya Japan 2.2 2
4 David 35.0 Fukuoka Japan 3.5 4
“`
新しい列はDataFrameの右端に追加されます。
8.2. 列(または行)の削除
DataFrameから不要な列や行を削除するには、drop()
メソッドを使用します。
df.drop(labels, axis=0)
: 指定したラベル(インデックス名)の行を削除します。axis=0
がデフォルトです。df.drop(labels, axis=1)
: 指定したラベル(列名)の列を削除します。axis=1
を指定する必要があります。
drop()
メソッドは、デフォルトでは元のDataFrameを変更せず、削除された新しいDataFrameを返します。元のDataFrameを直接変更したい場合は、inplace=True
引数を指定します(ただし、inplace=True
の使用は推奨されない傾向にあります。新しいオブジェクトを返して代入する方が明示的でエラーを防ぎやすいため)。
“`python
‘age_div_10’ 列を削除
df_dropped_column = df_from_tsv.drop(‘age_div_10’, axis=1)
print(“\n’age_div_10’列を削除したDataFrame:”)
print(df_dropped_column)
複数の列を削除
df_dropped_multiple = df_from_tsv.drop([‘country’, ‘rank’], axis=1)
print(“\n’country’列と’rank’列を削除したDataFrame:”)
print(df_dropped_multiple)
id=2 の行を削除
df_dropped_row = df_from_tsv.drop(2, axis=0) # または simply df_from_tsv.drop(2)
print(“\nid=2 の行を削除したDataFrame:”)
print(df_dropped_row)
複数の行を削除
df_dropped_multiple_rows = df_from_tsv.drop([1, 4]) # axis=0 はデフォルトなので省略可
print(“\nid=1 と id=4 の行を削除したDataFrame:”)
print(df_dropped_multiple_rows)
Note: drop() は元の df_from_tsv を変更していない
print(“\n元のDataFrame (変更なし):”)
print(df_from_tsv)
“`
実行結果例:
“`
‘age_div_10’列を削除したDataFrame:
name age city country rank
id
1 Alice 25.0 Tokyo Japan 1
2 Bob NaN Osaka Japan 3
3 Charlie 22.0 Nagoya Japan 2
4 David 35.0 Fukuoka Japan 4
‘country’列と’rank’列を削除したDataFrame:
name age city age_div_10
id
1 Alice 25.0 Tokyo 2.5
2 Bob NaN Osaka NaN
3 Charlie 22.0 Nagoya 2.2
4 David 35.0 Fukuoka 3.5
id=2 の行を削除したDataFrame:
name age city country age_div_10 rank
id
1 Alice 25.0 Tokyo Japan 2.5 1
3 Charlie 22.0 Nagoya Japan 2.2 2
4 David 35.0 Fukuoka Japan 3.5 4
id=1 と id=4 の行を削除したDataFrame:
name age city country age_div_10 rank
id
2 Bob NaN Osaka Japan NaN 3
3 Charlie 22.0 Nagoya Japan 2.2 2
元のDataFrame (変更なし):
name age city country age_div_10 rank
id
1 Alice 25.0 Tokyo Japan 2.5 1
2 Bob NaN Osaka Japan NaN 3
3 Charlie 22.0 Nagoya Japan 2.2 2
4 David 35.0 Fukuoka Japan 3.5 4
``
df = df.drop(…)
元のDataFrameを変更したい場合は、のように再代入するか、
inplace=True`を使用します(非推奨)。
8.3. 列名の変更
列名を変更するには、rename()
メソッドを使用します。変更したい列名と新しい列名の対応を辞書形式で指定します。
“`python
列名を変更
‘age’ -> ‘年齢(歳)’, ‘city’ -> ‘出身都市’ に変更
df_renamed = df_from_tsv.rename(columns={‘age’: ‘年齢(歳)’, ‘city’: ‘出身都市’})
print(“\n列名を変更したDataFrame:”)
print(df_renamed)
行インデックスの名前を変更することも可能 (index 引数を使う)
df_renamed_index = df_from_tsv.rename(index={1: ‘Person A’, 2: ‘Person B’})
print(“\n行インデックス名を変更したDataFrame:”)
print(df_renamed_index)
“`
実行結果例:
“`
列名を変更したDataFrame:
name 年齢(歳) 出身都市 country age_div_10 rank
id
1 Alice 25.0 Tokyo Japan 2.5 1
2 Bob NaN Osaka Japan NaN 3
3 Charlie 22.0 Nagoya Japan 2.2 2
4 David 35.0 Fukuoka Japan 3.5 4
行インデックス名を変更したDataFrame:
name age city country age_div_10 rank
id
Person A Alice 25.0 Tokyo Japan 2.5 1
Person B Bob NaN Osaka Japan NaN 3
3 Charlie 22.0 Nagoya Japan 2.2 2
4 David 35.0 Fukuoka Japan 3.5 4
“`
drop()
と同様に、rename()
もデフォルトでは新しいDataFrameを返します。元のDataFrameを変更したい場合は再代入するか、inplace=True
を指定します。
8.4. インデックスのリセット/設定
DataFrameの行インデックスはデータの一部ではないため、時には通常の列として扱いたい場合があります。また逆に、特定の列をインデックスに設定したい場合もあります。
df.reset_index()
: 現在のインデックスを列に変換し、新しいデフォルトの整数インデックス(0から始まる)を設定します。df.set_index(keys)
: 指定した列(または列のリスト)を新しいインデックスとして設定します。
先ほど作成した df_renamed
(列名とインデックス名が変更されたDataFrame)を使用します。
“`python
print(“現在のDataFrame (インデックス名あり):”)
print(df_renamed)
インデックスをリセット
id列が通常の列になり、新しい整数インデックスが付与される
df_reset = df_renamed.reset_index()
print(“\nインデックスをリセットしたDataFrame:”)
print(df_reset)
新しい整数インデックスではなく、現在のインデックス名(id)をそのまま列名として残したくない場合は、
drop=True 引数を指定します。
df_reset_drop = df_renamed.reset_index(drop=True)
print(“\nインデックスをリセット (drop=True) したDataFrame:”)
print(df_reset_drop)
print(“-” * 30)
再び age 列をインデックスとして設定 (age列は重複値やNaNを含む可能性があるので、実際のデータでは注意が必要)
今回のデータでは age がユニークでない可能性があるため、実行結果は参考としてください
実際には、ユニークな値を持つ列をインデックスにするのが一般的です
print(“age 列をインデックスとして設定 (set_index(‘年齢(歳)’)):”)
df_set = df_renamed.set_index(‘年齢(歳)’)
print(df_set)
“`
実行結果例:
“`
現在のDataFrame (インデックス名あり):
name 年齢(歳) 出身都市 country age_div_10 rank
id
1 Alice 25.0 Tokyo Japan 2.5 1
2 Bob NaN Osaka Japan NaN 3
3 Charlie 22.0 Nagoya Japan 2.2 2
4 David 35.0 Fukuoka Japan 3.5 4
インデックスをリセットしたDataFrame:
id name 年齢(歳) 出身都市 country age_div_10 rank
0 1 Alice 25.0 Tokyo Japan 2.5 1
1 2 Bob NaN Osaka Japan NaN 3
2 3 Charlie 22.0 Nagoya Japan 2.2 2
3 4 David 35.0 Fukuoka Japan 3.5 4
age 列をインデックスとして設定した場合の例 (実際のデータ内容により結果は異なる)
age 列に NaN が含まれる場合、その行のインデックスは NaN となる
age 列に重複がある場合、同じインデックスが複数行に割り当てられることになる
age 列がユニークでない場合、set_index() のデフォルトではエラーにはならないが、データによっては扱いにくくなる
“`
reset_index()
とset_index()
は、データを行インデックスに基づいて操作したり、逆にインデックスをデータの一部として扱ったりする際に役立ちます。
これらの基本的なデータ操作を組み合わせることで、読み込んだデータを分析に適した形に整形していくことができます。
9. まとめと次のステップ
この記事では、Pythonでデータ分析を行う上で不可欠なライブラリであるPandasの、まさに「最初のステップ」を詳細に解説しました。
学んだことを振り返ってみましょう。
- Pandasのインストール:
pip install pandas
または Anaconda/Miniconda によるインストール方法。 - Pandasのimport方法: データ分析コミュニティの標準である
import pandas as pd
の意味と理由。 - Pandasの主要なデータ構造: 1次元の
Series
と 2次元のDataFrame
の基本、それぞれの特徴、作成方法、基本的な属性と操作。 - データの読み込み: 最もよく使われる
pd.read_csv()
関数とその主要な引数(sep
,header
,index_col
,na_values
,encoding
など)の詳細な使い方。 - 読み込んだデータの概要把握:
head()
,tail()
,info()
,describe()
,shape
,columns
,index
,isnull().sum()
,value_counts()
といった、データの内容や構造、品質(欠損値など)を素早く理解するためのメソッド。 - データの選択とフィルタリング: 列の選択、
loc
とiloc
を使った行や特定のセル・範囲の選択、ブールインデックスを使った条件によるデータのフィルタリング(単一条件、複数条件、isin()
,query()
)。 - 簡単なデータ操作: 新しい列の追加、
drop()
を使った列や行の削除、rename()
を使った列名/インデックス名の変更、reset_index()
とset_index()
を使ったインデックス操作。
これらの内容は、Pandasを使ったデータ分析の出発点として非常に重要です。この記事で紹介した内容は、Pandasの機能のごく一部に過ぎませんが、これらをしっかりと理解していれば、多くのデータ分析タスクの最初の段階をこなすことができるでしょう。
次のステップへ
この記事で習得した基礎を土台として、さらにPandasを使ったデータ分析のスキルを深めていくことができます。次に学ぶべき主なトピックには以下のようなものがあります。
- 欠損値の処理:
isnull()
,dropna()
,fillna()
を使った欠損値の特定、削除、補完。 - データの結合とマージ: 複数のDataFrameを結合する
pd.concat()
,pd.merge()
。 - データの集計とグループ化:
groupby()
メソッドを使ったデータの集計、pivot_table の作成。 - 文字列操作: Seriesの
.str
アクセサを使った文字列データの操作。 - 日付・時刻データの操作: 日付・時刻型 (
datetime
) データの扱い、時系列データの操作。 - データの変換: データの型の変換 (
astype()
)、値の置換 (replace()
)、関数の適用 (apply()
,map()
,applymap()
)。 - データの並べ替え:
sort_values()
,sort_index()
。 - データの可視化: Pandasには簡単な可視化機能も内蔵されており、matplotlibと連携して利用できます。
これらのトピックを学ぶことで、より複雑なデータの前処理や分析を行えるようになります。
Pandasの学習は、実際に手を動かしながら進めるのが最も効果的です。この記事のコード例を自分の環境で実行してみたり、公開されているサンプルデータセット(Kaggleなどで提供されているものなど)をPandasで読み込み、この記事で学んだ操作を試してみたりすることをお勧めします。
Pandasは非常に奥深く、強力なライブラリです。この記事が、あなたのデータ分析の旅の良いスタートとなることを願っています。Happy Data Analyzing!