Step 33:ピボットテーブルを作ろう

📊 ステップ33: ピボットテーブルを作ろう

データを表形式で集計して、見やすく分析しよう!

ステップ32では、重複データの処理を学びました。今回は、データを表形式で集計するピボットテーブルの作り方を学びます。

📖 このステップで学ぶこと

・pivot_table()の使い方

・行・列・値の指定

・集計関数の選択

・クロス集計の作成

🎯 1. ピボットテーブルとは?

ピボットテーブルは、データを縦軸と横軸で整理して集計する機能です。Excelのピボットテーブルと同じ考え方です。

🔰 ピボットテーブルのイメージ

📌 ピボットテーブルの例

売上データから、商品×地域の売上合計を表形式で表示

縦軸(行):商品(りんご、バナナ、みかん)

横軸(列):地域(東京、大阪、名古屋)

:売上金額の合計

これにより、「どの商品がどの地域で売れているか」が一目でわかります!

📘 サンプルデータを準備

コード:サンプルデータの作成

import pandas as pd

# 売上データ
sales_data = {
    '日付': ['1/1', '1/1', '1/2', '1/2', '1/3', '1/3', '1/1', '1/2'],
    '商品': ['りんご', 'バナナ', 'りんご', 'みかん', 'バナナ', 'りんご', 
            'みかん', 'バナナ'],
    '地域': ['東京', '大阪', '東京', '名古屋', '大阪', '東京', 
            '東京', '名古屋'],
    '売上': [1200, 900, 1500, 800, 1100, 1000, 750, 950]
}

df = pd.DataFrame(sales_data)
print("売上データ:")
print(df)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

売上データ:
   日付   商品   地域   売上
0  1/1  りんご   東京  1200
1  1/1  バナナ   大阪   900
2  1/2  りんご   東京  1500
3  1/2  みかん  名古屋   800
4  1/3  バナナ   大阪  1100
5  1/3  りんご   東京  1000
6  1/1  みかん   東京   750
7  1/2  バナナ  名古屋   950

💡 このデータから知りたいこと

・商品ごとの売上合計は?

・地域ごとの売上合計は?

・商品×地域の組み合わせでの売上は?

ピボットテーブルを使えば、これらを表形式で見やすく表示できます。

📊 2. pivot_table()の基本

pivot_table()は、DataFrameをピボットテーブル形式に変換するメソッドです。

🔰 最初のピボットテーブル

コード:商品×地域の売上合計

# 商品×地域の売上合計
pivot1 = df.pivot_table(
    values='売上',      # 集計する値
    index='商品',       # 行(縦軸)
    columns='地域',     # 列(横軸)
    aggfunc='sum'      # 集計方法(合計)
)

print("商品×地域の売上合計:")
print(pivot1)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

商品×地域の売上合計:
地域     名古屋     大阪     東京
商品                        
みかん   800.0    NaN   750.0
バナナ   950.0  2000.0    NaN
りんご    NaN    NaN  3700.0

💡 コードの解説

df.pivot_table(…)

 ・DataFrameをピボットテーブルに変換します

values=’売上’

 ・集計する値の列を指定

 ・「売上」列の値を集計します

index=’商品’

 ・行(縦軸)に配置する列を指定

 ・商品名が行の見出しになります

columns=’地域’

 ・列(横軸)に配置する列を指定

 ・地域名が列の見出しになります

aggfunc=’sum’

 ・集計方法を指定(’sum’は合計)

 ・同じ組み合わせの値を合計します

📌 pivot_table()のパラメータまとめ

パラメータ 説明
values 集計する値の列 values=’売上’
index 行(縦軸)に配置する列 index=’商品’
columns 列(横軸)に配置する列 columns=’地域’
aggfunc 集計方法 aggfunc=’sum’

📝 NaNを0に変換

データがない組み合わせはNaN(欠損値)になります。fill_valueで埋められます。

コード:NaNを0に変換

