pandas基本

2026-09-15

目次

pandas使うのになぜか毎回勉強し直してるため

sample

import pandas as pd
data = {
"name": ["Tanaka", "Sato", "Suzuki", "Takahashi", "Ito"],
"dept": ["Sales", "Sales", "Dev", "Dev", "HR"],
"age": [34, 28, 41, 25, 38],
"salary": [320, 280, 410, 250, None],
}
df = pd.DataFrame(data)

pd.read_csv("data.csv"), pd.read_parquet("data.parquet")でcsv, parquetからも読み込み可能

以下この適当なダミーデータを使います

基本情報

df.head()
# name dept age salary
# 0 Tanaka Sales 34 320.0
# 1 Sato Sales 28 280.0
# 2 Suzuki Dev 41 410.0
# 3 Takahashi Dev 25 250.0
# 4 Ito HR 38 NaN
df.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 5 entries, 0 to 4
# Data columns (total 4 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 name 5 non-null object
# 1 dept 5 non-null object
# 2 age 5 non-null int64
# 3 salary 4 non-null float64
# dtypes: float64(1), int64(1), object(2)
# memory usage: 292.0+ bytes
df.shape
# (5, 4)
# row x column
df.dtypes
# name object
# dept object
# age int64
# salary float64
# dtype: object
df.describe()
# age salary
# count 5.000000 4.000000
# mean 33.200000 315.000000
# std 6.685806 69.522179
# min 25.000000 250.000000
# 25% 28.000000 272.500000
# 50% 34.000000 300.000000
# 75% 38.000000 342.500000
# max 41.000000 410.000000
# 数値列の統計量を出力、文字列列は自動で除外

選択

df[df["age"] > 30]
# name dept age salary
# 0 Tanaka Sales 34 320.0
# 2 Suzuki Dev 41 410.0
# 4 Ito HR 38 NaN
df[(df["age"] > 30) & (df["dept"] == "Dev")] # 30歳以上且つdev所属
# name dept age salary
# 2 Suzuki Dev 41 410.0
df[df["dept"].isin(["Sales", "Dev"])] # deptがsales, devが含まれる, isin() -> boolean
# name dept age salary
# 0 Tanaka Sales 34 320.0
# 1 Sato Sales 28 280.0
# 2 Suzuki Dev 41 410.0
# 3 Takahashi Dev 25 250.0
df.loc[df["age"] > 30, ["name", "age"]] # age30以上かつ列をname, ageに絞る
# name age
# 0 Tanaka 34
# 2 Suzuki 41
# 4 Ito 38
df.loc[0:2] # [row, column]
# name dept age salary
# 0 Tanaka Sales 34 320.0
# 1 Sato Sales 28 280.0
# 2 Suzuki Dev 41 410.0
# pythonスライスは0, 1で2は含まないが、pandasは両端を含む0, 1, 2
df.iloc[0:2, 0:2]
# name dept
# 0 Tanaka Sales
# 1 Sato Sales
# ilocはpythonスライスと同様、第1引数が行、2が列指定
df.query("age > 30 and salary > 300")
# name dept age salary
# 0 Tanaka Sales 34 320.0
# 2 Suzuki Dev 41 410.0
# 詳しいクエリ:
# https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html
df.nlargest(3, "salary")
# name dept age salary
# 2 Suzuki Dev 41 410.0
# 0 Tanaka Sales 34 320.0
# 1 Sato Sales 28 280.0
# salaryからlargest3つ
df.nsmallest(2, "age")
# name dept age salary
# 3 Takahashi Dev 25 250.0
# 1 Sato Sales 28 280.0
df.sample(2)
# name dept age salary
# 2 Suzuki Dev 41 410.0
# 0 Tanaka Sales 34 320.0

追加

df["bonus"] = df["salary"] * 0.1
# name dept age salary bonus
# 0 Tanaka Sales 34 320.0 32.0
# 1 Sato Sales 28 280.0 28.0
# 2 Suzuki Dev 41 410.0 41.0
# 3 Takahashi Dev 25 250.0 25.0
# 4 Ito HR 38 NaN NaN
# 以下、dfに対する破壊操作
df["is_senior"] = df["age"] >= 35
# name dept age salary bonus is_senior
# 0 Tanaka Sales 34 320.0 32.0 False
# 1 Sato Sales 28 280.0 28.0 False
# 2 Suzuki Dev 41 410.0 41.0 True
# 3 Takahashi Dev 25 250.0 25.0 False
# 4 Ito HR 38 NaN NaN True
df["level"] = df["age"].apply(lambda x: "senior" if x >= 35 else "junior")
# name dept age salary bonus is_senior level
# 0 Tanaka Sales 34 320.0 32.0 False junior
# 1 Sato Sales 28 280.0 28.0 False junior
# 2 Suzuki Dev 41 410.0 41.0 True senior
# 3 Takahashi Dev 25 250.0 25.0 False junior
# 4 Ito HR 38 NaN NaN True senior
# 内部で行ループに近い処理をするため、非効率
# 大規模データには非推奨
df["full_info"] = df["name"] + " (" + df["dept"] + ")"
# name dept age salary bonus is_senior level full_info
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
df.drop("bonus", axis=1)
# name dept age salary is_senior level full_info
# 0 Tanaka Sales 34 320.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 False junior Sato (Sales)
# 2 Suzuki Dev 41 410.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN True senior Ito (HR)
# 非破壊操作, inplace=Trueで破壊操作かつ戻り値無し
# axis=1で列に対して、0で行に対して
df.drop(columns=["bonus", "level"])
# name dept age salary is_senior full_info
# 0 Tanaka Sales 34 320.0 False Tanaka (Sales)
# 1 Sato Sales 28 280.0 False Sato (Sales)
# 2 Suzuki Dev 41 410.0 True Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 False Takahashi (Dev)
# 4 Ito HR 38 NaN True Ito (HR)
df.drop(0, axis=0)
# name dept age salary bonus is_senior level full_info
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
df.drop(index=[0, 1])
# name dept age salary bonus is_senior level full_info
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
df.rename(columns={"dept": "department"})
# name department age salary bonus is_senior level full_info
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
# 非破壊操作
df.insert(1, "id", range(1, len(df) + 1))
# name id dept age salary bonus is_senior level full_info
# 0 Tanaka 1 Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato 2 Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki 3 Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi 4 Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito 5 HR 38 NaN NaN True senior Ito (HR)
# 列インデックス1(つまり2列目)にidを挿入、1~行数分の連番を追加
# 破壊操作

