とほほのPandas 3入門

目次

Pandasとは

環境

本書は下記の環境で検証しています。

OS: AlmaLinux 10.1
Python: 3.12.12
Pandas: 3.0.0
Numpy: 2.4.2

準備

インストール

pip install pandas

モジュールをインポートする

pandas をインポートします。

import pandas as pd

Numpy を使用する場合は numpy もインポートしてください。

import numpy as np

Series・DataFrameを作成する

Seriesを生成する(Series())

一次元配列を引数として Series を生成します。

ser = pd.Series(['A', 'B', 'C', 'D'])

DataFrameを生成する(DataFrame())

下記の様な二次元配列を渡します。行ラベル(index)、列ラベル(columns)を省略した場合はいずれも [0, 1, 2, ...] とみなされます。

df = pd.DataFrame([
    ['Yamada', 36],
    ['Suzuki', 42],
    ['Tanaka', 54],
], columns=['Name', 'Age'], index=[1, 2, 3])

辞書から作成することもできます。

df = pd.DataFrame({
    'Name': ['Yamada', 'Suzuki', 'Tanaka'],
    'Age': [36, 42, 54]
})

辞書リストから作成することもできます。

df = pd.DataFrame([
    {'Name': 'Yamada', 'Age': 36},
    {'Name': 'Suzuki', 'Age': 42},
    {'Name': 'Tanaka', 'Age': 54},
])

以後の説明では、基本的に下記で作成した DataFrame に対する操作で説明します。

df = pd.DataFrame({
    'Name': ['Yamada', 'Suzuki', 'Tanaka'],
    'Age': [36, 42, 54]
})
#    Name    Age
# 0  Yamada  36
# 1  Suzuki  42
# 2  Tanaka  54

列の型

Pandasで扱えるデータ型

下記などのデータ型を扱うことができます。

int8, int16, int32, int64      # NumPy由来の整数。NaNを扱えない ([-128, 127])
uint8, uint16, uint32, uint64  # NumPy由来の整数。NaNを扱えない ([0, 255])
Int8, Int16, Int32, Int64      # Pandas拡張の整数。NaNを扱える ([-128, 127, np.nan])
UInt8, UInt16, UInt32, UInt64  # Pandas拡張の非負整数。NaNを扱える ([123, 124, np.nan])
float16, float32, float64      # NumPy由来の浮動小数点数。NaNを扱える ([12.3, 12.4, np.nan])
bool                           # NumPy由来の真偽値。NaNを扱えない ([True, False])
boolean                        # Pandas拡張の真偽値。NaNを扱える ([True, False, np.nan])
object                         # 汎用的 ([1, 12.3, 'ABC'])
string                         # 文字列 (['ABC', 'XYZ'])
category                       # 列挙型(高速) ["Red", "Green", "Red"]
datetime64[ns]                 # 日時(ナノ秒単位) ["2026-02-08 12:59:59.999999999"]
timedelta64[ns]                # 時間差(ナノ秒単位) (["123s", "42s"])
period                         # 期間 ([pd.Period("2026-02-08", freq="M")])
interval                       # インターバル ([pd.Interval(0, 10)])
complex64, complex128          # 複素数 ([1+1j, 2+2j])
Sparse                         # スパースデータ(NaNにメモリを割り当てない形式)
ArrowDtype                     # Apache Arrow互換(pyarrow)(実験的機能)

上記の他に Python の型も指定できます。

str                            # 文字列(stringとほぼ同義)
int                            # 整数(int32やint64)
float                          # 浮動小数点数(float32やfloat64)

列の型を表示する(dtypes)

dtypes で列の型を確認することができます。

df.dtypes
# Name      str
# Age     int64
# dtype: object

列の型を変更する(astype())

列の型を変更するには astype() を使用します。

df = df.astype('string')                 # すべての列の型をstringに変換
df['Age'] = df['Age'].astype('UInt16')   # Age列の型をUInt16に変換

DataFrameをファイルから読み込む

CSV, TSV, TXT, JSON, Excel, HTML から読み込む(read_csv(), read_json(), read_excel(), read_html())

CSV、TSV、TXT、JSON、Excel ファイルなどから読み込むことができます。

df = pd.read_csv('example.csv')        # CSVファイル(1行目はヘッダー)
df = pd.read_json('example.json')      # [{"Name":"...","Age":...},...]
df = pd.read_excel('example.xlsx')     # Excelファイル(1行目はヘッダー)
df = pd.read_html('example.html')[0]   # <table><tr><th>Name</th>...

URL から読み込むこともできます。

df = pd.read_csv('https://example.com/example.csv')

セパレーターを指定する(TSV,TXTファイル対応)(sep)

sep にセパレーターを指定することができます。

df = pd.read_csv('example.tsv', sep='\t')     # TSVファイル(1行目はヘッダー)
df = pd.read_csv('example.txt', sep=r'\s+')   # ホワイトスペース区切りテキスト(1行目はヘッダー)

列ラベルを指定する(header, names)

read_csv() で通常は1行目をヘッダーと見なしますが、headerNone を指定するとヘッダー無しと見なします。数値を指定すると header 行目をヘッダー、次の行からをデータと見なします。

df = pd.read_csv(file, header=None)   # ヘッダー無し
df = pd.read_csv(file, header=0)      # 0行目がヘッダー、1行目以降がデータ(0始まり)
df = pd.read_csv(file, header=1)      # 1行目がヘッダー、2行目以降がデータ(0始まり)

names で列ラベルを指定するとそれが優先されます。

df = pd.read_csv(file, names=['Name', 'Age'])             # CSVファイルにヘッダーが無い場合
df = pd.read_csv(file, names=['Name', 'Age'], header=0)   # CSVファイル0行目のヘッダーを無視する場合

行ラベルを指定する(index_col)

index_col に数値を指定すると index_col 列目を行ラベル、次の列からをデータと見なします。

df = pd.read_csv(file, index_col=0)       # 0列目が行ラベル、1列目以降がデータ(0始まり)
df = pd.read_csv(file, index_col=1)       # 1列目が行ラベル、2列目以降がデータ(0始まり)

指定した列のみを読み込む(usecols)

usecols を指定すると読み込む列を指定できます。

df = pd.read_csv(file, usecols=[0,2,3])   # 0, 2, 3列目のみを読み込む(0始まり)
df = pd.read_csv(file, usecols=['Age'])   # Age列目のみを読み込む