# fill_valueでNaNを0に
pivot2 = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc='sum',
    fill_value=0
)

print("NaNを0に変換:")
print(pivot2)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

NaNを0に変換:
地域    名古屋    大阪    東京
商品                     
みかん   800     0   750
バナナ   950  2000     0
りんご     0     0  3700

💡 fill_valueの効果

fill_value=0

 ・NaN(データなし)を0で埋めます

 ・表が見やすくなります

 ・計算にも使いやすくなります

📘 合計行・列を追加

margins=Trueで、合計行と合計列を追加できます。

コード:合計行・列を追加

# margins=Trueで合計を追加
pivot3 = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc='sum',
    fill_value=0,
    margins=True,
    margins_name='合計'
)

print("合計行・列を追加:")
print(pivot3)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

合計行・列を追加:
地域    名古屋    大阪    東京    合計
商品                          
みかん   800     0   750  1550
バナナ   950  2000     0  2950
りんご     0     0  3700  3700
合計   1750  2000  4450  8200

💡 margins パラメータ

margins=True

 ・合計行と合計列を追加します

margins_name=’合計’

 ・合計行・列の名前を指定(デフォルトは’All’)

結果の見方:

 ・各商品の合計売上がわかる(りんご: 3700円)

 ・各地域の合計売上がわかる(東京: 4450円)

 ・全体の合計売上がわかる(8200円)

🎨 3. 様々な集計方法

aggfuncパラメータで、様々な集計方法を選べます。

📝 平均値で集計

コード:平均値を計算

# 平均値
avg_pivot = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc='mean',
    fill_value=0
)

print("商品×地域の平均売上:")
print(avg_pivot.round(0))

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

商品×地域の平均売上:
地域    名古屋     大阪     東京
商品                       
みかん   800.0    0.0   750.0
バナナ   950.0 1000.0     0.0
りんご     0.0    0.0  1233.0

💡 ‘mean’の意味

aggfunc=’mean’

 ・同じ組み合わせの値を平均します

 ・東京のりんごは3回売れて、合計3700円なので平均1233円

📝 件数を集計

コード:件数をカウント

# 件数(カウント)
count_pivot = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc='count',
    fill_value=0
)

print("商品×地域の販売回数:")
print(count_pivot)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

商品×地域の販売回数:
地域    名古屋  大阪  東京
商品                
みかん     1   0   1
バナナ     1   2   0
りんご     0   0   3

💡 ‘count’の意味

aggfunc=’count’

 ・同じ組み合わせのデータ数を数えます

 ・東京でりんごは3回売れた

 ・大阪でバナナは2回売れた

📘 複数の集計を同時に

aggfuncにリストを渡すと、複数の集計を同時にできます。

コード:複数の集計方法

# 複数の集計方法
multi_pivot = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc=['sum', 'mean', 'count'],
    fill_value=0
)

print("複数の集計:")
print(multi_pivot)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

複数の集計:
         sum                 mean                count           
地域    名古屋    大阪    東京    名古屋     大阪     東京  名古屋 大阪 東京
商品                                                           
みかん   800     0   750   800.0    0.0   750.0    1  0  1
バナナ   950  2000     0   950.0 1000.0     0.0    1  2  0
りんご     0     0  3700     0.0    0.0  1233.3    0  0  3

📌 主な集計関数(aggfunc)

aggfunc 説明
‘sum’ 合計
‘mean’ 平均
‘count’ 件数
‘max’ 最大値
‘min’ 最小値
‘std’ 標準偏差

🔢 4. 複数の軸での集計

📘 複数の行で集計

indexにリストを渡すと、複数の列を行に配置できます。

コード:日付×商品×地域の売上

# 日付×商品×地域
pivot_3d = df.pivot_table(
    values='売上',
    index=['日付', '商品'],
    columns='地域',
    aggfunc='sum',
    fill_value=0
)

print("日付×商品×地域の売上:")
print(pivot_3d)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