欠損値

df.isna()
# name id dept age salary bonus is_senior level full_info
# 0 False False False False False False False False False
# 1 False False False False False False False False False
# 2 False False False False False False False False False
# 3 False False False False False False False False False
# 4 False False False False True True False False False
# 欠損してるとこだけTrue
df.isna().sum()
# name 0
# id 0
# dept 0
# age 0
# salary 1
# bonus 1
# is_senior 0
# level 0
# full_info 0
# dtype: int64
df.isna().any()
# name False
# id False
# dept False
# age False
# salary True
# bonus True
# is_senior False
# level False
# full_info False
# dtype: bool
df.dropna()
# name id dept age salary bonus is_senior level full_info
# 0 Tanaka 1 Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato 2 Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki 3 Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi 4 Dev 25 250.0 25.0 False junior Takahashi (Dev)
# NaNがある行を削除
# 非破壊
df.dropna(subset=["salary"])
# dropna()をsalaryに限定する
df.fillna(0)
# name id dept age salary bonus is_senior level full_info
# 0 Tanaka 1 Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato 2 Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki 3 Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi 4 Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito 5 HR 38 0.0 0.0 True senior Ito (HR)
df.fillna({"salary": 0, "bonus": df["bonus"].mean()})
# name dept age salary bonus is_senior level full_info
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 0.0 31.5 True senior Ito (HR)
# salaryは0埋め、bonusはbonus列の平均で埋め
df["salary"].fillna(df["salary"].mean())
# 0 320.0
# 1 280.0
# 2 410.0
# 3 250.0
# 4 315.0
# Name: salary, dtype: float64
# 一列だけの抽出
df.ffill()
# name dept age salary bonus is_senior level full_info
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 250.0 25.0 True senior Ito (HR)
# forward fill, 前の値で埋める 逆はdf.bfill()

ソート

df.sort_values("salary", ascending=False)
# name dept age salary bonus is_senior level full_info
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
# salary列でソート, ascending=Falseで降順, Trueで昇順
df.sort_values(["dept", "age"], ascending=[True, False])
# name dept age salary bonus is_senior level full_info
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2段階でのソート、deptのアルファベット順のあとageの年齢が高い順
df.sort_values("salary", na_position="first")
# name dept age salary bonus is_senior level full_info
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# NaNを先頭に持っていく引数、デフォは最後
df.sort_index()
# name dept age salary bonus is_senior level full_info
# 0 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 3 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
# 元の順番、インデックスを戻す
df.sort_values("salary").reset_index(drop=True)
# name dept age salary bonus is_senior level full_info
# 0 Takahashi Dev 25 250.0 25.0 False junior Takahashi (Dev)
# 1 Sato Sales 28 280.0 28.0 False junior Sato (Sales)
# 2 Tanaka Sales 34 320.0 32.0 False junior Tanaka (Sales)
# 3 Suzuki Dev 41 410.0 41.0 True senior Suzuki (Dev)
# 4 Ito HR 38 NaN NaN True senior Ito (HR)
# salaryで並び替えたのちインデックスをリセット
# drop=Trueにしないと旧インデックスが列として残る

統計

df.groupby("dept")["salary"].mean()
# dept
# Dev 330.0
# HR NaN
# Sales 300.0
# Name: salary, dtype: float64
# deptごとのグループでsalaryの平均を出す
# sum()は同様に合計
df.groupby("dept").agg({"salary": "mean", "age": "max"})
# salary age
# dept
# Dev 330.0 41
# HR NaN 38
# Sales 300.0 34
# 列ごとに違う方法での統計を行える
# agg = aggregate
df.groupby("dept").agg(avg_salary=("salary", "mean"), count=("name", "count"))
# avg_salary count
# dept
# Dev 330.0 2
# HR NaN 1
# Sales 300.0 2
# agg(新しい列名=("集計対象列", "統計方法"), ...)
df.groupby("dept").size()
# dept
# Dev 2
# HR 1
# Sales 2
# dtype: int64
# countは非NaN要素, size()は全て

tips

loopできる、ケドあんまりしない方がいい

for row in df.itertuples():
print(row.Index, row.name, row.salary)

全体的にベクトル演算を優先した方がいい、とのこと