指定した行を読み飛ばす(skiprows, skipfooter)

skiprows を指定すると指定した行数や指定した行を読み飛ばします。

df = pd.read_csv(file, skiprows=1)        # 最初の1行分(1始まり)を読み飛ばす
df = pd.read_csv(file, skiprows=[0,2])    # 0行目と2行目(0始まり)を読み飛ばす

skiprows にはラムダ式を与えることもできます。

df = pd.read_csv(file, skiprows=lambda x: x not in [0,2,3])  # 0行目をヘッダ、2,3行目をデータとして読み込む

skipfooter はスキップする末尾の行数を指定します。数値のみ指定できます。engine='c' の場合は使用できません。エラーが出る場合は engine='python' を指定してください。

df = pd.read_csv(file, skipfooter=100, engine='python')   # 末尾の100行は読み込まない

指定した行数分読み込む(nrows)

nrows は読み込む最大データ行数を指定します。ヘッダ行はカウントしません。

df = pd.read_csv(file, nrows=10)    # 10行分のデータを読む

100~199 行目のデータを読み込みたい場合は次のようにします。

df = pd.read_csv(file, skiprows=range(1,100), nrows=100)       # 0行目がヘッダーの場合
df = pd.read_csv(file, header=None, skiprows=99, nrows=100)    # ヘッダーが無い場合

列の型を指定する(dtype)

dtype で読み込む際の列のデータ型を指定することができます。

df = pd.read_csv(file, dtype={'Name': 'string', 'Age': 'UInt16'})

日付フォーマットを指定する(parse_dates, date_format)

parse_dates で日時として解釈して欲しい列を、date_format でその フォーマット を指定することができます。

df = pd.read_csv(file, parse_dates=['StartDate', 'EndDate'], date_format='%Y-%m-%d')

欠損値を指定する(na_values, keep_default_na, na_filter)

デフォルトでは空文字、NaNnanN/ANAnullNULL はすべて欠損値とみなします。欠損値とみなしたい文字列を追加するには na_values を指定します。

df = pd.read_csv(file, na_values=['#VALUE!', '#N/A!'])

逆に NaN のみを欠損値として扱い、他は通常の文字列として扱って欲しい場合は下記のようにします。

df = pd.read_csv(file, na_values=['NaN'], keep_default_na=False)

すべての値を欠損値として扱いたくない場合は na_filter=False を指定します。

df = pd.read_csv(file, na_filter=False)

圧縮ファイルを読み込む(compression)

read_csv() は圧縮ファイルを読み込むことができます。拡張子が .gz, .bz2, .zip, .xz, .zst, .tar, .tar.gz, .tar.xz, .tar.bz2 であれば展開アルゴリズムを自動的に判断します。複数ファイルを読むことはできません。compression には圧縮ファイルの扱い方(infer, gzip, bz2, zstd, xz, tar, None) を指定します。

df = pd.read_csv('example.csv.zip')
df = pd.read_csv('example.csv.zip', compression='infer')  # 拡張子から自動判断(デフォルト)
df = pd.read_csv('example.csv.gz', compression='gzip')    # .gz
df = pd.read_csv('example.csv.zip', compression=None)     # 解凍しない

エンコーディングを指定する(encoding, encoding_errors)

encoding でエンコーディングを指定できます。

df = pd.read_csv(file, encoding='utf-8')
df = pd.read_csv(file, encoding='Shift_JIS')
df = pd.read_csv(file, encoding='ISO-2022-JP')

encoding_errors にはエンコードエラー発生時の処理を指定できます。

df = pd.read_csv(file, encoding='Shift_JIS', encoding_errors='ignore')

DataFrameをファイルに書き込む

CSVファイルに書き込む(to_csv())

to_csv() で DataFrame を CSV ファイルに書き込むことができます。

df.to_csv('example.csv')

区切り文字を指定する(sep)

sep で区切り文字を指定できます。

df.to_csv('example.tsv', sep='\t')    # TSVファイル
df.to_csv('example.txt', sep=' ')     # TEXTファイル

欠損値を指定する(na_rep)

na_rep で欠損値をどのように書き出すかを指定します。デフォルトは空文字('')です。

df.to_csv(file, na_rep='NaN')

書き込む列を指定する(float_format)

float_format で浮動小数点数のフォーマットを指定できます。

df.to_csv(file, float_format='%.0f')     # 整数部のみ
df.to_csv(file, float_format='%.3f')     # 小数以下3桁まで
df.to_csv(file, float_format='%.3g')     # 有効桁3桁まで
df.to_csv(file, float_format='%.3e')     # 小数以下3桁×指数表記

書き込む列を指定する(columns)

columns で書き込む列を指定できます。

df.to_csv(file, columns=['Name', 'Age'])

列ラベル、行ラベルの書き出しを制御する(header, index)

headerindexFalse を指定すると列ラベル、行ラベルを書き出しません。

df.to_csv('example.csv', header=False, index=False)    # 書き出さない
df.to_csv('example.csv', header=['Name', 'Age'])       # 指定したラベルで書き出す

上書き・追記モードを指定する(mode)

mode で上書き・追記モードを指定できます。

df.to_csv(file, mode='w')         # 上書モード
df.to_csv(file, mode='a')         # 追記モード
df.to_csv(file, mode='x')         # ファイルが既に存在していればエラー

エンコーディングを指定する(encoding)

encoding でエンコーディングを指定できます。

df.to_csv(file, encoding='Shift_JIS')   # シフトJIS

圧縮形式を指定する(compression)

ファイルに拡張子(.gz, .bz2, .zip, .xz, .zst, .tar, .tar.gz, .tar.xz, .tar.bz2)を指定すると自動的に圧縮して書き出します。

df.to_csv('example.csv.zip')            # Zip圧縮

compression で明示的に指定することもできます。

df.to_csv('example.csv.zip', compression='zip')

改行コードを指定する(lineterminator)

lineterminator で改行コードを指定することができます。デフォルトは OS の標準に従います。

df.to_csv('example.csv.zip', lineterminator='\r\n')

日付フォーマットを指定する(date_format)

date_format で日付フォーマットを指定することができます。

df.to_csv(file, date_format='%Y/%m/%d')

DataFrame情報を得る

DataFrame情報を得る(info())

info() は DataFrame に関する列数、行数、型、使用メモリなどの情報を返します。