日付×商品×地域の売上:
地域        名古屋    大阪    東京
日付  商品                     
1/1  みかん     0     0   750
     バナナ     0   900     0
     りんご     0     0  1200
1/2  みかん   800     0     0
     バナナ   950     0     0
     りんご     0     0  1500
1/3  バナナ     0  1100     0
     りんご     0     0  1000

💡 複数列をindexに指定

index=[‘日付’, ‘商品’]

 ・日付と商品の組み合わせが行になります

 ・階層的なインデックスが作成されます

 ・より詳細な分析ができます

📘 複数の値を集計

valuesにリストを渡すと、複数の列を同時に集計できます。

コード:売上と数量を同時に集計

# 数量列を追加
df['数量'] = [10, 6, 12, 8, 7, 8, 5, 6]

# 売上と数量を同時に集計
multi_value_pivot = df.pivot_table(
    values=['売上', '数量'],
    index='商品',
    columns='地域',
    aggfunc='sum',
    fill_value=0
)

print("売上と数量を同時に集計:")
print(multi_value_pivot)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

売上と数量を同時に集計:
        売上              数量           
地域    名古屋    大阪    東京  名古屋 大阪 東京
商品                                  
みかん   800     0   750    8  0  5
バナナ   950  2000     0    6 13  0
りんご     0     0  3700    0  0 30

📋 5. クロス集計(crosstab)

pd.crosstab()は、2つの列の組み合わせの件数を集計する簡単な方法です。

🔰 crosstab()の基本

コード:クロス集計

# クロス集計
crosstab1 = pd.crosstab(df['商品'], df['地域'])

print("商品×地域のクロス集計:")
print(crosstab1)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

商品×地域のクロス集計:
地域    名古屋  大阪  東京
商品                
みかん     1   0   1
バナナ     1   2   0
りんご     0   0   3

💡 crosstab()の使い方

pd.crosstab(行, 列)

 ・第1引数:行に配置する列

 ・第2引数:列に配置する列

 ・デフォルトで件数をカウントします

pivot_table()との違い:

 ・crosstab():件数を数えるのに特化

 ・pivot_table():様々な値を集計できる

📝 合計を追加

コード:合計行・列を追加

# 合計行・列を追加
crosstab2 = pd.crosstab(
    df['商品'], 
    df['地域'],
    margins=True,
    margins_name='合計'
)

print("合計付きクロス集計:")
print(crosstab2)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

合計付きクロス集計:
地域    名古屋  大阪  東京  合計
商品                    
みかん     1   0   1   2
バナナ     1   2   0   3
りんご     0   0   3   3
合計      2   2   4   8

📘 割合を表示

normalizeパラメータで、割合(パーセント)を計算できます。

コード:割合を表示

# 割合で表示(全体に対する割合)
crosstab_pct = pd.crosstab(
    df['商品'], 
    df['地域'],
    normalize='all'  # 全体に対する割合
) * 100

print("割合(%):")
print(crosstab_pct.round(1))

# 行ごとの割合
crosstab_row_pct = pd.crosstab(
    df['商品'], 
    df['地域'],
    normalize='index'  # 行ごとの割合
) * 100

print("\n行ごとの割合(%):")
print(crosstab_row_pct.round(1))

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

割合(%):
地域    名古屋   大阪   東京
商品                  
みかん  12.5  0.0  12.5
バナナ  12.5 25.0   0.0
りんご   0.0  0.0  37.5

行ごとの割合(%):
地域    名古屋   大阪   東京
商品                  
みかん  50.0  0.0  50.0
バナナ  33.3 66.7   0.0
りんご   0.0  0.0 100.0

💡 normalizeパラメータ

normalize=’all’:全体に対する割合

normalize=’index’:行ごとの割合(各商品の地域別構成比)

normalize=’columns’:列ごとの割合(各地域の商品別構成比)

* 100:0〜1の値を0〜100%に変換

💼 6. 実践例

