Pythonのデータ処理の定番ライブラリであるpandasで、最も基本的なデータ構造がDataFrameとSeriesになります。
今回は、PandasにおけるDataFrameとSeriesの違いについて解説し、基本的な操作方法をまとめます。
本記事の内容
- DataFrameとSeriesの違い
- DataFrameの作成と基本操作
- Seriesの作成と基本操作
- データの取得・フィルタリング
DataFrameとSeriesの違い
DataFrameとSeriesの違いを一言で言うと、DataFrameは2次元のテーブル構造で、Seriesは1次元のラベル付き配列です。
何かしらのテーブル構造のデータがあった際に、DataFrameはデータ全体を、Seriesはデータの1列もしくは1行を表します。
| 特徴 | DataFrame | Series |
|---|---|---|
| 次元 | 2次元 | 1次元 |
| 構造 | 行 × 列のテーブル | ラベル付き配列 |
| 取得 | df['列名'] で Series を取得 |
インデックスで要素を取得 |
DataFrameの作成
DataFrameを作成する方法はいくつかあります。
辞書からの作成
import pandas as pd
import numpy as np
# 辞書からDataFrameを作成
data = {
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 32],
'score': [85.5, 92.0, 78.3, 95.1, 88.7],
'city': ['Tokyo', 'Osaka', 'Tokyo', 'Nagoya', 'Osaka']
}
df = pd.DataFrame(data)
print(df)
print(f"\nshape: {df.shape}")
print(f"dtypes:\n{df.dtypes}")
NumPy配列からの作成
import pandas as pd
import numpy as np
# NumPy配列からDataFrameを作成
arr = np.random.randn(5, 3)
df = pd.DataFrame(arr, columns=['A', 'B', 'C'], index=['row1', 'row2', 'row3', 'row4', 'row5'])
print(df)
DataFrameの基本操作
データの概要確認
import pandas as pd
import numpy as np
data = {
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 32],
'score': [85.5, 92.0, 78.3, 95.1, 88.7],
'city': ['Tokyo', 'Osaka', 'Tokyo', 'Nagoya', 'Osaka']
}
df = pd.DataFrame(data)
# 先頭/末尾の確認
print("=== head(3) ===")
print(df.head(3))
# 基本統計量
print("\n=== describe() ===")
print(df.describe())
# データ型とメモリ使用量
print("\n=== info() ===")
df.info()
列の操作
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 32],
'score': [85.5, 92.0, 78.3, 95.1, 88.7],
}
df = pd.DataFrame(data)
# 列の追加
df['grade'] = ['A', 'A+', 'B', 'A+', 'A']
print("列の追加:")
print(df)
# 計算による列の追加
df['score_normalized'] = (df['score'] - df['score'].min()) / (df['score'].max() - df['score'].min())
print("\n計算列の追加:")
print(df)
# 列の削除
df_dropped = df.drop(columns=['grade'])
print("\n列の削除後:")
print(df_dropped)
データのフィルタリング
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 32],
'score': [85.5, 92.0, 78.3, 95.1, 88.7],
'city': ['Tokyo', 'Osaka', 'Tokyo', 'Nagoya', 'Osaka']
}
df = pd.DataFrame(data)
# 条件でフィルタリング
print("age > 28:")
print(df[df['age'] > 28])
# 複数条件(AND)
print("\nage > 25 AND score > 85:")
print(df[(df['age'] > 25) & (df['score'] > 85)])
# 特定の値でフィルタリング
print("\ncity == 'Tokyo':")
print(df[df['city'] == 'Tokyo'])
# isinによるフィルタリング
print("\ncity in ['Tokyo', 'Osaka']:")
print(df[df['city'].isin(['Tokyo', 'Osaka'])])
Seriesの作成と操作
SeriesはDataFrameの1列に相当する1次元データ構造です。
import pandas as pd
import numpy as np
# リストからSeriesを作成
s = pd.Series([10, 20, 30, 40, 50], index=['a', 'b', 'c', 'd', 'e'], name='values')
print("Series:")
print(s)
print(f"\ndtype: {s.dtype}")
print(f"index: {s.index.tolist()}")
print(f"name: {s.name}")
DataFrameからSeriesを取得
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35],
'score': [85.5, 92.0, 78.3],
}
df = pd.DataFrame(data)
# 列名で取得するとSeriesになる
age_series = df['age']
print(f"type: {type(age_series)}")
print(age_series)
# 複数列を指定するとDataFrameになる
subset = df[['name', 'age']]
print(f"\ntype: {type(subset)}")
print(subset)
Seriesの演算
import pandas as pd
import numpy as np
s1 = pd.Series([1, 2, 3, 4, 5])
s2 = pd.Series([10, 20, 30, 40, 50])
# 要素ごとの演算
print("加算:", (s1 + s2).tolist())
print("乗算:", (s1 * s2).tolist())
# 集約関数
print(f"\n合計: {s1.sum()}")
print(f"平均: {s1.mean()}")
print(f"標準偏差: {s1.std():.4f}")
print(f"最大値: {s1.max()}, 最小値: {s1.min()}")
# NumPyの関数も適用可能
print(f"\nnp.sqrt: {np.sqrt(s2).tolist()}")
locとilocによるデータアクセス
DataFrameのデータにアクセスする方法として、loc(ラベルベース)と iloc(位置ベース)があります。
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 32],
'score': [85.5, 92.0, 78.3, 95.1, 88.7],
}
df = pd.DataFrame(data, index=['p1', 'p2', 'p3', 'p4', 'p5'])
# loc: ラベルで指定
print("loc['p2', 'name']:", df.loc['p2', 'name'])
print("\nloc['p1':'p3', 'name':'age']:")
print(df.loc['p1':'p3', 'name':'age'])
# iloc: 位置(整数)で指定
print("\niloc[1, 0]:", df.iloc[1, 0])
print("\niloc[0:3, 0:2]:")
print(df.iloc[0:3, 0:2])
loc はラベル(インデックスや列名)でアクセスし、スライスの終端を含みます。iloc は整数位置でアクセスし、スライスの終端を含みません(Pythonの標準的なスライスと同じ)。
実践: データの集計
実際のデータ分析でよく使うグループ化と集計を試してみましょう。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
# サンプルデータの生成
n = 100
df = pd.DataFrame({
'department': np.random.choice(['Engineering', 'Sales', 'Marketing', 'HR'], n),
'experience': np.random.randint(1, 20, n),
'salary': np.random.normal(500, 100, n).astype(int),
'performance': np.random.choice(['A', 'B', 'C'], n, p=[0.3, 0.5, 0.2])
})
# グループ化と集計
summary = df.groupby('department').agg(
count=('salary', 'count'),
mean_salary=('salary', 'mean'),
mean_experience=('experience', 'mean'),
).round(1)
print("=== Department Summary ===")
print(summary)
# 可視化
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
summary['mean_salary'].plot(kind='bar', ax=axes[0], color='steelblue', alpha=0.8)
axes[0].set_title("Mean Salary by Department")
axes[0].set_ylabel("Salary")
axes[0].tick_params(axis='x', rotation=45)
axes[0].grid(True, alpha=0.3, axis='y')
df.groupby('department')['performance'].value_counts().unstack().plot(
kind='bar', ax=axes[1], alpha=0.8)
axes[1].set_title("Performance Distribution by Department")
axes[1].set_ylabel("Count")
axes[1].tick_params(axis='x', rotation=45)
axes[1].legend(title='Performance')
axes[1].grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.show()
まとめ
本記事では、pandasのDataFrameとSeriesの違いと基本的な操作方法を解説しました。
- DataFrameは2次元のテーブル構造、Seriesは1次元のラベル付き配列
- DataFrameから列を1つ取得するとSeriesになる
- locはラベルベース、ilocは位置ベースのデータアクセス
- フィルタリングはブーリアンインデックスで直感的に行える
groupbyとaggで柔軟なグループ化・集計が可能