print(df.info())
# <class 'pandas.DataFrame'>
# RangeIndex: 3 entries, 0 to 2
# Data columns (total 2 columns):
#  #   Column  Non-Null Count  Dtype
# ---  ------  --------------  -----
#  0   Name    3 non-null      str
#  1   Age     3 non-null      int64
# dtypes: int64(1), str(1)
# memory usage: 180.0 bytes
# None

列ラベル、行ラベル、データ型、値を得る(columns, index, dtypes, values)

列ラベル(columns)、行ラベル(index)、データ型(dtypes)、値(values) を表示します。

df = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Age': [36, 42, 54]})
df.columns          # Index(['Name', 'Age'], dtype='str')
df.index            # RangeIndex(start=0, stop=3, step=1)
df.dtypes['Name']   # str
df.values           # [['Yamada', 36], ['Suzuki', 42], ['Tanaka', 54]]

列ラベル(columns)、行ラベル(index) は tolist() でリスト化できます。

df.columns.tolist()    # ['Name', 'Age']
df.index.tolist()      # [0, 1, 2]

行数、列数を得る(len, size, shape)

len(df)           # 3 ... 行数
len(df.columns)   # 2 ... 列数
df.shape          # (3, 2) ... (行数, 列数)
df.size           # 6 ... 行数×列数

数値列の統計量を得る(describe())

describe() は数値列の個数、平均値、標準偏差、最小値、25%値、50%値(中央値)、75%値、最大値を返します。

print(df.describe())
             Age
count   3.000000
mean   44.000000
std     9.165151
min    36.000000
25%    39.000000
50%    42.000000
75%    48.000000
max    54.000000

DataFrameから行・列を取り出す

指定した列を取り出す([...])

列ラベルを指定して取り出します。戻り値は DataFrame ではなく Series となります。

df['Name']           # Series(['Yamada', 'Suzuki', 'Tanaka'])
df.Name              # Series(['Yamada', 'Suzuki', 'Tanaka'])

tolist() でリスト化できます。

df['Name'].tolist()  # ['Yamada', 'Suzuki', 'Tanaka']
df.Name.tolist()     # ['Yamada', 'Suzuki', 'Tanaka']

行ラベル、列ラベルを指定して取り出す(loc[], at[], filter())

行ラベルを指定して取り出します。

df.loc[2]                    # 2行目をSeriesとして取り出す
df.loc[0:2]                  # 0~2行目をDataFrameとして取り出す
df.loc[[0,2]]                # 0と2行目をDataFrameとして取り出す

列ラベルを指定して取り出します。

df.loc[:, 'Name']            # Name列をSeriesとして取り出す
df.loc[:, 'Name':'Age']      # Name列~Age列をDataFrameとして取り出す
df.loc[:, ['Name', 'Age']]   # Name列とAge列をDataFrameとして取り出す

行ラベル、列ラベルを用いて値を取り出します。

df.at[1, 'Name']             # 1行目のName列の値を取り出す

filter() を用いても同様のことができます。

df.filter(items=['Name', 'Age'])    # 列ラベルを指定して列を取り出す
df.filter(items=[0, 1, 2], axis=1)  # 行ラベルを指定して行を取り出す

like はラベル名を部分マッチで、regex は正規表現でマッチさせます。

df.filter(like='ame')                # ameを含む列ラベルの列を取り出す
df.filter(regex=['e$'])              # 末尾がeで終わる列ラベルの列を取り出す

行インデックス、列インデックスを指定して取り出す(iloc[], iat[])

行インデックス(0, 1, 2, ...)を用いて取り出します。行ラベルを index=[1, 2, 3, ...] としていても、行インデックスは 0 から始まります。

df.iloc[0]             # 0行目をSeriesとして取り出す
df.iloc[0:2]           # 0~(2-1)行目をDataFrameとして取り出す
df.iloc[[0,2]]         # 0行目と2行目をDataFrameとして取り出す

列インデックス(0, 1, 2, ...)を用いて取り出します。

df.iloc[:, 0]          # 0列目をSeriesとして取り出す
df.iloc[:, 0:2]        # 0~(2-1)列目をDataFrameとして取り出す
df.iloc[:, [0,1]]      # 0列目と1列目をDataFrameとして取り出す

行インデックス、列インデックスを用いて値を取り出します。

df.iat[0, 0]           # 0行目の0列目の値を取り出す

最初の/最後のn行を取り出す(head(), tail())

最初の n 行、最後の n 行を取り出します。n を省略すると5と見なします。

df.head(3)             # 最初の3行
df.tail(3)             # 最後の3行

条件にマッチした行を取り出す([condition])

下記の様にして条件にマッチした行を取り出すことができます。AND(&) や OR(|) も使用できます。

df[df['Age'] > 40]
df[(40 <= df['Age']) & (df['Age'] < 50)]

条件にマッチした行を取り出す(query())

