Pythonで統計値を完全マスター【平均・中央値・最頻値・分散・標準偏差】
Pythonのstatisticsモジュールを使えば、基本的な統計値を簡単かつ正確に計算できます。この記事では、平均、中央値、最頻値、分散、標準偏差の計算方法を、実践的なサンプルコードと共に詳しく解説します。
statisticsモジュールの基本
基本的な統計関数
import statistics
# サンプルデータ
data = [10, 20, 20, 10, 10, 30, 20, 20, 20, 30, 30, 30]
# 基本統計値の計算
mean_val = statistics.mean(data) # 平均
median_val = statistics.median(data) # 中央値
mode_val = statistics.mode(data) # 最頻値
variance_val = statistics.variance(data) # 分散
stdev_val = statistics.stdev(data) # 標準偏差
print(f"データ: {data}")
print(f"平均: {mean_val:.2f}")
print(f"中央値: {median_val}")
print(f"最頻値: {mode_val}")
print(f"分散: {variance_val:.2f}")
print(f"標準偏差: {stdev_val:.2f}")
平均値の計算
算術平均(mean)
import statistics
def detailed_mean_calculation(data):
"""平均値の詳細計算"""
n = len(data)
total = sum(data)
mean_manual = total / n
mean_builtin = statistics.mean(data)
print(f"データ: {data}")
print(f"要素数: {n}")
print(f"合計: {total}")
print(f"手動計算: {total}/{n} = {mean_manual:.3f}")
print(f"statistics.mean(): {mean_builtin:.3f}")
print(f"差: {abs(mean_manual - mean_builtin):.10f}")
# テストデータ
test_data = [85, 90, 78, 92, 88, 76, 95, 89]
detailed_mean_calculation(test_data)
加重平均
import statistics
def weighted_mean(values, weights):
"""加重平均の計算"""
if len(values) != len(weights):
raise ValueError("値と重みの数が一致しません")
weighted_sum = sum(v * w for v, w in zip(values, weights))
total_weight = sum(weights)
return weighted_sum / total_weight
# 例:科目別成績の加重平均(単位数で重み付け)
subjects = {
'数学': {'score': 85, 'credits': 3},
'物理': {'score': 90, 'credits': 2},
'化学': {'score': 78, 'credits': 2},
'英語': {'score': 92, 'credits': 1}
}
scores = [subject['score'] for subject in subjects.values()]
credits = [subject['credits'] for subject in subjects.values()]
simple_avg = statistics.mean(scores)
weighted_avg = weighted_mean(scores, credits)
print("科目別成績:")
for subject, data in subjects.items():
print(f" {subject}: {data['score']}点 ({data['credits']}単位)")
print(f"\n単純平均: {simple_avg:.2f}点")
print(f"加重平均: {weighted_avg:.2f}点")
幾何平均と調和平均
import statistics
def geometric_mean(data):
"""幾何平均の計算(正の値のみ)"""
if any(x <= 0 for x in data):
raise ValueError("幾何平均は正の値のみで計算できます")
product = 1
for x in data:
product *= x
return product ** (1 / len(data))
# 成長率の平均を計算する例
growth_rates = [1.05, 1.03, 1.08, 1.02, 1.06] # 各年の成長率
# Python 3.8以降では statistics.geometric_mean() が利用可能
if hasattr(statistics, 'geometric_mean'):
geo_mean_builtin = statistics.geometric_mean(growth_rates)
else:
geo_mean_builtin = "利用不可"
geo_mean_manual = geometric_mean(growth_rates)
harmonic_mean_val = statistics.harmonic_mean(growth_rates)
print(f"成長率データ: {growth_rates}")
print(f"算術平均: {statistics.mean(growth_rates):.4f}")
print(f"幾何平均: {geo_mean_manual:.4f}")
print(f"調和平均: {harmonic_mean_val:.4f}")
# 年平均成長率
annual_growth_rate = (geo_mean_manual - 1) * 100
print(f"年平均成長率: {annual_growth_rate:.2f}%")
中央値の計算
中央値の基本
import statistics
def detailed_median_calculation(data):
"""中央値の詳細計算"""
sorted_data = sorted(data)
n = len(sorted_data)
print(f"元データ: {data}")
print(f"ソート後: {sorted_data}")
print(f"要素数: {n}")
if n % 2 == 1:
# 奇数個の場合
median_index = n // 2
median_manual = sorted_data[median_index]
print(f"中央値位置: {median_index + 1}番目")
print(f"中央値: {median_manual}")
else:
# 偶数個の場合
mid1, mid2 = n // 2 - 1, n // 2
median_manual = (sorted_data[mid1] + sorted_data[mid2]) / 2
print(f"中央値位置: {mid1 + 1}番目と{mid2 + 1}番目の平均")
print(f"中央値: ({sorted_data[mid1]} + {sorted_data[mid2]}) / 2 = {median_manual}")
median_builtin = statistics.median(data)
print(f"statistics.median(): {median_builtin}")
# 奇数個のデータ
odd_data = [23, 45, 56, 78, 32]
print("=== 奇数個のデータ ===")
detailed_median_calculation(odd_data)
print("\n=== 偶数個のデータ ===")
# 偶数個のデータ
even_data = [23, 45, 56, 78, 32, 67]
detailed_median_calculation(even_data)
median_low と median_high
import statistics
# 偶数個のデータで下位・上位中央値を計算
data = [1, 3, 5, 7]
median_low = statistics.median_low(data) # 下位中央値
median_high = statistics.median_high(data) # 上位中央値
median_normal = statistics.median(data) # 通常の中央値
print(f"データ: {data}")
print(f"下位中央値: {median_low}")
print(f"上位中央値: {median_high}")
print(f"通常中央値: {median_normal}")
最頻値(Mode)の計算
単一最頻値と複数最頻値
import statistics
from collections import Counter
def analyze_mode(data):
"""最頻値の詳細分析"""
counter = Counter(data)
most_common = counter.most_common()
print(f"データ: {data}")
print(f"度数分布: {dict(counter)}")
# 最高頻度
max_count = most_common[0][1]
modes = [value for value, count in most_common if count == max_count]
print(f"最高頻度: {max_count}")
print(f"最頻値: {modes}")
try:
mode_builtin = statistics.mode(data)
print(f"statistics.mode(): {mode_builtin}")
except statistics.StatisticsError as e:
print(f"statistics.mode()エラー: {e}")
# multimode(Python 3.8+)
if hasattr(statistics, 'multimode'):
multimode_result = statistics.multimode(data)
print(f"statistics.multimode(): {multimode_result}")
# 単一最頻値
single_mode_data = [1, 2, 2, 3, 4, 2, 5]
print("=== 単一最頻値 ===")
analyze_mode(single_mode_data)
print("\n=== 複数最頻値 ===")
# 複数最頻値
multi_mode_data = [1, 1, 2, 2, 3, 4]
analyze_mode(multi_mode_data)
print("\n=== 最頻値なし(全て同じ頻度)===")
# 最頻値なし
no_mode_data = [1, 2, 3, 4, 5]
analyze_mode(no_mode_data)
分散と標準偏差
母分散と標本分散
import statistics
import math
def detailed_variance_calculation(data):
"""分散の詳細計算"""
n = len(data)
mean_val = statistics.mean(data)
print(f"データ: {data}")
print(f"平均: {mean_val:.3f}")
print(f"要素数: {n}")
# 偏差の計算
deviations = [x - mean_val for x in data]
squared_deviations = [d ** 2 for d in deviations]
print(f"偏差: {[f'{d:.3f}' for d in deviations]}")
print(f"偏差二乗: {[f'{d:.3f}' for d in squared_deviations]}")
sum_squared_deviations = sum(squared_deviations)
print(f"偏差二乗和: {sum_squared_deviations:.3f}")
# 母分散(全データが母集団)
population_var_manual = sum_squared_deviations / n
population_var_builtin = statistics.pvariance(data)
# 標本分散(サンプルデータ)
sample_var_manual = sum_squared_deviations / (n - 1)
sample_var_builtin = statistics.variance(data)
print(f"\n母分散:")
print(f" 手動計算: {sum_squared_deviations:.3f}/{n} = {population_var_manual:.3f}")
print(f" statistics.pvariance(): {population_var_builtin:.3f}")
print(f"\n標本分散:")
print(f" 手動計算: {sum_squared_deviations:.3f}/{n-1} = {sample_var_manual:.3f}")
print(f" statistics.variance(): {sample_var_builtin:.3f}")
# テストデータ
test_scores = [85, 87, 90, 92, 88, 86, 91, 89]
detailed_variance_calculation(test_scores)
標準偏差の計算
import statistics
import math
def detailed_stdev_calculation(data):
"""標準偏差の詳細計算"""
# 分散を計算
population_var = statistics.pvariance(data)
sample_var = statistics.variance(data)
# 標準偏差(分散の平方根)
population_stdev_manual = math.sqrt(population_var)
sample_stdev_manual = math.sqrt(sample_var)
population_stdev_builtin = statistics.pstdev(data)
sample_stdev_builtin = statistics.stdev(data)
print(f"データ: {data}")
print(f"平均: {statistics.mean(data):.3f}")
print(f"\n母標準偏差:")
print(f" √{population_var:.3f} = {population_stdev_manual:.3f}")
print(f" statistics.pstdev(): {population_stdev_builtin:.3f}")
print(f"\n標本標準偏差:")
print(f" √{sample_var:.3f} = {sample_stdev_manual:.3f}")
print(f" statistics.stdev(): {sample_stdev_builtin:.3f}")
# 実例:テストの点数
exam_scores = [72, 85, 91, 68, 87, 78, 94, 82, 76, 89]
detailed_stdev_calculation(exam_scores)
実践的な応用例
データの正規化(標準化)
import statistics
def standardize_data(data):
"""データの標準化(z-score)"""
mean_val = statistics.mean(data)
stdev_val = statistics.stdev(data)
standardized = [(x - mean_val) / stdev_val for x in data]
print(f"元データ: {data}")
print(f"平均: {mean_val:.3f}, 標準偏差: {stdev_val:.3f}")
print(f"標準化後: {[f'{z:.3f}' for z in standardized]}")
# 標準化データの検証
std_mean = statistics.mean(standardized)
std_stdev = statistics.stdev(standardized)
print(f"標準化後の平均: {std_mean:.6f} (≈0)")
print(f"標準化後の標準偏差: {std_stdev:.6f} (≈1)")
return standardized
# テスト点数の標準化
scores = [65, 70, 75, 80, 85, 90, 95]
z_scores = standardize_data(scores)
外れ値の検出
import statistics
def detect_outliers(data, threshold=2):
"""標準偏差を使った外れ値検出"""
mean_val = statistics.mean(data)
stdev_val = statistics.stdev(data)
outliers = []
normal_values = []
for x in data:
z_score = abs(x - mean_val) / stdev_val
if z_score > threshold:
outliers.append((x, z_score))
else:
normal_values.append(x)
print(f"データ: {data}")
print(f"平均: {mean_val:.2f}, 標準偏差: {stdev_val:.2f}")
print(f"閾値: {threshold}σ")
print(f"正常値: {normal_values}")
print(f"外れ値: {[(val, f'{z:.2f}σ') for val, z in outliers]}")
return outliers, normal_values
# 外れ値を含むデータ
data_with_outliers = [10, 12, 11, 13, 12, 11, 10, 50, 9, 11, 12]
outliers, normal = detect_outliers(data_with_outliers)
グレード分布の分析
import statistics
from collections import Counter
def grade_distribution_analysis(scores):
"""成績分布の統計分析"""
# 基本統計値
mean_score = statistics.mean(scores)
median_score = statistics.median(scores)
mode_scores = statistics.multimode(scores) if hasattr(statistics, 'multimode') else [statistics.mode(scores)]
stdev_score = statistics.stdev(scores)
print("=== 成績統計 ===")
print(f"平均点: {mean_score:.1f}点")
print(f"中央値: {median_score}点")
print(f"最頻値: {mode_scores}点")
print(f"標準偏差: {stdev_score:.1f}点")
# グレード分類
def score_to_grade(score):
if score >= 90: return 'A'
elif score >= 80: return 'B'
elif score >= 70: return 'C'
elif score >= 60: return 'D'
else: return 'F'
grades = [score_to_grade(score) for score in scores]
grade_counter = Counter(grades)
print(f"\n=== グレード分布 ===")
for grade in ['A', 'B', 'C', 'D', 'F']:
count = grade_counter[grade]
percentage = count / len(scores) * 100
print(f"{grade}グレード: {count}人 ({percentage:.1f}%)")
# 偏差値の計算
deviation_values = [50 + (score - mean_score) / stdev_score * 10 for score in scores]
print(f"\n=== 偏差値範囲 ===")
print(f"最高偏差値: {max(deviation_values):.1f}")
print(f"最低偏差値: {min(deviation_values):.1f}")
return {
'mean': mean_score,
'median': median_score,
'mode': mode_scores,
'stdev': stdev_score,
'grades': grade_counter,
'deviation_values': deviation_values
}
# クラスの成績データ
class_scores = [95, 87, 92, 78, 85, 90, 76, 88, 93, 82, 79, 86, 91, 84, 77, 89, 94, 81, 83, 80]
analysis = grade_distribution_analysis(class_scores)
時系列データの移動統計
import statistics
def moving_statistics(data, window_size=3):
"""移動統計の計算"""
moving_means = []
moving_stdevs = []
for i in range(len(data) - window_size + 1):
window_data = data[i:i + window_size]
moving_means.append(statistics.mean(window_data))
moving_stdevs.append(statistics.stdev(window_data) if len(window_data) > 1 else 0)
print(f"元データ: {data}")
print(f"ウィンドウサイズ: {window_size}")
print()
print("期間 | データ範囲 | 移動平均 | 移動標準偏差")
print("-" * 50)
for i, (mean_val, stdev_val) in enumerate(zip(moving_means, moving_stdevs)):
window_data = data[i:i + window_size]
print(f"{i+1:4} | {window_data} | {mean_val:8.2f} | {stdev_val:11.2f}")
return moving_means, moving_stdevs
# 売上データの例
monthly_sales = [120, 135, 142, 128, 156, 149, 163, 145, 138, 152, 167, 174]
moving_means, moving_stdevs = moving_statistics(monthly_sales, window_size=3)
エラーハンドリングと注意点
空データと異常値の処理
import statistics
def safe_statistics(data, name="データ"):
"""安全な統計計算"""
print(f"=== {name} ===")
if not data:
print("エラー: データが空です")
return None
try:
# 基本統計値の計算
results = {}
results['count'] = len(data)
results['mean'] = statistics.mean(data)
results['median'] = statistics.median(data)
try:
results['mode'] = statistics.mode(data)
except statistics.StatisticsError:
results['mode'] = "複数または存在しない"
if len(data) > 1:
results['variance'] = statistics.variance(data)
results['stdev'] = statistics.stdev(data)
else:
results['variance'] = 0
results['stdev'] = 0
# 結果の表示
for key, value in results.items():
if isinstance(value, float):
print(f"{key}: {value:.3f}")
else:
print(f"{key}: {value}")
return results
except Exception as e:
print(f"計算エラー: {e}")
return None
# 各種テストケース
test_cases = [
([], "空のデータ"),
([42], "単一データ"),
([1, 2, 3], "正常データ"),
([1, 1, 1], "同一値データ"),
([1, 2, 2, 3, 3], "複数最頻値データ")
]
for data, description in test_cases:
result = safe_statistics(data, description)
print()
数値精度の問題
import statistics
import decimal
def precision_comparison():
"""浮動小数点数vs高精度数での統計計算"""
# 浮動小数点数
float_data = [0.1, 0.2, 0.3, 0.4, 0.5]
# Decimal型
decimal_data = [decimal.Decimal('0.1'), decimal.Decimal('0.2'),
decimal.Decimal('0.3'), decimal.Decimal('0.4'),
decimal.Decimal('0.5')]
print("=== 精度比較 ===")
print(f"float平均: {statistics.mean(float_data)}")
print(f"Decimal平均: {statistics.mean(decimal_data)}")
# より極端な例
extreme_float = [1e-15, 1e-15, 1e-15, 1.0]
print(f"\n極端な例(float):")
print(f"データ: {extreme_float}")
print(f"合計: {sum(extreme_float)}")
print(f"平均: {statistics.mean(extreme_float)}")
precision_comparison()
パフォーマンス最適化
大量データの効率的処理
import statistics
import time
import random
def benchmark_statistics():
"""統計計算のベンチマーク"""
# 大量データの生成
large_data = [random.gauss(100, 15) for _ in range(100000)]
functions = [
('平均', statistics.mean),
('中央値', statistics.median),
('分散', statistics.variance),
('標準偏差', statistics.stdev)
]
print(f"データサイズ: {len(large_data):,}要素")
print("=" * 40)
for name, func in functions:
start_time = time.time()
result = func(large_data)
end_time = time.time()
print(f"{name:8}: {result:8.3f} ({end_time - start_time:.4f}秒)")
benchmark_statistics()
ストリーミング統計
class StreamingStatistics:
"""ストリーミング統計計算クラス"""
def __init__(self):
self.count = 0
self.sum = 0
self.sum_squares = 0
self.min_val = float('inf')
self.max_val = float('-inf')
def add_value(self, value):
"""新しい値を追加"""
self.count += 1
self.sum += value
self.sum_squares += value ** 2
self.min_val = min(self.min_val, value)
self.max_val = max(self.max_val, value)
def mean(self):
"""平均の計算"""
return self.sum / self.count if self.count > 0 else 0
def variance(self):
"""分散の計算"""
if self.count <= 1:
return 0
mean_val = self.mean()
return (self.sum_squares - self.count * mean_val ** 2) / (self.count - 1)
def stdev(self):
"""標準偏差の計算"""
return self.variance() ** 0.5
def summary(self):
"""統計サマリーの表示"""
print(f"要素数: {self.count}")
print(f"最小値: {self.min_val}")
print(f"最大値: {self.max_val}")
print(f"平均: {self.mean():.3f}")
print(f"分散: {self.variance():.3f}")
print(f"標準偏差: {self.stdev():.3f}")
# ストリーミング統計の使用例
stream_stats = StreamingStatistics()
# データを順次追加
data_stream = [23, 45, 67, 12, 89, 34, 56, 78, 90, 21]
print("=== ストリーミング統計 ===")
for i, value in enumerate(data_stream, 1):
stream_stats.add_value(value)
print(f"\n{i}個目のデータ追加後:")
if i <= 3: # 最初の3つのみ詳細表示
stream_stats.summary()
else:
print(f"平均: {stream_stats.mean():.3f}, 標準偏差: {stream_stats.stdev():.3f}")
print(f"\n=== 最終結果 ===")
stream_stats.summary()
# 検証:一括計算との比較
print(f"\n=== 検証 ===")
print(f"一括計算平均: {statistics.mean(data_stream):.3f}")
print(f"一括計算標準偏差: {statistics.stdev(data_stream):.3f}")
まとめ
Pythonの統計計算機能は以下の特徴を持ちます:
statisticsモジュールによる正確で簡単な計算- 母集団と標本の両方に対応
- 加重平均、幾何平均、調和平均のサポート
- 複数最頻値の処理
- 高精度計算とストリーミング処理への対応
これらの統計関数は、データ分析、品質管理、学術研究、ビジネス分析など、様々な分野で基礎となる重要なツールです。データの性質を理解し、適切な統計値を選択して、意味のある洞察を得ることが重要です。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座