📘 例1:月次売上レポート

コード:月次売上レポートの作成

import pandas as pd

# 月次データ
monthly_data = pd.DataFrame({
    '月': ['1月', '1月', '1月', '2月', '2月', '2月', '3月', '3月', '3月'],
    '商品': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'],
    '売上': [100, 150, 120, 110, 160, 130, 105, 155, 125]
})

# 月×商品のピボットテーブル
monthly_pivot = monthly_data.pivot_table(
    values='売上',
    index='商品',
    columns='月',
    aggfunc='sum',
    margins=True,
    margins_name='合計'
)

print("月次売上レポート:")
print(monthly_pivot)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

月次売上レポート:
月     1月   2月   3月   合計
商品                     
A    100  110  105  315
B    150  160  155  465
C    120  130  125  375
合計  370  400  385 1155

📘 例2:構成比の計算

コード:地域ごとの商品構成比

# 商品×地域の売上ピボット
sales_pivot = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc='sum',
    fill_value=0
)

print("売上ピボット:")
print(sales_pivot)

# 地域ごとの構成比を計算
# 各地域の合計で割る
composition = sales_pivot.div(
    sales_pivot.sum(axis=0),  # 各列(地域)の合計
    axis=1                     # 列方向で割る
) * 100

print("\n地域ごとの商品構成比(%):")
print(composition.round(1))

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

売上ピボット:
地域    名古屋    大阪    東京
商品                     
みかん   800     0   750
バナナ   950  2000     0
りんご     0     0  3700

地域ごとの商品構成比(%):
地域    名古屋   大阪   東京
商品                   
みかん  45.7   0.0  16.9
バナナ  54.3 100.0   0.0
りんご   0.0   0.0  83.1

💡 構成比の計算方法

sales_pivot.div(sales_pivot.sum(axis=0), axis=1)

 ・sales_pivot.sum(axis=0):各列(地域)の合計を計算

 ・.div(…):割り算

 ・axis=1:列方向で割る

結果の見方:

 ・東京ではりんごが83.1%を占める

 ・大阪ではバナナが100%を占める

📝 練習問題

ここまで学んだことを、実際に手を動かして確認しましょう。

問題1:基本的なピボットテーブル(初級)

📋 問題

以下のデータから、商品×地域の売上合計をピボットテーブルで作成してください。

df = pd.DataFrame({
    '商品': ['A', 'B', 'A', 'C', 'B', 'C'],
    '地域': ['東京', '大阪', '大阪', '東京', '東京', '大阪'],
    '売上': [100, 150, 120, 90, 140, 110]
})

※ 画面が小さい場合は、コードブロックを横にスクロールできます

解答例を見る

コード

import pandas as pd

df = pd.DataFrame({
    '商品': ['A', 'B', 'A', 'C', 'B', 'C'],
    '地域': ['東京', '大阪', '大阪', '東京', '東京', '大阪'],
    '売上': [100, 150, 120, 90, 140, 110]
})

print("元のデータ:")
print(df)

# ピボットテーブル
pivot = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc='sum',
    fill_value=0
)

print("\n商品×地域の売上合計:")
print(pivot)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

元のデータ:
  商品  地域   売上
0  A  東京  100
1  B  大阪  150
2  A  大阪  120
3  C  東京   90
4  B  東京  140
5  C  大阪  110

商品×地域の売上合計:
地域    大阪   東京
商品           
A    120  100
B    150  140
C    110   90

問題2:合計行・列を追加(初級)

📋 問題

問題1のピボットテーブルに、合計行と合計列を追加してください。

解答例を見る

コード

# margins=Trueで合計を追加
pivot_with_total = df.pivot_table(
    values='売上',
    index='商品',
    columns='地域',
    aggfunc='sum',
    fill_value=0,
    margins=True,
    margins_name='合計'
)

print("合計行・列を追加:")
print(pivot_with_total)

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