query() を用いても同様のことができます。使用できる演算子には、等しい(==)、等しくない(!=)、大小比較(<, <=, >=, >)、四則演算(+, -, *, /)、切り捨て除算(//)、剰余(%)、べき乗(**)、含む(in)、かつ(and)、または(or)、否定(not)、ビット反転(~)などがあります。

df.query('Age > 40')
df.query('Name in ["Yamada", "Suzuki"]')

@ で変数も参照できます。

low = 40
high = 50
df2 = df.query('@low <= Age < @high')

str で文字列化することによりいくつかの文字列メソッドを使用できます(詳細)。

df.query('Name.str.contains("a")')                 # "a"を含んでいれば
df.query('Name.str.startswith("Y")')               # "Y"で始まっていれば
df.query('Name.str.endswith("a")')                 # "a"で終わっていれば
df.query('Name.str.match(r"[XYZ]")')               # 正規表現 [XYZ] にマッチすれば
df.query('Name.str.isalpha()')                     # アルファベットであれば
df.query('Name.str.isdigit()')                     # 数値であれば
df.query('Name.str.lower() == "yamada"')           # 小文字に変換
df.query('Name.str.upper() == "YAMADA"')           # 大文字に変換
df.query('Name.str.len() == 6')                    # 文字数
df.query('Name.str.count("a") == 3')               # "a"が現れる回数
df.query('Name.str.strip() == "Yamada"')           # 左右の空白を削除
df.query('Name.str.lstrip() == "Yamada"')          # 左側の空白を削除
df.query('Name.str.rstrip() == "Yamada"')          # 右側の空白を削除
df.query('Name.str.replace("Y", "T") == "Tamada"') # "Y"を"T"に置換
df.query('Name.str.split("a").str[0] == "Y"')      # "a"で分割

型を指定して取り出す(select_dtypes())

select_dtypes() で型を指定して列を取り出すことができます。

df.select_dtypes(include='int')               # 型がint系の列
df.select_dtypes(include=['int', 'string'])   # 型がint系またはstring系の列
df.select_dtypes(exclude='int')               # 型がint系以外の列
df.select_dtypes(exclude=['int', 'string'])   # 型がint系またはstring系以外の列

DataFrameに行・列を追加する

単数行を追加する(loc[])

1行を追加するには loc[] を使用できます。append() は廃止されました。

df.loc[len(df)] = {'Name': 'Kimura', 'Age': 28}

複数行を追加する(concat())

複数行追加するには pd.concat() を使用します。以前は append() もありましたが廃止されました。

rows = [ {'Name': 'Kimura', 'Age': 28}, {'Name': 'Nakano', 'Age': 62} ]
df = pd.concat([df, pd.DataFrame(rows)], ignore_index=True)

単数行を挿入する(分割+concat())

単数行を挿入する機能は提供されていません。無理矢理挿入する場合は分割して結合するしかなさそうです。

df2 = pd.DataFrame([{'Name': 'Kimura', 'Age': 28}])
df = pd.concat([df.iloc[:2], df2, df.iloc[2:]]).reset_index(drop=True)

単数列を追加する([...])

列を追加するには下記の様にします。全行に同じデータが入ります。

df['Gender'] = 'Unknown'

各行の値を指定するには下記の様にします。要素数が行数と一致している必要があります。

df['Gender'] = ['Male', 'Female', 'Male']

既存の列をベースに設定することもできます。

df['After_10_years'] = df['Age'] + 10
df['IsAdult'] = df['Age'] >= 20             # True/False
df['IsAdult'] = np.where(df['Age'] >= 20, 'Adult', 'Minor')

単数列を変更・追加する(assign())

assign() で列の値を変更したり、列を追加することができます。元の df は変更されません。

df = df.assign(Age=[37, 43, 55])                   # Age列の値を変更
df = df.assign(Gender=['Male', 'Female', 'Male'])  # Gender列を追加

単数列を挿入する(insert())

列数を指定して列を間に挿入することができます。下記の例は1列目の右側に 'Gender' 列を追加します。

df.insert(1, 'Gender', 'Unknown')
df.insert(1, 'Gender', ['Male', 'Female', 'Male'])
df.insert(1, 'Gender', df['Age'] + 10)
df.insert(1, 'Gender', df['Age'] >= 20)
df.insert(1, 'Gender', np.where(df['Age'] >= 20, 'Adult', 'Minor'))

複数列を追加する(concat())

concat()axis=1 を指定して複数列を追加することができます。

df2 = pd.DataFrame({'Gender': ['Male', 'Female', 'Male'], 'IsAdult': [True, True, True]})
df = pd.concat([df, df2], axis=1)

列・行を削除する

列・行を削除する(drop())

drop() は列や行を削除します。

df = df.drop(index=0)                  # 行ラベル0の行を削除する
df = df.drop(index=[0, 2])             # 行ラベル0と2の行を削除する
df = df.drop(columns='Age')            # 列ラベル'Age'の列を削除する
df = df.drop(columns=['Name', 'Age'])  # 列ラベル'Age'の列を削除する

列を取り出す(pop())

pop() は指定した列を取り出し、DataFrame から削除します。

df.pop('Age')    # 戻り値はAge列。DataFrameからAge列が削除される

欠損値

欠損値(NaN, None, NA, NaT, ...)

pandas には型に応じていくつかの欠損値があります。ファイルから読み込む際には 空文字や NaNnanN/ANAnullNULL などの文字列も欠損値と見なされます(詳細)。int32 などの型は欠損値を扱うことができず、欠損値がある場合は float32 に変換されるので注意してください。Int32 であれば欠損値を扱えます。

np.nan : float系の欠損値。表示は NaNpd.NA : Int系, UInt系、boolean, string などの欠損値。表示は <NA>
pd.NaT : datetime64[ns], timedelta64[ns] の欠損値。表示は NaTNone : object の欠損値。表示は None
df = pd.DataFrame({
    'Name':  pd.Series([pd.NA], dtype='string'),
    'Age':   pd.Series([pd.NA], dtype='Int32'),
    'Date':  pd.Series([pd.NaT], dtype='datetime64[ns]'),
    'Point': pd.Series([np.nan], dtype='float32'),
    'Note':  pd.Series([None], dtype='object'),
})
print(df)
#    Name   Age Date  Point  Note
# 0  <NA>  <NA>  NaT    NaN  None

欠損値か否かを判定する(isna())

isna() は値が欠損値か否かを判定します。互換性のために同等機能の isnull() も残されています。

pd.isna(df.loc[0, 'Name'])    # True/False

欠損値を削除する(dropna())

dropna() は欠損値のある行を削除します。how='any' とするとひとつでも欠損値がある行、how='all' とするとすべてが欠損値の行を削除します。省略時は 'any' です。

df = pd.DataFrame([
    ['A1',  'B1',  'C1'],
    ['A2',  'B2',  pd.NA],
    ['A3',  pd.NA, pd.NA],
    [pd.NA, pd.NA, pd.NA],
], columns=['A', 'B', 'C'], index=[1, 2, 3, 4])
print(df.dropna())              # how='any'と同義
print(df.dropna(how='any'))     # ひとつでも欠損値があれば削除
print(df.dropna(how='all'))     # すべて欠損値であれば削除

欠損値を固定値/平均値/中央値で埋める(fillna())

fillna() を用いて欠損値を埋めることができます。

df = pd.DataFrame({'A': [1.0, np.nan, np.nan, 4.0], 'B': [1.0, pd.NA, pd.NA, 4.0]})
df['A'] = df['A'].fillna(-1.0)            # -1.0 で埋める
df['A'] = df['A'].fillna(df.mean())       # 平均値(2.5)で埋める
df['A'] = df['A'].fillna(df.median())     # 中央値(2.5)で埋める
df['A', 'B'] = df['A', 'B'].fillna(-1.0)  # 複数の列に対して埋める
df = df.fillna(-1.0)                      # すべての列に対して埋める

欠損値を前出値/後出値で埋める(ffill(), bfill())

ffill(), bfill() を用いて欠損値を前出値、後出値で埋めることができます。

df['A'] = df['A'].ffill()                 # 前出の値(1.0)で埋める
df['A'] = df['A'].bfill()                 # 後出の値(4.0)で埋める

欠損値を補完値で埋める(interpolate())

interpolate() を用いると欠損値を線形変化した場合の値や、スプライン曲線に従った場合の値で補完することができます。時系列に線形補完する場合は method='time' を指定します。その他の method 値については 詳細 を参照してください。

df = pd.DataFrame({'A': [1.0, np.nan, np.nan, 4.0], 'B': [1.0, pd.NA, pd.NA, 4.0]})
df['A'].interpolate()                  # method='lenear'と同義
df['A'].interpolate(method='linear')   # 線形変化すると想定して補完
df['A'].interpolate(method='spline')   # スプライン曲線に従って変化すると想定して補完

マルチインデックス

マルチインデックスのDataFrameを作成する(MultiIndex, set_index())

MultiIndex を用いて多階層のインデックスを持つ DataFrame を生成することができます。

index = pd.MultiIndex.from_tuples(
    [(2025, 12), (2026, 1), (2026, 2)],
    names=['Year', 'Month']
)
df = pd.DataFrame({'Sales': [100, 120, 140]}, index=index)
print(df)
#             Sales
# Year Month
# 2025 12       100
#      1        120
# 2026 2        140

DataFrame 作成後に set_index() を使用して作成することもできます。

df = pd.DataFrame({
    'Year': [2025, 2025, 2026],
    'Month': [12, 1, 2],
    'Sales': [100, 120, 140],
})
df = df.set_index(['Year', 'Month'])
print(df)

DataFrameをソートする

値でソートする(sort_values())

sort_values() は値で行や列をソートします。kind には quicksort(デフォルト), mergesort, heapsort, stable のいずれかを指定します。

df.sort_values('Age')                       # Age列の値で昇順にソートする
df.sort_values('Age', ascending=False)      # 降順にソートする
df.sort_values('Age', inplace=True)         # DataFrame自体を変更する
df.sort_values('Age', kind='quicksort')     # ソートアルゴリズムを指定する
df.sort_values('Age', na_position='first')  # 欠損値を先頭に配置する
df.sort_values('Age', ignore_index=True)    # インデックスをリナンバリングする
df.sort_values(row, axis='columns')         # 列方向にソートする
df.sort_values('Name', key=lamda s: s.str.len())   # ソート関数を指定する

ラベルでソートする(sort_index())

sort_index() は行ラベルや列ラベルで行や列をソートします。

df.sort_index()                          # 行ラベルで行を昇順にソートする
df.sort_index(ascending=False)           # 降順にソートする
df.sort_index(na_position='first')       # 欠損値を先頭に配置する
df.sort_index(kind='quicksort')          # ソートアルゴリズムを指定する
df.sort_index(level=1)                   # マルチインデックスで行ラベルの1階層目(0始まり)でソートする
df.sort_index(level=[0,1])               # マルチインデックスで行ラベルの0階層目を第1キー、1階層目を第2キーとしてソートする
df.sort_index(sort_remaining=False)      # level指定時他のインデックスではソートしない(デフォルトはソートする)
df.sort_index(ignore_index=True)         # インデックスをリナンバリングする
df.sort_index(axis='columns')            # 列ラベルで列をソートする
df.sort_index(key=lamda s: s.str.len())  # ソート関数を指定する

DataFrameをマージする

DataFrameをマージする(merge())

merge() は二つの DataFrame をマージします。

df1 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Age': [36, 42, 54]})
df2 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Gender': ['Male', 'Female', 'Male']})
df3 = pd.merge(df1, df2)
#     Name  Age  Gender
# 0  Yamada  36    Male
# 1  Suzuki  42  Female
# 2  Tanaka  54    Male

下記のようにも書けます。

df3 = df1.merge(df2)

結合キーを指定する(on, left_on, right_on)

通常はふたつの DataFrame で重複する列ラベルが結合キーとなりますが、on で明示的に指定することができます。

df3 = pd.merge(df1, df2, on='Name')

left_on, right_on を使用すると異なる列ラベルでも結合することができます。

df1 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Age': [36, 42, 54]})
df2 = pd.DataFrame({'User': ['Yamada', 'Suzuki', 'Tanaka'], 'Gender': ['Male', 'Female', 'Male']})
df3 = pd.merge(df1, df2, left_on='Name', right_on='User')
#      Name  Age    User  Gender
# 0  Yamada   36  Yamada    Male
# 1  Suzuki   42  Suzuki  Female
# 2  Tanaka   54  Tanaka    Male

結合方式(内部結合/外部結合/左結合/右結合/交差結合)を指定する(how)

how で結合方式を指定できます。デフォルトは inner で内部結合となり、左表・右表両方に存在する行が生成されます。

df1 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Age': [36, 42, 54]})
df2 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Kimura'], 'Gender': ['Male', 'Female', 'Male']})
df3 = pd.merge(df1, df2, how='inner')
#      Name  Age  Gender
# 0  Yamada   36    Male
# 1  Suzuki   42  Female

outer を指定すると外部結合となり、左表と右表どちらかに存在する行が生成されます。結合できない箇所は欠損値となります。

df1 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Age': [36, 42, 54]})
df2 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Kimura'], 'Gender': ['Male', 'Female', 'Male']})
df3 = pd.merge(df1, df2, how='outer')
#      Name   Age  Gender
# 0  Kimura   NaN    Male
# 1  Suzuki  42.0  Female
# 2  Tanaka  54.0     NaN
# 3  Yamada  36.0    Male

left を指定すると左結合となり、右表に存在しなくても、左表に存在する行が生成されます。

df1 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Age': [36, 42, 54]})
df2 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Kimura'], 'Gender': ['Male', 'Female', 'Male']})
df3 = pd.merge(df1, df2, how='left')
#      Name  Age  Gender
# 0  Yamada   36    Male
# 1  Suzuki   42  Female
# 2  Tanaka   54     NaN

right を指定すると右結合となり、左表に存在しなくても、右表に存在する行が生成されます。

df1 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Tanaka'], 'Age': [36, 42, 54]})
df2 = pd.DataFrame({'Name': ['Yamada', 'Suzuki', 'Kimura'], 'Gender': ['Male', 'Female', 'Male']})
df3 = pd.merge(df1, df2, how='right')
#      Name   Age  Gender
# 0  Yamada  36.0    Male
# 1  Suzuki  42.0  Female
# 2  Kimura   NaN    Male

cross を指定すると交差結合となり、左表と右表のすべての組み合わせが生成されます。ラベルには _x, _y が追加されます。

df1 = pd.DataFrame({'Name': ['Yamada', 'Suzuki'], 'Age': [36, 42]})
df2 = pd.DataFrame({'Name': ['Tanaka', 'Kimura'], 'Age': [54, 28]})
df3 = pd.merge(df1, df2, how='cross')
   Name_x  Age_x  Name_y  Age_y
0  Yamada     36  Tanaka     54
1  Yamada     36  Kimura     28
2  Suzuki     42  Tanaka     54
3  Suzuki     42  Kimura     28

left_anti を指定すると左アンチ結合となり、左表にのみ存在する行みを生成します。right_anti も同様です。Pandas 3 で追加されました。

df3 = pd.mearge(df1, df2, how='left_anti')    # 左アンチ結合
df3 = pd.mearge(df1, df2, how='right_anti')   # 右アンチ結合

上記の outerrightAge に欠損値が生じる場合、int64 型では欠損値を扱えないため、欠損値を扱える float64 に型変換されています。あらかじめ Int64 に変更しておくと整数型のまま欠損値を扱えます。

df1['Age'] = df1['Age'].astype('Int64')

列方向にマージする(join())

merge() は行方向のマージを行いますが、join() は行ラベルをキーとして列方向のマージを行います。

df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2']})
df2 = pd.DataFrame({'B': ['B0', 'B1', 'B2']})
df3 = df1.join(df2)
#     A   B
# 0  A0  B0
# 1  A1  B1
# 2  A2  B2

merge() と違い pd.join() はサポートされていません。how のデフォルトは left となります。

DataFrameをグルーピングする

グルーピングする(groupby())

groupby() を用いて、指定した列の値で行をグルーピングし、グループ毎の平均値や中央値を計算することができます。

df = pd.DataFrame({
    'Country': ['Japan', 'Japan', 'Japan', 'USA', 'USA', 'USA'],
    'City': ['Tokyo', 'Tokyo', 'Osaka', 'NY', 'NY', 'LA'],
    'Point': [72, 95, 63, 88, 92, 74],
})
#   Country   City  Point
# 0   Japan  Tokyo     72
# 1   Japan  Tokyo     95
# 2   Japan  Osaka     63
# 3     USA     NY     88
# 4     USA     NY     92
# 5     USA     LA     74
df.groupby('Country').mean(numeric_only=True)            # Countryでグルーピングして平均値を求める
#              Point
# Country
# Japan    76.666667
# USA      84.666667
df.groupby(['Country', 'City']).mean(numeric_only=True)  # CountryとCityでグルーピングして平均値を求める
#                Point
# Country City
# Japan   Osaka   63.0
#         Tokyo   83.5
# USA     LA      74.0
#         NY      90.0

ラベルを変更する

行・列ラベルを変更する(columns, index, set_axis())

columnsindex で列ラベル、行ラベルを変更することができます。set_axis() でも同様のことができます。

df.columns = ['NAMAE', 'NENREI']        # 列ラベルを変更
df.index = [1, 2, 3]                    # 行ラベルを変更
df.set_axis(['NAMAE', 'NENREI'])        # 列ラベルを変更
df.set_axis([1, 2, 3], axis=='index')   # 行ラベルを変更

行・列ラベルを変更する(rename())

rename() で行ラベル、列ラベルを一部のみ変更することができます。元の DataFrame は変更されません。

df = df.rename(columns={'Name': 'NAMAE', 'Age': 'NENREI'}, index={0:1, 1:2, 2:3})

ラムダ式で変更することもできます。

df = df.rename(index=lambda x: x + 1)

inplace=True を指定すると元の DataFrame が変更されます。

df.rename(columns={'Name': 'NAMAE', 'Age': 'NENREI'}, index={0:1, 1:2, 2:3}, inplace=True)

インデックスを設定する(set_index())

set_index() は現在のインデックス(行ラベル)を削除し、代わりに引数で指定した列を行ラベルとして使用します。

df = pd.DataFrame([
    [10, 'Yamada', 36],
    [20, 'Suzuki', 42],
    [30, 'Tanaka', 54],
], columns=['Number', 'Name', 'Age'])
print(df)
#    Number    Name  Age
# 0      10  Yamada   36
# 1      20  Suzuki   42
# 2      30  Tanaka   54
print(df.set_index('Number'))
#           Name  Age
# Number
# 10      Yamada   36
# 20      Suzuki   42
# 30      Tanaka   54

下記などのオプションを使用できます。

df.set_index(..., drop=False)     # インデックスとして指定した列を列にも残す
df.set_index(..., append=True)    # 現在のインデックスに指定した列をインデックスとして追加する
df.set_index(..., inplace=True)   # DataFrame自体を変更する

インデックスをリセットする(reset_index())

reset_index() は現在の行ラベルを列に加え、新たに 0, 1, 2... のインデックス番号(行ラベル)を振りなおします。groupby() 実行後はグループキーが行ラベルとなるため、これを再度 0, 1, 2, ... のインデックス番号に振りなおす際などに使用されます。

df = pd.DataFrame([
    ['Yamada', 36],
    ['Suzuki', 42],
    ['Tanaka', 54],
], columns=['Name', 'Age'], index=[10, 20, 30])
print(df)
      Name  Age
10  Yamada   36
20  Suzuki   42
30  Tanaka   54
print(df.reset_index())
   index    Name  Age
0     10  Yamada   36
1     20  Suzuki   42
2     30  Tanaka   54

下記などのオプションを使用できます。

df.reset_index(drop=True)         # 元の行ラベルを破棄する
df.reset_index(inplace=True)      # 元のDataFrameを直接変更する
df.reset_index(level=True)        # マルチインデックスの一部のみを解除する
df.reset_index(names='OldIndex')  # 古いインデックスの列名を指定する

データに対して関数を実行する

Seriesの値に対して関数を実行する(map())

map() は各値に対して関数を実行します。

ser = pd.Series([98, 46, 82])
ser = ser.map(lambda x: x * 2)   # 196, 92, 164

DataFrameの値対して関数を実行する(map())

DataFrame に対して map() を行うとすべての値に対して関数を実行します。列に対して行うとその列に対してのみ実行します。

df.map(lambda x: print(f"[{x}]"))           # すべての値を[...]付で表示する
df['Age'] = df['Age'].map(lambda x: x + 1)  # Age列の値に1加える

na_action='ignore' を指定すると欠損値に対しては処理を行いません。

df['Age'].map(lambda x: x + 1, na_action='ignore')

下記の様に関数に渡す名前付き変数を指定することもできます。

def add(x, n):
    return x + n

df['Age'] = df['Age'].map(add, n=3)

列に対して関数を実行する(apply())

apply() は列に対して関数を実行します。関数は Series を引数として受け取れる必要があります。戻り値は各列に対して関数を実行した結果を格納した Series となります。

df = pd.DataFrame({
    'X': [1, 2, 3],
    'Y': [4, 5, 6],
    'Z': [7, 8, 9]
})
ser = df.apply(sum)
# X    6
# Y   15
# Z   24

下記などの引数を指定できます。

df.apply(sum, axis='columns')  # 列ではなく行に対して実行する
df.apply(sum, raw=True)        # SeriesではなくNumPy ndarrayとして渡す
df.apply(sum, engine='numba')  # Numba JITコンパイラを用いて高速化する
df.apply(func, foo='Foo')      # 関数に任意の名前付き引数を渡す

ループで回す

ループで回す(iterrows(), itertuples(), items(), to_numpy())

DataFrame は明示的なループ処理は行わず、ベクトル演算、apply()query() などを使用するのが原則ですが、練習用やデバッグ用にループを回す場合は下記などの手段があります。

for index, row in df.iterrows():        # 遅い
    for col in df.columns:
        print(index, col, row[col])

for row in df.itertuples():             # iterrows()よりは早い
    print(row.Index, row.Name, row.Age)

for col, rows in df.items():            # 列ごとに処理
    for row in rows:
        print(col, row)

for val in df.to_numpy():               # ループの中では比較的高速
    print(val[0], val[1])

# for文を使用しない処理
df.apply(lambda row: print(row['Name'], row['Age']), axis=1)

集計や変更

値を置換する(replace())

replace() で値を置換することができます。下記はデータ中のすべての 'Yamada''YAMADA' に置換します。

df = df.replace('Yamada', 'YAMADA')

複数指定することもできます。

df = df.replace({'Yamada': 'YAMADA', 'Suzuki': 'SUZUKI'})
df = df.replace(['Yamada', 'Suzuki'], ['YAMADA', 'SUZUKI'])

置換する対象列を限定することができます。下記の例では、Name 列のみを置換します。

df = df.replace({'Name': {'Yamada': 'YAMADA'})

正規表現を使用することもできます。

df = df.replace('^(yamada|Yamada)$', 'YAMADA', regex=True)

\1, \2, ... で正規表現の (...) にマッチした文字列を参照することができます。

df = pd.DataFrame({'Date': ['2026-02-15', '2026-02-16']})
df = df.replace('(.+)-(.+)-(.+)', r'\1\2\3日', regex=True)

集計処理をまとめて実行する(agg())

agg() は aggregate(集計)の意味で、各列に対する集計処理を一括で行います。下記の例では、A列、B列に対して最小値、最大値、合計値をまとめて計算しています。まとめて計算することで、個別に計算するよりも高速に計算することができます。

df = pd.DataFrame({
    'A': [57, 83, 23],
    'B': [36, 42, 54],
})
print(df.agg(["min", "max", "sum"]))
#        A    B
# min   23   36
# max   83   54
# sum  163  132

groupby() でグルーピングした各グループに対して、複数の集計処理を行うこともできます。

df = pd.DataFrame({
    'Store': ['A', 'A', 'A', 'B', 'B'],
    'Sales': [100, 200, 150, 300, 250],
    'Quantity': [2, 3, 2, 5, 3],
})
print(df.groupby('Store').agg({
    'Sales': ['min', 'max', 'mean', 'sum'],
    'Quantity': 'sum'
})
      Sales                  Quantity
        min  max   mean  sum      sum
Store
A       100  200  150.0  450        7
B       250  300  275.0  550        8

下記の様に結果ラベルを指定することもできます。

print(df.groupby('Store').agg(
    min_sales=('Sales', 'min'),
    max_sales=('Sales', 'max'),
    mean_sales=('Sales', 'mean'),
    total_sales=('Sales', 'sum'),
    total_count=('Quantity', 'sum')
)
#        min_sales  max_sales  mean_sales  total_sales  total_count
# Store
# A            100        200       150.0          450            7
# B            250        300       275.0          550            5

値の出現回数をカウントする(value_counts())

value_counts() は Series や DataFrame の列に適用して、同じ値が出現した回数を集計します。下記の例では 1~6 の乱数を10,000個作成し、それぞれの値の出現回数を集計しています。デフォルトでは降順にソートされます。

ser = pd.Series(np.random.randint(1, 7, size=10000))
print(ser.value_counts())
# 2    1722
# 6    1717
# 3    1664
# 5    1644
# 4    1634
# 1    1619

下記などのオプションを指定できます。

ser.value_counts(normalize=True)   # 出現回数の代わりに出現割合(0.0~1.0)を集計する
ser.value_counts(dropna=False)     # 欠損値も集計する
ser.value_counts(ascending=True)   # 昇順にソートする
ser.value_counts(sort=False)       # ソートしない
ser.value_counts(bins=3)           # 出現する数値を3等分し、それぞれのグループについて集計する

ピボット集計する(pivot_table())

pivot_table() は Excel のピボットテーブルのようにデータをクロス集計します。

df = pd.DataFrame({
    'Store': ['A', 'A', 'A', 'B', 'B'],
    'Item':  ['X', 'Y', 'X', 'X', 'Y'],
    'Sales': [100, 200, 150, 300, 250],
    'Quantity': [2, 3, 2, 5, 3],
})
print(pd.pivot_table(
    df,
    values='Sales',
    index='Store',
    columns='Item',
    aggfunc='sum'
))
# Item     X    Y
# Store
# A      250  200
# B      300  250

下記などのオプションを指定できます。

pd.pivot_table(..., fill_value=0)          # # 欠損値を0とみなす
pd.pivot_table(..., margins=True)          # # 末尾に合計列・合計行(All)を追加する
pd.pivot_table(..., margins_name='Total')  # # 合計列・合計行のラベルを'All'から変更する
pd.pivot_table(..., sort=False)            # # 列ラベル・行ラベルでソートしない(デフォルトはソート)

値を上限・下限で制限する(clip())

clip(min, max) は DataFrame や Series の値の中から、min 以下の値を min に、max 以上の値を max に制限します。

df = df.clip(1, 100)         # 下限を1、上限を100とする
df = df.clip(lower=1)        # 下限のみを指定する
df = df.clip(upper=100)      # 上限のみを指定する

下記の様に、列毎に異なる下限値・上限値を指定することもできます。

df = df.clip([10, 20, 30], [70, 80, 90])

下記のオプションを指定できます。

df.clip(..., axis='columns')    # 列ではなく行に対して適用します
df.clip(..., inplace=True)      # DataFrame自体を変更します

条件により値を置換する(mask(), where())

mask() は条件にマッチした値を指定した値に置換します。

df = df.mask(df >= 40, 999)            # 999に置換する
df = df.mask(df >= 40)                 # NaNに置換する
df = df.mask(df >= 40, df + 10)        # +10した値に置換する
df['A'] = df['A'].mask(df['A'] >= 40)  # 列にだけ指定する

where() は条件にマッチしなかった値を指定した値に置換します。

df = df.where(df >= 40, 999)           # 40未満の値を999に置換する

下記などのオプションを指定できます。

df.mask(..., inplace=True)           # DataFrame自体を変更する
df.mask(..., axis='columns')         # 行に対して実行する

数値をランキングする(rank())

rank() は数値を小さい順に並べて1位, 2位, 3位...とランキングします。下記の例では、18が1位、22が2位、34が3位、43が4位、56が5位となります。3位が同順で2つ存在する場合はそれぞれが平均値の3.5位となります。

df = pd.DataFrame({'Score': [34, 22, 56, 18, 43]})
print(df.rank())
#    Score
# 0    3.0
# 1    2.0
# 2    5.0
# 3    1.0
# 4    4.0

下記のオプションを指定できます。

df.rank(ascending=False)     # 降順でランキングする(数値の大きな方が上位)
df.rank(pct=True)            # 0.0~1.0でランキングする。0.3以下のものを抽出すると上位30%のデータを取得できる
df.rank(axis='columns')      # 列ではなく行方向にランキングする
df.rank(method='min')        # 同順の場合の順位の計算方法を指定する(average,min,max,first,dense)
df.rank(numeric_only=True)   # ランキング対象を数値列のみに絞る
df.rank(na_option='bottom')  # NaNの順位を最下位とする(keep,top,bottom)

重複行を判定・削除する(duplicated(), drop_duplicates())

duplicated() は行を比較し、値がすべて前出のものと重複しているか否かを判定します。

df = pd.DataFrame([
    ['Yamada', 36],
    ['Suzuki', 42],
    ['Yamada', 36],
])
print(df.duplicated())
# 0    False   ← 重複しているけど最初の行なのでFalse
# 1    False   ← 重複していないのでFalse
# 2     True   ← 重複していて最初の行ではないのでTrue

下記のオプションを指定できます。

df.duplicated(keep='first')      # 重複行の中で最初の行はFalseとする(デフォルト)
df.duplicated(keep='last')       # 重複行の中で最後の行はFalseとする
df.duplicated(keep=False)        # 重複行をすべてTrueとする
df.duplicated(subset=['A', 'B']) # 全列ではなく、A列とB列のみで判断する

drop_duplicates() は行を比較し、重複する行を削除します。

print(df.drop_duplicates())
#         0   1
# 0  Yamada  36
# 1  Suzuki  42

下記のオプションを指定できます。

df.drop_duplicates(keep='first')       # 最初に出現する行を残す(デフォルト)
df.drop_duplicates(keep='last')        # 最後に出現する行を残す(デフォルト)
df.drop_duplicates(keep=False)         # 重複行をすべて削除する
df.drop_duplicates(inplace=True)       # DataFrame自体を書き換える
df.drop_duplicates(ignore_index=True)  # 削除後にインデックスを振りなおす

累積和・累積積・累積最大・累積最小を得る(cumsum(), cumprod(), cummax(), cummin())

cumsum()cumprod()cummax()cummin() は累積和・累積積・累積最大・累積最小を算出します。

df = pd.DataFrame({
    'A': [10, 20, 30, 40]
})
df['cumsum'] = df['A'].cumsum()
df['cumprod'] = df['A'].cumprod()
df['cummax'] = df['A'].cummax()
df['cummin'] = df['A'].cummin()
#     A  cumsum  cumprod  cummax  cummin
# 0  10      10       10      10      10
# 1  20      30      200      20      10
# 2  30      60     6000      30      10
# 3  40     100   240000      40      10

下記のオプションを指定できます。

df.cumsum(axis='columns')    # 列ではなく行方向に算出する
df.cumsum(skipna=False)      # NaN値を無視しない。NaN値以降はすべてNaN値とする
df.cumsum(numeric_only=True) # 数値列のみを対象とする

その他

ワイド形式をロング形式に変換する(melt())

melt() は横方向のワイド形式の DataFrame を縦方向のロング形式に変換します。

df = pd.DataFrame({
    "name": ["Yamada", "Suzuki"],
    "A": [10, 20],
    "B": [30, 40],
    "C": [50, 60],
    "D": [70, 80],
})
print(df)
#      name   A   B   C   D
# 0  Yamada  10  30  50  70
# 1  Suzuki  20  40  60  80
print(df.melt(id_vars="name"))
#      name variable  value
# 0  Yamada        A     10
# 1  Suzuki        A     20
# 2  Yamada        B     30
# 3  Suzuki        B     40
# 4  Yamada        C     50
# 5  Suzuki        C     60
# 6  Yamada        D     70
# 7  Suzuki        D     80

行と列を転置する(T)

T は行と列を入れ替えます。

df = pd.DataFrame({
    'Name': ['Yamada', 'Suzuki', 'Tanaka'],
    'Age': [36, 42, 54]
})
print(df)
#      Name  Age
# 0  Yamada   36
# 1  Suzuki   42
# 2  Tanaka   54
print(df.T)
#            0       1       2
# Name  Yamada  Suzuki  Tanaka
# Age       36      42      54