📋 このステップで学ぶこと
- データ品質チェックの重要性と6つの品質側面
- スキーマ検証(データ型、カラム存在チェック)
- 範囲チェック、NULLチェック、重複チェック
- 再利用可能な検証関数の作成
- Great Expectations入門
- 実践演習:データ品質レポート作成
⏱️ 学習時間の目安:2時間
📝 練習問題:10問(基礎4問・応用4問・発展2問)
🎯 1. データ品質チェックの重要性
1-1. なぜデータ検証が必要なのか?
データ検証(Validation)とは、データが正しいかどうかをチェックすることです。
ETLパイプラインでは、「Garbage In, Garbage Out(ゴミを入れればゴミが出る)」という言葉があるように、不正なデータが入ると、出力も信頼できなくなります。
📚 例え話:食材の検品
レストランで料理を作る前に、食材の品質をチェックしますよね。
・野菜は新鮮か?(適時性)
・賞味期限は切れていないか?(妥当性)
・傷んでいないか?(正確性)
・注文した食材が全部揃っているか?(完全性)
データも同じように、使う前に品質チェックが必要です!
⚠️ データ品質が悪いと…
- 間違った分析結果:売上が実際より高く/低く見えてしまう
- ビジネス判断ミス:誤ったデータに基づいて意思決定
- システムエラー:予期しないNULLや型不一致で処理が止まる
- 顧客への影響:誤った請求や配送先ミスなど
1-2. データ品質の6つの側面
データ品質の6つの側面
| 品質項目 |
説明 |
チェック例 |
| 完全性 |
必要なデータがすべて揃っているか |
必須カラムにNULLがないか、レコード数が期待通りか |
| 正確性 |
データが正しい値か |
計算結果が正しいか、入力ミスがないか |
| 一貫性 |
データ形式が統一されているか |
日付形式が統一されているか、コード体系が一致するか |
| 適時性 |
データが最新か |
更新日時が期待範囲内か、古すぎるデータがないか |
| 妥当性 |
データが妥当な範囲内か |
年齢が0〜120の範囲か、価格が正の値か |
| 一意性 |
重複データがないか |
主キーが一意か、同じレコードが複数ないか |
📋 2. スキーマ検証
2-1. スキーマとは?
スキーマ(Schema)とは、データの構造定義です。
「どんなカラムがあって、どんなデータ型か」を定義します。
📝 スキーマで定義する項目
- カラム名:どんなカラムが必要か
- データ型:int64、float64、object(文字列)など
- NULL許容:欠損値を許可するか
- 制約:一意性、外部キーなど
2-2. 基本的なスキーマチェック
# ===== データ型のチェック =====
import pandas as pd
df = pd.DataFrame({
‘user_id’: [1, 2, 3],
‘name’: [‘山田’, ‘佐藤’, ‘鈴木’],
‘age’: [25, 30, 28],
‘email’: [‘yamada@ex.com’, ‘sato@ex.com’, ‘suzuki@ex.com’]
})
# 期待されるスキーマ
expected_schema = {
‘user_id’: ‘int64’,
‘name’: ‘object’,
‘age’: ‘int64’,
‘email’: ‘object’
}
print(“=== 現在のスキーマ ===”)
print(df.dtypes)
print(“\n=== スキーマ検証 ===”)
for col, expected_dtype in expected_schema.items():
if col not in df.columns:
print(f”❌ カラム ‘{col}’ が存在しません”)
elif str(df[col].dtype) != expected_dtype:
print(f”❌ カラム ‘{col}’ の型が違います: {df[col].dtype} (期待: {expected_dtype})”)
else:
print(f”✅ カラム ‘{col}’ OK ({expected_dtype})”)
【実行結果】
=== 現在のスキーマ ===
user_id int64
name object
age int64
email object
dtype: object
=== スキーマ検証 ===
✅ カラム ‘user_id’ OK (int64)
✅ カラム ‘name’ OK (object)
✅ カラム ‘age’ OK (int64)
✅ カラム ‘email’ OK (object)
2-3. 必須カラムの存在チェック
# ===== 必須カラムの確認 =====
import pandas as pd
df = pd.DataFrame({
‘user_id’: [1, 2, 3],
‘name’: [‘山田’, ‘佐藤’, ‘鈴木’]
# emailとageがない!
})
# 必須カラムのリスト
required_columns = [‘user_id’, ‘name’, ‘email’, ‘age’]
print(“=== 必須カラムチェック ===”)
missing_columns = []
for col in required_columns:
if col in df.columns:
print(f”✅ ‘{col}’ 存在”)
else:
print(f”❌ ‘{col}’ 不足”)
missing_columns.append(col)
if missing_columns:
print(f”\n⚠️ 不足カラム: {missing_columns}”)
else:
print(“\n✅ すべての必須カラムが存在します”)
【実行結果】
=== 必須カラムチェック ===
✅ ‘user_id’ 存在
✅ ‘name’ 存在
❌ ‘email’ 不足
❌ ‘age’ 不足
⚠️ 不足カラム: [‘email’, ‘age’]
2-4. 再利用可能なスキーマ検証関数
# ===== 再利用可能な検証関数 =====
import pandas as pd
def validate_schema(df, schema):
“””
DataFrameのスキーマを検証
Args:
df: 検証するDataFrame
schema: 期待されるスキーマ(辞書: {カラム名: データ型})
Returns:
tuple: (成功フラグ, エラーリスト)
“””
errors = []
# カラムの存在チェック
for col in schema.keys():
if col not in df.columns:
errors.append(f”カラム ‘{col}’ が存在しません”)
# データ型チェック
for col, expected_dtype in schema.items():
if col in df.columns:
actual_dtype = str(df[col].dtype)
if actual_dtype != expected_dtype:
errors.append(
f”カラム ‘{col}’ の型が違います: ”
f”{actual_dtype} (期待: {expected_dtype})”
)
# 余分なカラムの警告(エラーではない)
extra_cols = set(df.columns) – set(schema.keys())
if extra_cols:
print(f”ℹ️ 追加カラム(スキーマ外): {extra_cols}”)
# 結果
if errors:
print(“❌ スキーマ検証失敗:”)
for error in errors:
print(f” – {error}”)
return False, errors
else:
print(“✅ スキーマ検証成功”)
return True, []
# ===== 使用例 =====
df = pd.DataFrame({
‘user_id’: [1, 2, 3],
‘name’: [‘山田’, ‘佐藤’, ‘鈴木’],
‘age’: [25, 30, 28],
‘extra_col’: [‘x’, ‘y’, ‘z’] # スキーマ外のカラム
})
schema = {
‘user_id’: ‘int64’,
‘name’: ‘object’,
‘age’: ‘int64’,
‘email’: ‘object’ # dfに存在しない
}
success, errors = validate_schema(df, schema)
【実行結果】
ℹ️ 追加カラム(スキーマ外): {‘extra_col’}
❌ スキーマ検証失敗:
– カラム ‘email’ が存在しません
🔍 3. 範囲チェック・NULLチェック・重複チェック
3-1. 範囲チェック
# ===== 値が妥当な範囲内かチェック =====
import pandas as pd
df = pd.DataFrame({
‘user_id’: [1, 2, 3, 4, 5],
‘age’: [25, 30, -5, 150, 28], # -5と150は異常
‘price’: [1000, 1500, 0, 2000, -100] # 0と-100は異常
})
print(“=== 元データ ===”)
print(df)
# 年齢の範囲チェック(0〜120)
print(“\n=== 年齢の範囲チェック(0〜120)===”)
age_invalid = df[(df[‘age’] < 0) | (df['age'] > 120)]
if len(age_invalid) > 0:
print(f”❌ 範囲外のデータ: {len(age_invalid)}件”)
print(age_invalid[[‘user_id’, ‘age’]])
else:
print(“✅ すべて範囲内”)
# 価格の範囲チェック(1以上)
print(“\n=== 価格の範囲チェック(1以上)===”)
price_invalid = df[df[‘price’] < 1]
if len(price_invalid) > 0:
print(f”❌ 範囲外のデータ: {len(price_invalid)}件”)
print(price_invalid[[‘user_id’, ‘price’]])
else:
print(“✅ すべて範囲内”)
【実行結果】
=== 元データ ===
user_id age price
0 1 25 1000
1 2 30 1500
2 3 -5 0
3 4 150 2000
4 5 28 -100
=== 年齢の範囲チェック(0〜120)===
❌ 範囲外のデータ: 2件
user_id age
2 3 -5
3 4 150
=== 価格の範囲チェック(1以上)===
❌ 範囲外のデータ: 2件
user_id price
2 3 0
4 5 -100
3-2. NULLチェック(欠損値チェック)
# ===== 欠損値のチェック =====
import pandas as pd
import numpy as np
df = pd.DataFrame({
‘user_id’: [1, 2, 3, 4],
‘name’: [‘山田’, np.nan, ‘鈴木’, ‘田中’], # 1件欠損
‘email’: [‘yamada@ex.com’, ‘sato@ex.com’, None, ‘tanaka@ex.com’], # 1件欠損
‘age’: [25, 30, np.nan, np.nan] # 2件欠損
})
print(“=== 元データ ===”)
print(df)
# 必須カラムのNULLチェック
print(“\n=== 必須カラムのNULLチェック ===”)
required_columns = [‘user_id’, ‘name’, ‘email’]
for col in required_columns:
null_count = df[col].isnull().sum()
total_count = len(df)
null_pct = (null_count / total_count * 100)
if null_count > 0:
print(f”❌ ‘{col}’: {null_count}件の欠損 ({null_pct:.1f}%)”)
else:
print(f”✅ ‘{col}’: 欠損なし”)
# 全体の欠損値サマリー
print(“\n=== 全体の欠損値サマリー ===”)
null_summary = df.isnull().sum()
null_summary = null_summary[null_summary > 0]
print(null_summary)
【実行結果】
=== 元データ ===
user_id name email age
0 1 山田 yamada@ex.com 25.0
1 2 NaN sato@ex.com 30.0
2 3 鈴木 None NaN
3 4 田中 tanaka@ex.com NaN
=== 必須カラムのNULLチェック ===
✅ ‘user_id’: 欠損なし
❌ ‘name’: 1件の欠損 (25.0%)
❌ ‘email’: 1件の欠損 (25.0%)
=== 全体の欠損値サマリー ===
name 1
email 1
age 2
dtype: int64
3-3. 重複チェック
# ===== 重複データのチェック =====
import pandas as pd
df = pd.DataFrame({
‘user_id’: [1, 2, 3, 2, 4], # user_id=2が重複
‘email’: [‘a@ex.com’, ‘b@ex.com’, ‘c@ex.com’, ‘b@ex.com’, ‘d@ex.com’],
‘name’: [‘山田’, ‘佐藤’, ‘鈴木’, ‘佐藤’, ‘田中’]
})
print(“=== 元データ ===”)
print(df)
# 特定カラムの重複チェック
print(“\n=== user_idの重複チェック ===”)
dup_user_id = df[df[‘user_id’].duplicated(keep=False)]
if len(dup_user_id) > 0:
print(f”❌ 重複あり: {len(dup_user_id)}件”)
print(dup_user_id)
else:
print(“✅ 重複なし”)
# 行全体の重複チェック
print(“\n=== 行全体の重複チェック ===”)
dup_rows = df[df.duplicated(keep=False)]
if len(dup_rows) > 0:
print(f”❌ 重複行: {len(dup_rows)}件”)
print(dup_rows)
else:
print(“✅ 重複行なし”)
【実行結果】
=== 元データ ===
user_id email name
0 1 a@ex.com 山田
1 2 b@ex.com 佐藤
2 3 c@ex.com 鈴木
3 2 b@ex.com 佐藤
4 4 d@ex.com 田中
=== user_idの重複チェック ===
❌ 重複あり: 2件
user_id email name
1 2 b@ex.com 佐藤
3 2 b@ex.com 佐藤
=== 行全体の重複チェック ===
❌ 重複行: 2件
user_id email name
1 2 b@ex.com 佐藤
3 2 b@ex.com 佐藤
3-4. 包括的なデータ品質レポート関数
# ===== 包括的な品質チェック関数 =====
import pandas as pd
import numpy as np
def data_quality_report(df):
“””
DataFrameの品質レポートを生成
“””
print(“=” * 60)
print(“データ品質レポート”)
print(“=” * 60)
# 基本情報
print(f”\n【1. 基本情報】”)
print(f” 行数: {len(df):,}”)
print(f” 列数: {len(df.columns)}”)
print(f” メモリ使用量: {df.memory_usage(deep=True).sum() / 1024:.1f} KB”)
# 欠損値
print(f”\n【2. 欠損値】”)
null_counts = df.isnull().sum()
null_pct = (null_counts / len(df) * 100).round(2)
null_df = pd.DataFrame({
‘欠損数’: null_counts,
‘欠損率(%)’: null_pct
})
null_df = null_df[null_df[‘欠損数’] > 0]
if len(null_df) > 0:
print(null_df)
else:
print(” 欠損値なし ✅”)
# 重複
print(f”\n【3. 重複】”)
dup_count = df.duplicated().sum()
if dup_count > 0:
print(f” 重複行数: {dup_count} ❌”)
else:
print(f” 重複行なし ✅”)
# データ型
print(f”\n【4. データ型】”)
for col in df.columns:
print(f” {col}: {df[col].dtype}”)
# 数値カラムの統計
numeric_cols = df.select_dtypes(include=[np.number]).columns
if len(numeric_cols) > 0:
print(f”\n【5. 数値カラムの統計】”)
stats = df[numeric_cols].describe().T[[‘min’, ‘max’, ‘mean’, ‘std’]]
print(stats.round(2))
print(“\n” + “=” * 60)
# ===== 使用例 =====
df = pd.DataFrame({
‘user_id’: [1, 2, 3, 2, 4],
‘age’: [25, np.nan, 30, 28, 35],
‘price’: [1000, 1500, 2000, 1500, 2500],
‘name’: [‘山田’, ‘佐藤’, ‘鈴木’, ‘佐藤’, ‘田中’]
})
data_quality_report(df)
【実行結果】
============================================================
データ品質レポート
============================================================
【1. 基本情報】
行数: 5
列数: 4
メモリ使用量: 0.5 KB
【2. 欠損値】
欠損数 欠損率(%)
age 1 20.0
【3. 重複】
重複行数: 1 ❌
【4. データ型】
user_id: int64
age: float64
price: int64
name: object
【5. 数値カラムの統計】
min max mean std
user_id 1.0 4.0 2.40 1.14
age 25.0 35.0 29.50 4.20
price 1000.0 2500.0 1700.00 547.72
============================================================
🔧 4. Great Expectations入門
4-1. Great Expectationsとは?
Great Expectationsは、データ検証を自動化するPythonライブラリです。
100種類以上の検証ルール(Expectation)が用意されており、複雑な検証も簡単に定義できます。
💡 Great Expectationsのメリット
- 自動化:検証ルールを一度定義すれば、毎回自動実行
- ドキュメント化:検証ルールが自己文書化される
- HTMLレポート:見やすいレポートを自動生成
- CI/CD統合:パイプラインに組み込める
- 豊富な検証ルール:100種類以上のExpectation
4-2. インストールと基本的な使い方
# インストール
pip install great_expectations
# ===== Great Expectationsの基本的な使い方 =====
import pandas as pd
import great_expectations as gx
# データ作成
df = pd.DataFrame({
‘user_id’: [1, 2, 3, 4, 5],
‘age’: [25, 30, 28, 35, 40],
‘email’: [‘a@ex.com’, ‘b@ex.com’, ‘c@ex.com’, ‘d@ex.com’, ‘e@ex.com’]
})
# コンテキストを作成(一時的なもの)
context = gx.get_context()
# DataFrameをデータソースとして追加
datasource = context.sources.add_pandas(“pandas_datasource”)
data_asset = datasource.add_dataframe_asset(name=”my_data”)
batch_request = data_asset.build_batch_request(dataframe=df)
# Validatorを取得(検証器)
validator = context.get_validator(batch_request=batch_request)
# 検証ルールを定義して実行
print(“=== 検証実行 ===”)
# カラムの存在チェック
result1 = validator.expect_column_to_exist(“user_id”)
print(f”user_idが存在: {result1.success}”)
# NULL値がないことを確認
result2 = validator.expect_column_values_to_not_be_null(“user_id”)
print(f”user_idにNULLなし: {result2.success}”)
# 範囲チェック
result3 = validator.expect_column_values_to_be_between(“age”, min_value=0, max_value=120)
print(f”ageが0-120の範囲内: {result3.success}”)
# 全体の検証実行
results = validator.validate()
print(f”\n=== 総合結果 ===”)
print(f”成功: {‘✅’ if results.success else ‘❌’}”)
【実行結果】
=== 検証実行 ===
user_idが存在: True
user_idにNULLなし: True
ageが0-120の範囲内: True
=== 総合結果 ===
成功: ✅
4-3. よく使うExpectation一覧
代表的なExpectation
| Expectation |
説明 |
expect_column_to_exist |
カラムが存在することを確認 |
expect_column_values_to_not_be_null |
NULLがないことを確認 |
expect_column_values_to_be_between |
値が指定範囲内であることを確認 |
expect_column_values_to_be_unique |
値が一意であることを確認 |
expect_column_values_to_be_in_set |
値が指定した集合に含まれることを確認 |
expect_column_values_to_match_regex |
正規表現にマッチすることを確認 |
expect_column_values_to_be_of_type |
データ型が一致することを確認 |
expect_table_row_count_to_be_between |
行数が指定範囲内であることを確認 |
✅ Great Expectationsの学習ポイント
Great Expectationsは高機能ですが、学習コストも高いです。
まずは自作の検証関数で基本を理解してから、
本番環境で必要になったらGreat Expectationsを導入することをお勧めします。
🏋️ 5. 実践演習:総合的なデータ品質チェック
5-1. 課題:包括的な検証システムの構築
設定ファイルに基づいて、スキーマ・欠損値・範囲・重複のすべてをチェックする検証システムを構築します。
# ===== 完全な品質チェックシステム =====
import pandas as pd
import numpy as np
from datetime import datetime
def comprehensive_data_validation(df, config):
“””
包括的なデータ検証を実行
Args:
df: 検証するDataFrame
config: 検証設定(辞書)
– schema: {カラム名: データ型}
– required_columns: [必須カラムのリスト]
– ranges: {カラム名: (最小値, 最大値)}
– unique_columns: [一意であるべきカラムのリスト]
Returns:
dict: 検証結果
“””
results = {
‘timestamp’: datetime.now().strftime(‘%Y-%m-%d %H:%M:%S’),
‘total_rows’: len(df),
‘total_columns’: len(df.columns),
‘checks’: [],
‘passed’: 0,
‘failed’: 0
}
print(“=” * 60)
print(“データ品質検証レポート”)
print(“=” * 60)
print(f”実行日時: {results[‘timestamp’]}”)
print(f”行数: {results[‘total_rows’]:,}”)
print(f”列数: {results[‘total_columns’]}”)
# 1. スキーマチェック
print(“\n【1. スキーマチェック】”)
if ‘schema’ in config:
for col, expected_dtype in config[‘schema’].items():
if col not in df.columns:
print(f” ❌ カラム ‘{col}’ が存在しません”)
results[‘failed’] += 1
elif str(df[col].dtype) != expected_dtype:
print(f” ❌ ‘{col}’ の型: {df[col].dtype} (期待: {expected_dtype})”)
results[‘failed’] += 1
else:
print(f” ✅ ‘{col}’ OK ({expected_dtype})”)
results[‘passed’] += 1
# 2. 欠損値チェック
print(“\n【2. 欠損値チェック】”)
if ‘required_columns’ in config:
for col in config[‘required_columns’]:
if col in df.columns:
null_count = df[col].isnull().sum()
if null_count > 0:
print(f” ❌ ‘{col}’ に欠損値: {null_count}件 ({null_count/len(df)*100:.1f}%)”)
results[‘failed’] += 1
else:
print(f” ✅ ‘{col}’ 欠損値なし”)
results[‘passed’] += 1
# 3. 範囲チェック
print(“\n【3. 範囲チェック】”)
if ‘ranges’ in config:
for col, (min_val, max_val) in config[‘ranges’].items():
if col in df.columns:
invalid = df[(df[col] < min_val) | (df[col] > max_val)]
invalid_count = len(invalid)
if invalid_count > 0:
print(f” ❌ ‘{col}’ が範囲外: {invalid_count}件 ({min_val}〜{max_val})”)
results[‘failed’] += 1
else:
print(f” ✅ ‘{col}’ 範囲内 ({min_val}〜{max_val})”)
results[‘passed’] += 1
# 4. 重複チェック
print(“\n【4. 重複チェック】”)
if ‘unique_columns’ in config:
for col in config[‘unique_columns’]:
if col in df.columns:
dup_count = df[col].duplicated().sum()
if dup_count > 0:
print(f” ❌ ‘{col}’ に重複: {dup_count}件”)
results[‘failed’] += 1
else:
print(f” ✅ ‘{col}’ 重複なし”)
results[‘passed’] += 1
# サマリー
print(“\n” + “=” * 60)
print(“検証サマリー”)
print(“=” * 60)
total_checks = results[‘passed’] + results[‘failed’]
print(f”チェック総数: {total_checks}”)
print(f”成功: {results[‘passed’]} ({results[‘passed’]/total_checks*100:.0f}%)”)
print(f”失敗: {results[‘failed’]} ({results[‘failed’]/total_checks*100:.0f}%)”)
overall_success = results[‘failed’] == 0
print(f”\n総合結果: {‘✅ 合格’ if overall_success else ‘❌ 不合格’}”)
results[‘overall_success’] = overall_success
return results
# ========== 使用例 ==========
# テストデータ(意図的に問題を含む)
df = pd.DataFrame({
‘user_id’: [1, 2, 3, 2, 4], # 重複あり
‘name’: [‘山田’, np.nan, ‘鈴木’, ‘佐藤’, ‘田中’], # 欠損値あり
‘age’: [25, 30, -5, 28, 35], # 範囲外あり
‘email’: [‘a@ex.com’, ‘b@ex.com’, ‘c@ex.com’, ‘d@ex.com’, ‘e@ex.com’]
})
# 検証設定
validation_config = {
‘schema’: {
‘user_id’: ‘int64’,
‘name’: ‘object’,
‘age’: ‘int64’,
‘email’: ‘object’
},
‘required_columns’: [‘user_id’, ‘name’, ‘email’],
‘ranges’: {
‘age’: (0, 120)
},
‘unique_columns’: [‘user_id’, ‘email’]
}
# 検証実行
results = comprehensive_data_validation(df, validation_config)
【実行結果】
============================================================
データ品質検証レポート
============================================================
実行日時: 2024-01-15 10:30:45
行数: 5
列数: 4
【1. スキーマチェック】
✅ ‘user_id’ OK (int64)
✅ ‘name’ OK (object)
✅ ‘age’ OK (int64)
✅ ‘email’ OK (object)
【2. 欠損値チェック】
✅ ‘user_id’ 欠損値なし
❌ ‘name’ に欠損値: 1件 (20.0%)
✅ ‘email’ 欠損値なし
【3. 範囲チェック】
❌ ‘age’ が範囲外: 1件 (0〜120)
【4. 重複チェック】
❌ ‘user_id’ に重複: 1件
✅ ‘email’ 重複なし
============================================================
検証サマリー
============================================================
チェック総数: 10
成功: 7 (70%)
失敗: 3 (30%)
総合結果: ❌ 不合格
📝 STEP 12 のまとめ
✅ このステップで学んだこと
- データ品質の重要性:6つの品質側面(完全性・正確性・一貫性・適時性・妥当性・一意性)
- スキーマ検証:データ型、カラムの存在チェック
- 範囲チェック:値が妥当な範囲内かを確認
- NULLチェック:欠損値の検出
- 重複チェック:一意性の確認
- Great Expectations:データ検証の自動化ライブラリ
💡 データ検証のベストプラクティス
- ETLの入口で検証:データ取得直後にチェック
- ETLの出口で検証:ロード前に最終チェック
- 検証ルールを文書化:ルールを明確に定義
- エラーをログに記録:問題発生時に追跡可能に
- アラートを設定:重大な問題は即座に通知
🎯 次のステップの予告
次のSTEP 13では、「複雑なデータ変換の実践」を学びます。
- apply()、map()、applymap()の使い分け
- lambda関数の活用
- カスタム変換関数の作成
📝 練習問題
問題 1
基礎
DataFrameに’email’カラムが存在するかチェックするコードを書いてください。
【解答例】
if ‘email’ in df.columns:
print(“✅ ‘email’ カラムが存在します”)
else:
print(“❌ ‘email’ カラムが存在しません”)
問題 2
基礎
‘age’カラムに欠損値が何件あるかを確認するコードを書いてください。
【解答例】
null_count = df[‘age’].isnull().sum()
print(f”欠損値: {null_count}件”)
問題 3
基礎
‘price’カラムの値が0未満のデータを抽出してください。
【解答例】
invalid_price = df[df[‘price’] < 0]
print(invalid_price)
問題 4
基礎
‘user_id’カラムに重複があるかチェックするコードを書いてください。
【解答例】
dup_count = df[‘user_id’].duplicated().sum()
if dup_count > 0:
print(f”❌ 重複あり: {dup_count}件”)
else:
print(“✅ 重複なし”)
問題 5
応用
‘age’カラムが0〜120の範囲内かチェックし、範囲外のデータがあれば表示してください。
【解答例】
invalid_age = df[(df[‘age’] < 0) | (df['age'] > 120)]
if len(invalid_age) > 0:
print(f”❌ 範囲外のデータ: {len(invalid_age)}件”)
print(invalid_age)
else:
print(“✅ すべて範囲内”)
問題 6
応用
DataFrameのデータ型が期待通りかチェックする関数を書いてください。
【解答例】
def check_dtype(df, col, expected_dtype):
actual_dtype = str(df[col].dtype)
if actual_dtype == expected_dtype:
print(f”✅ ‘{col}’ の型は {expected_dtype} で正しい”)
return True
else:
print(f”❌ ‘{col}’ の型は {actual_dtype} (期待: {expected_dtype})”)
return False
# 使用例
check_dtype(df, ‘age’, ‘int64’)
問題 7
応用
全カラムの欠損値サマリー(カラム名、欠損数、欠損率)を表示するコードを書いてください。
【解答例】
null_counts = df.isnull().sum()
null_pct = (null_counts / len(df) * 100).round(2)
null_summary = pd.DataFrame({
‘欠損数’: null_counts,
‘欠損率(%)’: null_pct
})
print(null_summary[null_summary[‘欠損数’] > 0])
問題 8
応用
‘email’カラムがメールアドレスの形式(@を含む)かチェックするコードを書いてください。
【解答例】
# @を含まないメールアドレスを検出
invalid_email = df[~df[‘email’].str.contains(‘@’, na=False)]
if len(invalid_email) > 0:
print(f”❌ 不正なメールアドレス: {len(invalid_email)}件”)
print(invalid_email)
else:
print(“✅ すべて有効な形式”)
問題 9
発展
以下のチェックをすべて行う検証関数を作成してください:
① 必須カラムの存在チェック
② 必須カラムの欠損値チェック
③ 結果をTrue/Falseで返す
【解答例】
def validate_required_columns(df, required_columns):
“””必須カラムの存在と欠損値をチェック”””
is_valid = True
for col in required_columns:
# 存在チェック
if col not in df.columns:
print(f”❌ カラム ‘{col}’ が存在しません”)
is_valid = False
continue
# 欠損値チェック
null_count = df[col].isnull().sum()
if null_count > 0:
print(f”❌ ‘{col}’ に欠損値: {null_count}件”)
is_valid = False
else:
print(f”✅ ‘{col}’ OK”)
return is_valid
# 使用例
result = validate_required_columns(df, [‘user_id’, ‘name’, ‘email’])
問題 10
発展
以下の情報を含むデータ品質レポートを作成する関数を書いてください:
① 基本情報(行数、列数)
② 各カラムの欠損値数と欠損率
③ 重複行数
④ 数値カラムの最小値・最大値
【解答例】
def create_quality_report(df):
“””データ品質レポートを作成”””
print(“=” * 50)
print(“データ品質レポート”)
print(“=” * 50)
# ① 基本情報
print(f”\n【基本情報】”)
print(f” 行数: {len(df):,}”)
print(f” 列数: {len(df.columns)}”)
# ② 欠損値
print(f”\n【欠損値】”)
for col in df.columns:
null_count = df[col].isnull().sum()
null_pct = null_count / len(df) * 100
print(f” {col}: {null_count}件 ({null_pct:.1f}%)”)
# ③ 重複
print(f”\n【重複】”)
dup_count = df.duplicated().sum()
print(f” 重複行数: {dup_count}”)
# ④ 数値カラムの範囲
print(f”\n【数値カラムの範囲】”)
for col in df.select_dtypes(include=’number’).columns:
print(f” {col}: {df[col].min()} 〜 {df[col].max()}”)
print(“\n” + “=” * 50)
# 使用例
create_quality_report(df)