合計行・列を追加:
地域    大阪   東京   合計
商品                
A    120  100  220
B    150  140  290
C    110   90  200
合計  380  330  710

問題3:平均値のピボットテーブル(中級)

📋 問題

以下のデータから、クラス×科目の平均点をピボットテーブルで作成してください。

df = pd.DataFrame({
    'クラス': ['A', 'A', 'B', 'B', 'A', 'B'],
    '科目': ['数学', '英語', '数学', '英語', '数学', '数学'],
    '点数': [85, 90, 78, 88, 92, 82]
})

※ 画面が小さい場合は、コードブロックを横にスクロールできます

解答例を見る

コード

import pandas as pd

df = pd.DataFrame({
    'クラス': ['A', 'A', 'B', 'B', 'A', 'B'],
    '科目': ['数学', '英語', '数学', '英語', '数学', '数学'],
    '点数': [85, 90, 78, 88, 92, 82]
})

print("元のデータ:")
print(df)

# 平均点のピボットテーブル
pivot_avg = df.pivot_table(
    values='点数',
    index='クラス',
    columns='科目',
    aggfunc='mean',
    fill_value=0
)

print("\nクラス×科目の平均点:")
print(pivot_avg.round(1))

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

元のデータ:
  クラス  科目  点数
0   A  数学  85
1   A  英語  90
2   B  数学  78
3   B  英語  88
4   A  数学  92
5   B  数学  82

クラス×科目の平均点:
科目    数学    英語
クラス           
A    88.5  90.0
B    80.0  88.0

問題4:クロス集計(中級)

📋 問題

以下のアンケートデータから、年齢層×満足度のクロス集計を作成してください(件数と割合)。

df = pd.DataFrame({
    '年齢層': ['20代', '30代', '20代', '40代', '30代', '20代', '40代', '30代'],
    '満足度': ['満足', '満足', '普通', '満足', '不満', '満足', '普通', '満足']
})

※ 画面が小さい場合は、コードブロックを横にスクロールできます

解答例を見る

コード

import pandas as pd

df = pd.DataFrame({
    '年齢層': ['20代', '30代', '20代', '40代', '30代', '20代', '40代', '30代'],
    '満足度': ['満足', '満足', '普通', '満足', '不満', '満足', '普通', '満足']
})

print("元のデータ:")
print(df)

# 件数のクロス集計
crosstab_count = pd.crosstab(
    df['年齢層'], 
    df['満足度'],
    margins=True,
    margins_name='合計'
)

print("\n件数:")
print(crosstab_count)

# 割合(行ごと)
crosstab_pct = pd.crosstab(
    df['年齢層'], 
    df['満足度'],
    normalize='index'
) * 100

print("\n割合(%):")
print(crosstab_pct.round(1))

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

元のデータ:
   年齢層  満足度
0  20代   満足
1  30代   満足
2  20代   普通
3  40代   満足
4  30代   不満
5  20代   満足
6  40代   普通
7  30代   満足

件数:
満足度   不満  普通  満足  合計
年齢層                  
20代    0   1   2   3
30代    1   0   2   3
40代    0   1   1   2
合計    1   2   5   8

割合(%):
満足度     不満    普通    満足
年齢層                  
20代    0.0  33.3  66.7
30代   33.3   0.0  66.7
40代    0.0  50.0  50.0

問題5:総合演習(上級)

📋 問題

以下のデータから:

1. 月×商品の売上合計(合計付き)

2. 月×商品の販売件数

3. 各月の商品別構成比(%)

4. 最も売上が高い月と商品を表示

df = pd.DataFrame({
    '月': ['1月', '1月', '1月', '2月', '2月', '2月', '3月', '3月', '3月'],
    '商品': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'],
    '売上': [100, 150, 120, 110, 160, 130, 105, 155, 125]
})

※ 画面が小さい場合は、コードブロックを横にスクロールできます

解答例を見る

コード

import pandas as pd

