🧮 ステップ21: NumPy配列の演算
配列の計算をマスターして、データ分析の基礎を固めよう!
このステップでは、NumPy配列での演算(計算)を学びます。NumPyの真の力は「全ての要素に対して一度に計算できる」ことにあります。これをマスターすれば、データ分析の効率が大きく上がります!
📖 このステップで学ぶこと
・要素ごとの四則演算(+, -, *, /)
・ブロードキャスト(形の違う配列同士の計算)
・条件抽出(条件に合うデータだけを取り出す)
・np.where()での条件分岐
・便利な数学関数
学習時間の目安: 2.5〜3時間
🎯 1. 要素ごとの四則演算
NumPy配列の最大の特徴は、全ての要素に対して一度に計算できることです。
🔰 配列と数値の演算
配列に数値を足したり掛けたりすると、全ての要素に対してその計算が適用されます。
コード:配列全体に計算を適用
import numpy as np
# 商品の価格データ
prices = np.array([100, 200, 300, 400, 500])
print(f"元の価格: {prices}")
print()
print(f"2倍: {prices * 2}")
print(f"100円引き: {prices - 100}")
print(f"消費税10%込み: {prices * 1.1}")
print(f"半額: {prices / 2}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
元の価格: [100 200 300 400 500] 2倍: [ 200 400 600 800 1000] 100円引き: [ 0 100 200 300 400] 消費税10%込み: [110. 220. 330. 440. 550.] 半額: [ 50. 100. 150. 200. 250.]
💡 これがNumPyの威力!
普通のリストで同じことをしようとすると、forループが必要です:
result = [p * 2 for p in prices] # リストの場合
NumPyなら prices * 2 の1行で済みます!
しかも、NumPyの方が何十倍も速いのです。
📌 ベクトル化(Vectorization)
全ての要素に一度に計算を適用することをベクトル化といいます。
ループを書く必要がなく、高速で読みやすいコードになります!
📘 配列同士の演算
同じサイズの配列同士を計算すると、対応する位置の要素同士が計算されます。
コード:配列同士の計算
import numpy as np
# 先週と今週の売上(万円)
last_week = np.array([120, 135, 150, 145, 160, 175, 180])
this_week = np.array([125, 140, 155, 150, 165, 180, 185])
print(f"先週の売上: {last_week}")
print(f"今週の売上: {this_week}")
print()
# 増減額(今週 - 先週)
increase = this_week - last_week
print(f"増減額: {increase}")
# 増加率(%)
increase_rate = (this_week - last_week) / last_week * 100
print(f"増加率: {increase_rate}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
先週の売上: [120 135 150 145 160 175 180] 今週の売上: [125 140 155 150 165 180 185] 増減額: [5 5 5 5 5 5 5] 増加率: [4.16666667 3.7037037 3.33333333 3.44827586 3.125 2.85714286 2.77777778]
💡 配列同士の計算の仕組み
先週: [120, 135, 150, …]
今週: [125, 140, 155, …]
増減: [125-120, 140-135, 155-150, …] = [5, 5, 5, …]
同じ位置の要素同士が計算されます。
📘 複数の演算を組み合わせる
複数の計算を組み合わせて、複雑な計算も簡単にできます。
コード:売上分析の計算
import numpy as np
# 商品の原価
cost = np.array([800, 1200, 1500, 2000])
# ステップ1: 利益率30%で販売価格を計算
selling_price = cost * 1.3
print(f"原価: {cost}円")
print(f"販売価格(利益率30%): {selling_price}円")
# ステップ2: 消費税10%を加える
final_price = selling_price * 1.1
print(f"税込価格: {final_price}円")
# ステップ3: 利益を計算
profit = final_price - cost
print(f"利益: {profit}円")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
原価: [ 800 1200 1500 2000]円 販売価格(利益率30%): [1040. 1560. 1950. 2600.]円 税込価格: [1144. 1716. 2145. 2860.]円 利益: [ 344. 516. 645. 860.]円
📡 2. ブロードキャスト
ブロードキャストは、NumPyの強力な機能の一つです。形の違う配列同士でも計算できるようになります。
🔰 ブロードキャストとは?
配列と1つの数値を計算したとき、NumPyは自動的にその数値を配列と同じ形に「拡張」して計算します。これがブロードキャストです。
コード:ブロードキャストの基本
import numpy as np
arr = np.array([1, 2, 3])
# 10を足す → 10が自動的に[10, 10, 10]に拡張される
result = arr + 10
print(f"配列: {arr}")
print(f"配列 + 10: {result}")
print()
print("内部的には: [1, 2, 3] + [10, 10, 10] = [11, 12, 13]")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
配列: [1 2 3] 配列 + 10: [11 12 13] 内部的には: [1, 2, 3] + [10, 10, 10] = [11, 12, 13]
💡 ブロードキャストのイメージ
「10」という1つの値が、配列と同じサイズに「コピー」されるイメージです。
ただし、実際にはコピーされず、効率的に計算されます。
📘 2次元配列でのブロードキャスト
コード:2次元配列に数値を足す
import numpy as np
# 3人×3科目の点数
scores = np.array([
[80, 75, 90],
[85, 92, 88],
[78, 82, 85]
])
print("元の点数:")
print(scores)
# 全員に5点加点(ブロードキャスト)
adjusted = scores + 5
print("\n5点加点後:")
print(adjusted)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
元の点数: [[80 75 90] [85 92 88] [78 82 85]] 5点加点後: [[85 80 95] [90 97 93] [83 87 90]]
📘 行ごと・列ごとに異なる計算
ブロードキャストを使うと、行ごとや列ごとに異なる値を適用することもできます。
コード:行ごとに異なる係数をかける
import numpy as np
# 3店舗×4日間の売上
sales = np.array([
[100, 120, 130, 140], # 店舗A
[110, 125, 135, 145], # 店舗B
[105, 115, 125, 135] # 店舗C
])
print("元の売上:")
print(sales)
# 各店舗に異なる係数をかける
# 店舗A: 1.1倍, 店舗B: 1.0倍, 店舗C: 1.2倍
coefficients = np.array([[1.1], [1.0], [1.2]])
adjusted_sales = sales * coefficients
print("\n調整後の売上:")
print(adjusted_sales)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
元の売上: [[100 120 130 140] [110 125 135 145] [105 115 125 135]] 調整後の売上: [[110. 132. 143. 154. ] [110. 125. 135. 145. ] [126. 138. 150. 162. ]]
💡 コードの解説
coefficients = np.array([[1.1], [1.0], [1.2]])
・3行1列の配列を作成
・これが各行(店舗)に適用される係数
sales * coefficients
・ブロードキャストにより、各行に対応する係数がかけられる
・店舗Aの全データに1.1、店舗Bに1.0、店舗Cに1.2
📌 ブロードキャストの利点
| 利点 | 説明 |
| メモリ効率 | 配列を実際にコピーしないので省メモリ |
| コードが簡潔 | ループを書く必要がない |
| 高速 | NumPy内部で最適化された計算 |
🔍 3. 条件抽出
NumPyでは、条件に合うデータだけを取り出すことが簡単にできます。
🔰 条件に合う要素を抽出
配列に条件式を適用すると、条件に合う要素だけを取り出せます。
📝 書き方:条件抽出
配列[条件式]
例:scores[scores >= 80] → 80以上の要素だけを抽出
コード:条件に合う要素を抽出
import numpy as np
scores = np.array([95, 72, 88, 91, 65, 78, 85, 92, 70, 87])
print(f"全ての点数: {scores}")
print()
# 80点以上を抽出
high_scores = scores[scores >= 80]
print(f"80点以上: {high_scores}")
# 70点未満を抽出
low_scores = scores[scores < 70]
print(f"70点未満: {low_scores}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
全ての点数: [95 72 88 91 65 78 85 92 70 87] 80点以上: [95 88 91 85 92 87] 70点未満: [65]
💡 条件抽出の仕組み
ステップ1:条件式が評価される
scores >= 80 → [True, False, True, True, False, ...]
ステップ2:Trueの位置の要素だけが抽出される
scores[True, False, ...] → [95, 88, 91, ...]
📘 複数条件での抽出
複数の条件を組み合わせることもできます。
📌 論理演算子
| 演算子 | 意味 | 例 |
| & | AND(かつ) | (arr >= 80) & (arr < 90) |
| | | OR(または) | (arr < 60) | (arr >= 90) |
| ~ | NOT(否定) | ~(arr >= 80) |
重要:各条件は必ずカッコ()で囲んでください!
コード:複数条件での抽出
import numpy as np
scores = np.array([95, 72, 88, 91, 65, 78, 85, 92, 70, 87])
print(f"全ての点数: {scores}")
print()
# 80点以上90点未満(AND条件)
mid_scores = scores[(scores >= 80) & (scores < 90)]
print(f"80点以上90点未満: {mid_scores}")
# 70点未満または90点以上(OR条件)
extreme_scores = scores[(scores < 70) | (scores >= 90)]
print(f"70点未満または90点以上: {extreme_scores}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
全ての点数: [95 72 88 91 65 78 85 92 70 87] 80点以上90点未満: [88 85 87] 70点未満または90点以上: [95 91 65 92]
⚠️ よくある間違い
❌ 間違い:scores >= 80 and scores < 90
→ Pythonの「and」は配列には使えません
✅ 正解:(scores >= 80) & (scores < 90)
→ NumPyの「&」を使い、条件はカッコで囲む
📘 np.where()で条件分岐
np.where()は、条件によって異なる値を返す関数です。Excelの「IF関数」に似ています。
📝 書き方:np.where()
np.where(条件, Trueの時の値, Falseの時の値)
条件がTrueなら2番目の値、Falseなら3番目の値が入ります。
コード:np.where()で合格/不合格を判定
import numpy as np
scores = np.array([95, 72, 88, 91, 65, 78, 85])
# 80点以上なら"合格"、未満なら"不合格"
result = np.where(scores >= 80, "合格", "不合格")
print(f"点数: {scores}")
print(f"結果: {result}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
点数: [95 72 88 91 65 78 85] 結果: ['合格' '不合格' '合格' '合格' '不合格' '不合格' '合格']
コード:数値を条件で置き換える
import numpy as np
scores = np.array([95, 72, 88, 91, 65, 78, 85])
# 80点未満は0に置き換え
adjusted = np.where(scores >= 80, scores, 0)
print(f"元の点数: {scores}")
print(f"80点未満を0に: {adjusted}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
元の点数: [95 72 88 91 65 78 85] 80点未満を0に: [95 0 88 91 0 0 85]
📘 複数条件での分類(成績のランク分け)
np.where()を入れ子にすると、複数の条件で分類できます。
コード:成績をランク分け
import numpy as np
scores = np.array([95, 72, 88, 91, 65, 78, 85, 50, 92, 70])
# 成績を分類
# 90点以上: A、80点以上: B、70点以上: C、60点以上: D、それ以外: F
grade = np.where(scores >= 90, "A",
np.where(scores >= 80, "B",
np.where(scores >= 70, "C",
np.where(scores >= 60, "D", "F"))))
print(f"点数: {scores}")
print(f"成績: {grade}")
# 集計
print("\n成績別人数:")
for g in ["A", "B", "C", "D", "F"]:
count = np.count_nonzero(grade == g)
print(f" {g}: {count}人")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
点数: [95 72 88 91 65 78 85 50 92 70] 成績: ['A' 'C' 'B' 'A' 'D' 'C' 'B' 'F' 'A' 'C'] 成績別人数: A: 3人 B: 2人 C: 3人 D: 1人 F: 1人
🧮 4. 便利な数学関数
NumPyには、データ分析で便利な数学関数がたくさん用意されています。
📘 絶対値・平方根・累乗
コード:基本的な数学関数
import numpy as np
numbers = np.array([-5, -3, 0, 3, 5])
print(f"元の数値: {numbers}")
print(f"絶対値 np.abs(): {np.abs(numbers)}")
print(f"2乗 np.square(): {np.square(numbers)}")
print(f"3乗 np.power(x, 3): {np.power(numbers, 3)}")
# 平方根は正の数のみ
positive = np.array([1, 4, 9, 16, 25])
print(f"\n平方根 np.sqrt(): {np.sqrt(positive)}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
元の数値: [-5 -3 0 3 5] 絶対値 np.abs(): [5 3 0 3 5] 2乗 np.square(): [25 9 0 9 25] 3乗 np.power(x, 3): [-125 -27 0 27 125] 平方根 np.sqrt(): [1. 2. 3. 4. 5.]
📘 四捨五入・切り上げ・切り捨て
コード:丸め関数
import numpy as np
prices = np.array([1234.5, 5678.9, 9012.3, 3456.7])
print(f"元の価格: {prices}")
print()
print(f"四捨五入 np.round(): {np.round(prices)}")
print(f"切り上げ np.ceil(): {np.ceil(prices)}")
print(f"切り捨て np.floor(): {np.floor(prices)}")
# 小数第1位で四捨五入
values = np.array([1.234, 5.678, 9.012])
print(f"\n小数第1位で四捨五入: {np.round(values, 1)}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
元の価格: [1234.5 5678.9 9012.3 3456.7] 四捨五入 np.round(): [1234. 5679. 9012. 3457.] 切り上げ np.ceil(): [1235. 5679. 9013. 3457.] 切り捨て np.floor(): [1234. 5678. 9012. 3456.] 小数第1位で四捨五入: [1.2 5.7 9. ]
📘 対数・指数関数
データ分析では、対数変換や指数関数もよく使います。
コード:対数と指数
import numpy as np
numbers = np.array([1, 10, 100, 1000])
print(f"元の数値: {numbers}")
print(f"自然対数 np.log(): {np.log(numbers)}")
print(f"常用対数 np.log10(): {np.log10(numbers)}")
# 指数関数
exponents = np.array([0, 1, 2, 3])
print(f"\ne^x np.exp(): {np.exp(exponents)}")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
元の数値: [ 1 10 100 1000] 自然対数 np.log(): [0. 2.30258509 4.60517019 6.90775528] 常用対数 np.log10(): [0. 1. 2. 3.] e^x np.exp(): [ 1. 2.71828183 7.3890561 20.08553692]
💡 対数の使いどころ
np.log10()(常用対数)
・桁数が大きく違うデータを扱いやすくする
・10→1、100→2、1000→3 と変換される
np.log()(自然対数)
・成長率の計算などで使用
・機械学習でもよく使われる
📌 よく使う数学関数一覧
| 関数 | 説明 | 例 |
| np.abs() | 絶対値 | np.abs(-5) → 5 |
| np.sqrt() | 平方根 | np.sqrt(16) → 4 |
| np.square() | 2乗 | np.square(3) → 9 |
| np.round() | 四捨五入 | np.round(3.6) → 4 |
| np.ceil() | 切り上げ | np.ceil(3.1) → 4 |
| np.floor() | 切り捨て | np.floor(3.9) → 3 |
| np.log() | 自然対数 | np.log(e) → 1 |
| np.log10() | 常用対数 | np.log10(100) → 2 |
| np.exp() | 指数関数(e^x) | np.exp(1) → 2.718 |
📊 5. 実践:売上データの計算
📘 例1:月別売上分析
コード:年間売上を分析する
import numpy as np
# 月別売上(万円)
monthly_sales = np.array([120, 135, 150, 145, 160, 175, 180, 190, 185, 170, 160, 200])
months = ['1月', '2月', '3月', '4月', '5月', '6月',
'7月', '8月', '9月', '10月', '11月', '12月']
print("📊 年間売上分析")
print("=" * 50)
# 基本統計
print(f"年間合計: {np.sum(monthly_sales)}万円")
print(f"月平均: {np.mean(monthly_sales):.1f}万円")
max_idx = np.argmax(monthly_sales)
min_idx = np.argmin(monthly_sales)
print(f"最高売上: {months[max_idx]} {np.max(monthly_sales)}万円")
print(f"最低売上: {months[min_idx]} {np.min(monthly_sales)}万円")
# 目標達成率(目標150万円)
target = 150
achieved = np.count_nonzero(monthly_sales >= target)
print(f"\n目標{target}万円達成: {achieved}ヶ月 / 12ヶ月")
# 前月比成長
growth = monthly_sales[1:] - monthly_sales[:-1]
print(f"前月比平均: {np.mean(growth):+.1f}万円")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
📊 年間売上分析 ================================================== 年間合計: 1970万円 月平均: 164.2万円 最高売上: 12月 200万円 最低売上: 1月 120万円 目標150万円達成: 9ヶ月 / 12ヶ月 前月比平均: +6.4万円
💡 コードの解説
monthly_sales[1:] - monthly_sales[:-1]
・monthly_sales[1:] → 2月〜12月のデータ
・monthly_sales[:-1] → 1月〜11月のデータ
・引き算 → 各月の前月比が計算される
📘 例2:商品別売上の分析
コード:商品の売上構成比を分析
import numpy as np
# 商品データ
products = ['商品A', '商品B', '商品C', '商品D', '商品E']
quantities = np.array([150, 200, 120, 180, 90]) # 販売数
unit_prices = np.array([1000, 1500, 2000, 1200, 3000]) # 単価
# 売上を計算(販売数 × 単価)
sales = quantities * unit_prices
print("📦 商品別売上分析")
print("=" * 60)
# 各商品の情報を表示
for product, qty, price, sale in zip(products, quantities, unit_prices, sales):
print(f"{product}: {qty:>4}個 × {price:>5}円 = {sale:>8}円")
print("-" * 60)
print(f"合計: {np.sum(quantities):>4}個 {np.sum(sales):>8}円")
# 売上構成比
sales_ratio = sales / np.sum(sales) * 100
print("\n売上構成比:")
for product, ratio in zip(products, sales_ratio):
print(f" {product}: {ratio:.1f}%")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
📦 商品別売上分析 ============================================================ 商品A: 150個 × 1000円 = 150000円 商品B: 200個 × 1500円 = 300000円 商品C: 120個 × 2000円 = 240000円 商品D: 180個 × 1200円 = 216000円 商品E: 90個 × 3000円 = 270000円 ------------------------------------------------------------ 合計: 740個 1176000円 売上構成比: 商品A: 12.8% 商品B: 25.5% 商品C: 20.4% 商品D: 18.4% 商品E: 23.0%
📘 例3:複数店舗の売上比較
コード:店舗別・日別の売上分析
import numpy as np
# 3店舗×7日間の売上(千円)
sales = np.array([
[50, 62, 58, 71, 65, 88, 92], # 店舗A
[45, 55, 60, 68, 70, 85, 90], # 店舗B
[52, 58, 55, 65, 68, 82, 88] # 店舗C
])
stores = ['店舗A', '店舗B', '店舗C']
days = ['月', '火', '水', '木', '金', '土', '日']
print("🏪 店舗別売上分析(単位:千円)")
print("=" * 60)
# 店舗別サマリー
print("店舗別サマリー:")
for i, store in enumerate(stores):
total = np.sum(sales[i])
avg = np.mean(sales[i])
max_day = days[np.argmax(sales[i])]
print(f" {store}: 合計{total}千円、平均{avg:.1f}千円、最高{max_day}曜日")
# 日別合計(全店舗)
daily_total = np.sum(sales, axis=0)
print("\n日別合計(全店舗):")
for day, total in zip(days, daily_total):
print(f" {day}曜日: {total}千円")
print(f"\n週間合計: {np.sum(sales)}千円")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
🏪 店舗別売上分析(単位:千円) ============================================================ 店舗別サマリー: 店舗A: 合計486千円、平均69.4千円、最高日曜日 店舗B: 合計473千円、平均67.6千円、最高日曜日 店舗C: 合計468千円、平均66.9千円、最高日曜日 日別合計(全店舗): 月曜日: 147千円 火曜日: 175千円 水曜日: 173千円 木曜日: 204千円 金曜日: 203千円 土曜日: 255千円 日曜日: 270千円 週間合計: 1427千円
📝 練習問題
ここまで学んだことを、実際に手を動かして確認しましょう。
問題1:配列の四則演算(初級)
📋 問題
以下の配列の全ての要素に対して、以下の計算を行ってください:
1. 全ての要素に10を足す
2. 全ての要素を2倍にする
3. 全ての要素を1.5で割る
data = [20, 40, 60, 80, 100]
解答例を見る
コード
import numpy as np
data = np.array([20, 40, 60, 80, 100])
print(f"元のデータ: {data}")
print()
print(f"10を足す: {data + 10}")
print(f"2倍: {data * 2}")
print(f"1.5で割る: {data / 1.5}")
実行結果
元のデータ: [ 20 40 60 80 100] 10を足す: [ 30 50 70 90 110] 2倍: [ 40 80 120 160 200] 1.5で割る: [13.33333333 26.66666667 40. 53.33333333 66.66666667]
問題2:条件抽出(初級)
📋 問題
以下の点数データから、60点以上の点数だけを抽出してください。また、その個数も表示してください。
scores = [85, 55, 72, 48, 91, 63, 77, 58, 89, 51]
解答例を見る
コード
import numpy as np
scores = np.array([85, 55, 72, 48, 91, 63, 77, 58, 89, 51])
# 60点以上を抽出
passing = scores[scores >= 60]
print(f"全ての点数: {scores}")
print(f"60点以上: {passing}")
print(f"合格者数: {len(passing)}人")
print(f"合格率: {len(passing) / len(scores) * 100:.0f}%")
実行結果
全ての点数: [85 55 72 48 91 63 77 58 89 51] 60点以上: [85 72 91 63 77 89] 合格者数: 6人 合格率: 60%
問題3:配列同士の計算(中級)
📋 問題
先週と今週の売上データがあります。以下を計算してください:
1. 各日の売上増減額
2. 各日の増減率(%)
3. 最も増加した曜日
先週 = [100, 110, 105, 120, 115, 140, 150]
今週 = [105, 115, 110, 130, 125, 150, 160]
解答例を見る
コード
import numpy as np
last_week = np.array([100, 110, 105, 120, 115, 140, 150])
this_week = np.array([105, 115, 110, 130, 125, 150, 160])
days = ['月', '火', '水', '木', '金', '土', '日']
# 増減額
increase = this_week - last_week
print(f"増減額: {increase}")
# 増減率
rate = (this_week - last_week) / last_week * 100
print(f"増減率(%): {np.round(rate, 1)}")
# 最も増加した曜日
max_idx = np.argmax(increase)
print(f"\n最も増加: {days[max_idx]}曜日(+{increase[max_idx]}万円、+{rate[max_idx]:.1f}%)")
実行結果
増減額: [ 5 5 5 10 10 10 10] 増減率(%): [5. 4.5 4.8 8.3 8.7 7.1 6.7] 最も増加: 木曜日(+10万円、+8.3%)
問題4:np.where()を使った条件分岐(中級)
📋 問題
気温データがあります。20℃以上なら「暖かい」、20℃未満なら「寒い」という配列を作成してください。
temperatures = [18, 22, 19, 25, 17, 23, 21, 16, 24, 20]
解答例を見る
コード
import numpy as np
temperatures = np.array([18, 22, 19, 25, 17, 23, 21, 16, 24, 20])
# 条件分岐
weather = np.where(temperatures >= 20, "暖かい", "寒い")
print(f"気温: {temperatures}")
print(f"判定: {weather}")
# 集計
warm_days = np.count_nonzero(weather == "暖かい")
cold_days = np.count_nonzero(weather == "寒い")
print(f"\n暖かい日: {warm_days}日")
print(f"寒い日: {cold_days}日")
実行結果
気温: [18 22 19 25 17 23 21 16 24 20] 判定: ['寒い' '暖かい' '寒い' '暖かい' '寒い' '暖かい' '暖かい' '寒い' '暖かい' '暖かい'] 暖かい日: 6日 寒い日: 4日
問題5:商品売上の分析(上級)
📋 問題
5商品の販売数と単価があります。以下を計算してください:
1. 各商品の売上
2. 売上合計
3. 売上が最も高い商品
4. 売上構成比(%)
販売数 = [120, 80, 150, 60, 100]
単価 = [500, 800, 400, 1200, 600]
解答例を見る
コード
import numpy as np
quantities = np.array([120, 80, 150, 60, 100])
prices = np.array([500, 800, 400, 1200, 600])
products = ['商品A', '商品B', '商品C', '商品D', '商品E']
# 売上計算
sales = quantities * prices
print("商品別売上:")
for product, sale in zip(products, sales):
print(f" {product}: {sale:,}円")
# 売上合計
total = np.sum(sales)
print(f"\n売上合計: {total:,}円")
# 最高売上商品
max_idx = np.argmax(sales)
print(f"最高売上: {products[max_idx]}({sales[max_idx]:,}円)")
# 構成比
ratio = sales / total * 100
print("\n売上構成比:")
for product, r in zip(products, ratio):
print(f" {product}: {r:.1f}%")
実行結果
商品別売上: 商品A: 60,000円 商品B: 64,000円 商品C: 60,000円 商品D: 72,000円 商品E: 60,000円 売上合計: 316,000円 最高売上: 商品D(72,000円) 売上構成比: 商品A: 19.0% 商品B: 20.3% 商品C: 19.0% 商品D: 22.8% 商品E: 19.0%
問題6:複雑な条件分岐と集計(上級)
📋 問題
テスト点数があります。以下の基準でランク分けし、各ランクの人数を集計してください:
・90点以上: S ・80点以上90点未満: A ・70点以上80点未満: B
・60点以上70点未満: C ・60点未満: D
scores = [95, 72, 88, 91, 65, 78, 85, 55, 92, 70, 83, 58, 87, 76, 90]
解答例を見る
コード
import numpy as np
scores = np.array([95, 72, 88, 91, 65, 78, 85, 55, 92, 70, 83, 58, 87, 76, 90])
# ランク分け
ranks = np.where(scores >= 90, "S",
np.where(scores >= 80, "A",
np.where(scores >= 70, "B",
np.where(scores >= 60, "C", "D"))))
print(f"点数: {scores}")
print(f"ランク: {ranks}")
# 集計
print("\nランク別集計:")
for rank in ["S", "A", "B", "C", "D"]:
count = np.count_nonzero(ranks == rank)
percentage = count / len(scores) * 100
print(f" {rank}: {count}人({percentage:.1f}%)")
実行結果
点数: [95 72 88 91 65 78 85 55 92 70 83 58 87 76 90] ランク: ['S' 'B' 'A' 'S' 'C' 'B' 'A' 'D' 'S' 'B' 'A' 'D' 'A' 'B' 'S'] ランク別集計: S: 4人(26.7%) A: 4人(26.7%) B: 4人(26.7%) C: 1人(6.7%) D: 2人(13.3%)
🎯 このステップのまとめ
✅ 学んだこと
✓ 配列全体に一度に計算を適用できる(ベクトル化)
✓ ブロードキャストで形の違う配列同士も計算できる
✓ 条件式(配列[条件])で簡単にデータを抽出できる
✓ np.where()で条件分岐ができる
✓ 論理演算子(&, |, ~)で複雑な条件も表現できる
✓ 様々な数学関数(abs, sqrt, round等)が使える
💡 NumPy完了!次はPandasへ
これでNumPyの基礎は完了です!以下ができるようになったはずです:
□ 配列全体に計算を適用できる
□ 条件式でデータを抽出できる
□ np.where()を使った条件分岐ができる
□ 実際のデータ分析に応用できる
次のステップからはPandasを学びます。NumPyの上に構築されたPandasは、さらに強力なデータ分析ツールです!
❓ よくある質問
Q1: ベクトル化はなぜ速いのですか?
A: NumPyは内部でC言語を使っており、ループを使わずに一度に全ての計算を行います。Pythonのforループより圧倒的に高速で、大量のデータでは10倍〜100倍の速度差が出ることもあります。
Q2: ブロードキャストはどんな時に使いますか?
A: 全ての要素に同じ値を適用したい時に便利です。例えば、全商品に10%値上げ、全生徒に5点加点などです。
Q3: 条件抽出で&とandの違いは?
A: NumPy配列では&を使います。andはPythonの論理演算子で、配列には使えません。また、条件は必ずカッコ()で囲む必要があります。
Q4: np.where()はいつ使いますか?
A: 条件によって異なる値を設定したい時に使います。ExcelのIF関数のようなものです。
Q5: 元の配列を変更せずに計算するには?
A: copy()メソッドを使ってコピーを作成してから操作します。new_arr = arr.copy()。これをしないと、元の配列も変更されてしまうことがあります。
学習メモ
Pythonデータ分析入門 - Step 21