df = pd.DataFrame({
    '月': ['1月', '1月', '1月', '2月', '2月', '2月', '3月', '3月', '3月'],
    '商品': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'],
    '売上': [100, 150, 120, 110, 160, 130, 105, 155, 125]
})

print("="*50)
print("売上分析ダッシュボード")
print("="*50)

# 1. 売上合計
sales_pivot = df.pivot_table(
    values='売上',
    index='商品',
    columns='月',
    aggfunc='sum',
    margins=True,
    margins_name='合計'
)

print("\n【1. 月×商品の売上合計】")
print(sales_pivot)

# 2. 販売件数
count_pivot = df.pivot_table(
    values='売上',
    index='商品',
    columns='月',
    aggfunc='count',
    fill_value=0
)

print("\n【2. 月×商品の販売件数】")
print(count_pivot)

# 3. 構成比
sales_no_margin = df.pivot_table(
    values='売上',
    index='商品',
    columns='月',
    aggfunc='sum'
)

composition = sales_no_margin.div(
    sales_no_margin.sum(axis=0), 
    axis=1
) * 100

print("\n【3. 各月の商品別構成比(%)】")
print(composition.round(1))

# 4. 最高売上
max_idx = df['売上'].idxmax()
max_row = df.loc[max_idx]
print(f"\n【4. 最も売上が高い】")
print(f"{max_row['月']}の商品{max_row['商品']}: {max_row['売上']}円")

※ 画面が小さい場合は、コードブロックを横にスクロールできます

実行結果

==================================================
売上分析ダッシュボード
==================================================

【1. 月×商品の売上合計】
月     1月   2月   3月   合計
商品                     
A    100  110  105  315
B    150  160  155  465
C    120  130  125  375
合計  370  400  385 1155

【2. 月×商品の販売件数】
月    1月  2月  3月
商品           
A    1  1  1
B    1  1  1
C    1  1  1

【3. 各月の商品別構成比(%)】
月      1月    2月    3月
商品                  
A    27.0  27.5  27.3
B    40.5  40.0  40.3
C    32.4  32.5  32.5

【4. 最も売上が高い】
2月の商品B: 160円

🎯 このステップのまとめ

✅ 学んだこと

pivot_table()で表形式の集計ができる

values, index, columnsで行・列・値を指定できる

aggfuncで様々な集計関数が使える

marginsで合計行・列を追加できる

crosstab()でクロス集計ができる

✓ 構成比や割合を計算できる

💡 次のステップに進む前に確認

以下のことができるようになったか確認しましょう:

□ pivot_table()でピボットテーブルを作れる

□ 様々な集計関数を使える

□ 合計行・列を追加できる

□ crosstab()でクロス集計ができる

これらができたら、次のステップに進みましょう!

❓ よくある質問

Q1: pivot_table()とgroupby()の違いは?

A: groupby()は集計結果を縦に並べます。

pivot_table()は表形式(縦×横)で表示します。

見やすさが大きく違います。ピボットテーブルはExcelのように見やすい!

Q2: NaNが表示されてしまいます

A: fill_value=0を指定すると、NaNを0に変換できます。

見やすくなり、計算にも使いやすくなります。

Q3: 複数の集計をきれいに表示したいです

A: aggfuncにリストで複数指定できます:

aggfunc=['sum', 'mean', 'count']

ただし列が階層的になるので、見にくい場合は別々に作成することをお勧めします。

Q4: ピボットテーブルをExcelに出力できますか?

A: はい、pivot.to_excel('output.xlsx')で出力できます。

さらに整形したい場合は、openpyxlやxlsxwriterを使います。

Q5: pivot_table()とcrosstab()はどう使い分けますか?

A: pivot_table():数値の集計(売上合計など)

crosstab():件数の集計やカテゴリの組み合わせ

どちらでもできますが、crosstab()の方が件数を数えるのに簡潔です。

📝

学習メモ

Pythonデータ分析入門 - Step 33

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE