Python filter関数入門|条件に合う要素だけを抽出

Python filter関数の基本的な使い方を初心者向けに解説。条件関数の作成、lambda式との組み合わせ、リスト内包表記との比較、実践的な活用方法まで詳しく紹介します。

Learning Next 運営
37 分で読めます

みなさん、Pythonでリストから特定の条件に合う要素だけを取り出したいと思ったことはありませんか?

「偶数だけを抽出したい」 「特定の文字を含む文字列だけを選びたい」 「条件に合うデータだけをフィルタリングしたい」

そんな時に役立つのがfilter関数です。 でも大丈夫です!

この記事では、filter関数の基本から実践的な使い方まで、初心者向けに分かりやすく解説します。 コード例をたくさん使って、一緒に理解していきましょう!

filter関数って何?

filter関数は、条件に合う要素だけを抽出してくれる便利な関数です。 簡単に言うと、「フィルター」の役割をしてくれます。

基本的な仕組み

まず、シンプルな例から見てみましょう:

# 正の数だけを抽出する関数
def is_positive(number):
return number > 0
# リストから正の数だけを取り出す
numbers = [-3, -1, 0, 2, 5, 8, -2]
positive_numbers = list(filter(is_positive, numbers))
print(f"元のリスト: {numbers}")
print(f"正の数のみ: {positive_numbers}")

実行結果:

元のリスト: [-3, -1, 0, 2, 5, 8, -2] 正の数のみ: [2, 5, 8]

**filter(関数, リスト)**という形で使います。 関数がTrueを返す要素だけが残ります。

filter関数の書き方

filter関数の基本的な構文はこんな感じです:

filter(条件を判定する関数, フィルタリングしたいリスト)

もう少し詳しい例を見てみましょう:

# 偶数を判定する関数
def is_even(number):
return number % 2 == 0
# 1から10までの数値
all_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 偶数だけを抽出
even_numbers = list(filter(is_even, all_numbers))
print(f"全ての数値: {all_numbers}")
print(f"偶数のみ: {even_numbers}")

実行結果:

全ての数値: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 偶数のみ: [2, 4, 6, 8, 10]

is_even関数が各数値をチェックして、偶数(2で割り切れる数)だけを抽出しています。

他の方法との比較

filter関数を使わない場合と比較してみましょう:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 方法1: for文を使った従来の方法
even_traditional = []
for num in numbers:
if num % 2 == 0:
even_traditional.append(num)
print("for文の場合:", even_traditional)
# 方法2: filter関数を使った方法
even_filter = list(filter(lambda x: x % 2 == 0, numbers))
print("filter関数の場合:", even_filter)
# 方法3: リスト内包表記
even_comprehension = [x for x in numbers if x % 2 == 0]
print("リスト内包表記:", even_comprehension)

実行結果:

for文の場合: [2, 4, 6, 8, 10] filter関数の場合: [2, 4, 6, 8, 10] リスト内包表記: [2, 4, 6, 8, 10]

結果は同じですが、filter関数は条件が明確で読みやすいのが特徴です。

基本的な使い方

filter関数の基本的な使い方を、具体例とともに学んでいきましょう。

数値のフィルタリング

まず、数値を扱う基本的な例から始めます:

data = [-10, -5, -1, 0, 1, 3, 5, 8, 10, 15, 20]
print("元のデータ:", data)
# 正の数だけ
positive = list(filter(lambda x: x > 0, data))
print(f"正の数: {positive}")
# 負の数だけ
negative = list(filter(lambda x: x < 0, data))
print(f"負の数: {negative}")
# 5以上10以下の数
range_5_to_10 = list(filter(lambda x: 5 <= x <= 10, data))
print(f"5以上10以下: {range_5_to_10}")

実行結果:

元のデータ: [-10, -5, -1, 0, 1, 3, 5, 8, 10, 15, 20] 正の数: [1, 3, 5, 8, 10, 15, 20] 負の数: [-10, -5, -1] 5以上10以下: [5, 8, 10]

lambda x: 条件という書き方で、簡単な条件を指定できます。

文字列のフィルタリング

文字列でもfilter関数を活用できます:

words = ["apple", "banana", "cherry", "date", "elderberry", "fig", "grape"]
print("単語リスト:", words)
# 5文字以上の単語
long_words = list(filter(lambda w: len(w) >= 5, words))
print(f"5文字以上: {long_words}")
# 'a'を含む単語
contains_a = list(filter(lambda w: 'a' in w, words))
print(f"'a'を含む: {contains_a}")
# 'e'で終わる単語
ends_with_e = list(filter(lambda w: w.endswith('e'), words))
print(f"'e'で終わる: {ends_with_e}")

実行結果:

単語リスト: ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig', 'grape'] 5文字以上: ['apple', 'banana', 'cherry', 'elderberry', 'grape'] 'a'を含む: ['apple', 'banana', 'date', 'grape'] 'e'で終わる: ['apple', 'date', 'elderberry', 'grape']

文字列の長さや内容で条件を指定できます。

リストの中の辞書をフィルタリング

より実践的な例として、辞書のリストをフィルタリングしてみましょう:

students = [
{"name": "田中", "age": 20, "grade": "A"},
{"name": "佐藤", "age": 22, "grade": "B"},
{"name": "鈴木", "age": 19, "grade": "A"},
{"name": "高橋", "age": 21, "grade": "C"},
{"name": "伊藤", "age": 23, "grade": "A"}
]
print("学生データ:")
for student in students:
print(f" {student['name']}: {student['age']}歳, {student['grade']}評価")
# 20歳以上の学生
adults = list(filter(lambda s: s["age"] >= 20, students))
print(f"
20歳以上の学生:")
for student in adults:
print(f" {student['name']}: {student['age']}歳")
# A評価の学生
a_grade = list(filter(lambda s: s["grade"] == "A", students))
print(f"
A評価の学生:")
for student in a_grade:
print(f" {student['name']}: {student['grade']}評価")

実行結果:

学生データ: 田中: 20歳, A評価 佐藤: 22歳, B評価 鈴木: 19歳, A評価 高橋: 21歳, C評価 伊藤: 23歳, A評価 20歳以上の学生: 田中: 20歳 佐藤: 22歳 高橋: 21歳 伊藤: 23歳 A評価の学生: 田中: A評価 鈴木: A評価 伊藤: A評価

辞書の中の特定のキーの値で条件を指定できます。

空の値やNoneを除去する

実際のデータ処理でよく使われる、空の値を除去する方法です:

mixed_data = [1, None, 3, "", 5, 0, None, 7, False, 9]
print("元のデータ:", mixed_data)
# None以外の値
non_none = list(filter(lambda x: x is not None, mixed_data))
print(f"None以外: {non_none}")
# 「真」の値のみ(より簡潔な書き方)
truthy_values = list(filter(None, mixed_data))
print(f"真の値のみ: {truthy_values}")
# 空でない文字列
texts = ["hello", "", "world", None, "python", "", "programming"]
non_empty_texts = list(filter(lambda x: x and x.strip(), texts))
print(f"
空でない文字列: {non_empty_texts}")

実行結果:

元のデータ: [1, None, 3, '', 5, 0, None, 7, False, 9] None以外: [1, 3, '', 5, 0, 7, False, 9] 真の値のみ: [1, 3, 5, 7, 9] 空でない文字列: ['hello', 'world', 'python', 'programming']

**filter(None, リスト)**は、「偽」の値(None、0、空文字列など)を除去する便利な方法です。

lambda式との組み合わせ

filter関数では、lambda式を使って条件を簡潔に書けます。 lambda式について詳しく見てみましょう。

lambdaの基本的な書き方

lambda式は、簡単な関数を一行で書く方法です:

# 普通の関数
def is_even(x):
return x % 2 == 0
# lambda式で同じことを書く
is_even_lambda = lambda x: x % 2 == 0
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# どちらも同じ結果
result1 = list(filter(is_even, numbers))
result2 = list(filter(is_even_lambda, numbers))
result3 = list(filter(lambda x: x % 2 == 0, numbers))
print("普通の関数:", result1)
print("lambda変数:", result2)
print("直接lambda:", result3)

実行結果:

普通の関数: [2, 4, 6, 8, 10] lambda変数: [2, 4, 6, 8, 10] 直接lambda: [2, 4, 6, 8, 10]

lambda x: 条件という形で、短く書けるのが便利です。

複雑な条件をlambdaで書く

より複雑な条件も、lambdaで表現できます:

products = [
{"name": "ノートPC", "price": 80000, "category": "electronics", "stock": 5},
{"name": "マウス", "price": 2500, "category": "electronics", "stock": 20},
{"name": "本", "price": 1500, "category": "books", "stock": 0},
{"name": "コーヒー", "price": 500, "category": "food", "stock": 30},
{"name": "スマートフォン", "price": 60000, "category": "electronics", "stock": 8}
]
print("商品データのフィルタリング:")
# 5000円以下の商品
affordable = list(filter(lambda p: p["price"] <= 5000, products))
print(f"5000円以下の商品:")
for product in affordable:
print(f" {product['name']}: {product['price']}円")
# 在庫ありの電子機器
electronics_in_stock = list(filter(
lambda p: p["category"] == "electronics" and p["stock"] > 0,
products
))
print(f"
在庫ありの電子機器:")
for product in electronics_in_stock:
print(f" {product['name']}: {product['stock']}個")

実行結果:

商品データのフィルタリング: 5000円以下の商品: マウス: 2500円 本: 1500円 コーヒー: 500円 在庫ありの電子機器: ノートPC: 5個 マウス: 20個 スマートフォン: 8個

andorを使って、複数の条件を組み合わせできます。

より高度なlambda式

さらに複雑な条件の例も見てみましょう:

employees = [
{"name": "田中", "age": 28, "department": "開発", "salary": 5000000, "experience": 3},
{"name": "佐藤", "age": 35, "department": "営業", "salary": 4500000, "experience": 8},
{"name": "鈴木", "age": 42, "department": "開発", "salary": 7000000, "experience": 15},
{"name": "高橋", "age": 29, "department": "マーケティング", "salary": 4800000, "experience": 5},
{"name": "伊藤", "age": 38, "department": "開発", "salary": 6200000, "experience": 12}
]
print("従業員データの高度なフィルタリング:")
# シニアエンジニア(開発部、30歳以上、経験10年以上)
senior_engineers = list(filter(
lambda emp: (emp["department"] == "開発" and
emp["age"] >= 30 and
emp["experience"] >= 10),
employees
))
print(f"
シニアエンジニア:")
for emp in senior_engineers:
print(f" {emp['name']}: {emp['age']}歳, 経験{emp['experience']}年")
# 高収入の若手(30歳未満、年収500万以上)
high_earning_young = list(filter(
lambda emp: emp["age"] < 30 and emp["salary"] >= 5000000,
employees
))
print(f"
高収入の若手:")
for emp in high_earning_young:
print(f" {emp['name']}: {emp['age']}歳, {emp['salary']:,}円")

実行結果:

従業員データの高度なフィルタリング: シニアエンジニア: 鈴木: 42歳, 経験15年 伊藤: 38歳, 経験12年 高収入の若手: 田中: 28歳, 5,000,000円

複数の条件を組み合わせることで、より精密なフィルタリングができます。

lambdaの制限と対処法

lambda式では表現しにくい複雑な条件もあります。 そんな時は、普通の関数を使いましょう:

def is_valid_email(email):
"""メールアドレスの妥当性をチェック"""
if not email or not isinstance(email, str):
return False
# 基本的なチェック
if "@" not in email or "." not in email:
return False
# @の個数チェック
if email.count("@") != 1:
return False
# 空白文字のチェック
if " " in email:
return False
return True
# テストデータ
email_candidates = [
"user@example.com",
"invalid-email",
"test@test.org",
"user@@double.com", # 無効
"space @email.com", # 無効
"admin@site.net"
]
valid_emails = list(filter(is_valid_email, email_candidates))
print("有効なメールアドレス:")
for email in valid_emails:
print(f" {email}")

実行結果:

有効なメールアドレス: user@example.com test@test.org admin@site.net

複雑な判定は、普通の関数を作った方が読みやすくなります。

実践的な活用例

filter関数の実践的な使い方を、具体例とともに見てみましょう。

データ分析での活用

売上データを分析する例です:

sales_data = [
{"date": "2024-01-15", "product": "ノートPC", "amount": 120000, "region": "東京"},
{"date": "2024-01-16", "product": "マウス", "amount": 2500, "region": "大阪"},
{"date": "2024-01-17", "product": "キーボード", "amount": 8000, "region": "東京"},
{"date": "2024-01-18", "product": "モニター", "amount": 45000, "region": "名古屋"},
{"date": "2024-01-19", "product": "ノートPC", "amount": 135000, "region": "東京"},
{"date": "2024-01-20", "product": "タブレット", "amount": 60000, "region": "大阪"}
]
print("=== 売上データ分析 ===")
print(f"総売上件数: {len(sales_data)}")
# 高額商品(50000円以上)
high_value_sales = list(filter(lambda sale: sale["amount"] >= 50000, sales_data))
print(f"
高額商品の売上: {len(high_value_sales)}件")
for sale in high_value_sales:
print(f" {sale['date']}: {sale['product']} {sale['amount']:,}円")
# 東京エリアの売上
tokyo_sales = list(filter(lambda sale: sale["region"] == "東京", sales_data))
tokyo_total = sum(sale["amount"] for sale in tokyo_sales)
print(f"
東京エリアの売上: {len(tokyo_sales)}, 合計 {tokyo_total:,}円")
# PC関連商品
pc_products = list(filter(
lambda sale: sale["product"] in ["ノートPC", "タブレット"],
sales_data
))
print(f"
PC関連商品: {len(pc_products)}件")
for sale in pc_products:
print(f" {sale['product']}: {sale['amount']:,}円")

実行結果:

=== 売上データ分析 === 総売上件数: 6 高額商品の売上: 4件 2024-01-15: ノートPC 120,000円 2024-01-18: モニター 45,000円 2024-01-19: ノートPC 135,000円 2024-01-20: タブレット 60,000円 東京エリアの売上: 3件, 合計 263,000円 PC関連商品: 3件 ノートPC: 120,000円 ノートPC: 135,000円 タブレット: 60,000円

ビジネスデータの分析でも、filter関数は大活躍します。

ログ分析での活用

システムのログを分析する例です:

log_entries = [
{"timestamp": "2024-01-15 10:30:00", "level": "INFO", "message": "アプリケーション開始"},
{"timestamp": "2024-01-15 10:31:00", "level": "INFO", "message": "ユーザーログイン"},
{"timestamp": "2024-01-15 10:32:00", "level": "WARNING", "message": "メモリ使用量が高い"},
{"timestamp": "2024-01-15 10:33:00", "level": "ERROR", "message": "データベース接続失敗"},
{"timestamp": "2024-01-15 10:34:00", "level": "INFO", "message": "データベース再接続成功"},
{"timestamp": "2024-01-15 10:35:00", "level": "ERROR", "message": "ファイル読み込みエラー"},
{"timestamp": "2024-01-15 10:36:00", "level": "CRITICAL", "message": "システム停止"}
]
print("=== ログ分析 ===")
print(f"総ログエントリー数: {len(log_entries)}")
# エラーレベルのログのみ
error_logs = list(filter(lambda log: log["level"] in ["ERROR", "CRITICAL"], log_entries))
print(f"
エラーログ: {len(error_logs)}件")
for log in error_logs:
print(f" {log['timestamp']} [{log['level']}] {log['message']}")
# 問題のあるログ
def is_problematic_log(log):
"""問題のあるログかどうかを判定"""
problem_levels = ["WARNING", "ERROR", "CRITICAL"]
problem_keywords = ["失敗", "エラー", "停止", "高い"]
if log["level"] in problem_levels:
return True
return any(keyword in log["message"] for keyword in problem_keywords)
problematic_logs = list(filter(is_problematic_log, log_entries))
print(f"
問題のあるログ: {len(problematic_logs)}件")
for log in problematic_logs:
print(f" {log['timestamp']} [{log['level']}] {log['message']}")

実行結果:

=== ログ分析 === 総ログエントリー数: 7 エラーログ: 3件 2024-01-15 10:33:00 [ERROR] データベース接続失敗 2024-01-15 10:35:00 [ERROR] ファイル読み込みエラー 2024-01-15 10:36:00 [CRITICAL] システム停止 問題のあるログ: 4件 2024-01-15 10:32:00 [WARNING] メモリ使用量が高い 2024-01-15 10:33:00 [ERROR] データベース接続失敗 2024-01-15 10:35:00 [ERROR] ファイル読み込みエラー 2024-01-15 10:36:00 [CRITICAL] システム停止

ログの監視や問題の特定にも、filter関数が使えます。

ファイル処理での活用

ファイル一覧から特定の条件のファイルを抽出する例です:

files = [
{"name": "document.pdf", "size": 1024000, "modified": "2024-01-15"},
{"name": "image.jpg", "size": 2048000, "modified": "2024-01-10"},
{"name": "script.py", "size": 5120, "modified": "2024-01-20"},
{"name": "data.csv", "size": 512000, "modified": "2024-01-18"},
{"name": "backup.zip", "size": 10240000, "modified": "2024-01-12"},
{"name": "config.json", "size": 2048, "modified": "2024-01-19"}
]
print("=== ファイル分析 ===")
print(f"総ファイル数: {len(files)}")
# 大きなファイル(1MB以上)
large_files = list(filter(lambda f: f["size"] >= 1024000, files))
print(f"
大きなファイル(1MB以上): {len(large_files)}件")
for file in large_files:
size_mb = file["size"] / 1024000
print(f" {file['name']}: {size_mb:.2f}MB")
# Pythonファイル
python_files = list(filter(lambda f: f["name"].endswith('.py'), files))
print(f"
Pythonファイル: {len(python_files)}件")
for file in python_files:
print(f" {file['name']}: {file['size']}バイト")
# 最近更新されたファイル(2024-01-18以降)
recent_files = list(filter(lambda f: f["modified"] >= "2024-01-18", files))
print(f"
最近更新されたファイル: {len(recent_files)}件")
for file in recent_files:
print(f" {file['name']}: {file['modified']}")

実行結果:

=== ファイル分析 === 総ファイル数: 6 大きなファイル(1MB以上): 3件 document.pdf: 1.00MB image.jpg: 2.00MB backup.zip: 10.00MB Pythonファイル: 1件 script.py: 5120バイト 最近更新されたファイル: 3件 script.py: 2024-01-20 data.csv: 2024-01-18 config.json: 2024-01-19

ファイル管理やバックアップの自動化でも活躍します。

リスト内包表記との比較

filter関数と似た機能を持つリスト内包表記と比較してみましょう。

基本的な比較

同じ結果を得る2つの方法を比較します:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# filter関数を使った方法
even_filter = list(filter(lambda x: x % 2 == 0, numbers))
print("filter関数:", even_filter)
# リスト内包表記を使った方法
even_comprehension = [x for x in numbers if x % 2 == 0]
print("リスト内包表記:", even_comprehension)
# 結果は同じ
print("結果が同じ:", even_filter == even_comprehension)

実行結果:

filter関数: [2, 4, 6, 8, 10] リスト内包表記: [2, 4, 6, 8, 10] 結果が同じ: True

どちらを使っても、同じ結果が得られます。

それぞれの特徴

それぞれの使い分けのポイントを見てみましょう:

# 複雑な条件の場合
def is_prime(n):
"""素数かどうかを判定"""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
numbers = list(range(1, 21))
print("=== 使い分けの例 ===")
# 1. 既存の関数を使う場合
print("既存の関数を使う場合(素数抽出):")
print("filter関数:", list(filter(is_prime, numbers)))
print("リスト内包表記:", [x for x in numbers if is_prime(x)])
# 2. 単純な条件の場合
print("
単純な条件の場合(偶数抽出):")
print("filter関数:", list(filter(lambda x: x % 2 == 0, numbers)))
print("リスト内包表記:", [x for x in numbers if x % 2 == 0])
# 3. フィルタ + 変換の場合
print("
フィルタ + 変換の場合(偶数の2乗):")
print("filter + map:", list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, numbers))))
print("リスト内包表記:", [x**2 for x in numbers if x % 2 == 0])

実行結果:

=== 使い分けの例 === 既存の関数を使う場合(素数抽出): filter関数: [2, 3, 5, 7, 11, 13, 17, 19] リスト内包表記: [2, 3, 5, 7, 11, 13, 17, 19] 単純な条件の場合(偶数抽出): filter関数: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] リスト内包表記: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] フィルタ + 変換の場合(偶数の2乗): filter + map: [4, 16, 36, 64, 100, 144, 196, 256, 324, 400] リスト内包表記: [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]

どちらを選ぶべき?

使い分けの指針をまとめます:

filter関数が適している場面

  • 既存の関数を条件として使いたい時
  • 条件だけを抽出したい時(変換は不要)
  • 関数型プログラミングのスタイルを重視する時

リスト内包表記が適している場面

  • 条件が比較的シンプルな時
  • フィルタリングと同時に要素の変換もしたい時
  • Pythonらしい書き方を重視する時
data = [
{"name": "田中", "age": 25, "score": 85},
{"name": "佐藤", "age": 30, "score": 92},
{"name": "鈴木", "age": 22, "score": 78},
{"name": "高橋", "age": 28, "score": 88}
]
print("=== 実用的な比較 ===")
# 単純なフィルタリング(80点以上)
print("80点以上の学生(filter関数):")
high_scorers_filter = list(filter(lambda s: s["score"] >= 80, data))
for student in high_scorers_filter:
print(f" {student['name']}: {student['score']}点")
print("
80点以上の学生(リスト内包表記):")
high_scorers_comp = [s for s in data if s["score"] >= 80]
for student in high_scorers_comp:
print(f" {student['name']}: {student['score']}点")
# フィルタ + 変換(名前だけ抽出)
print("
80点以上の学生の名前のみ(filter + map:")
names_filter = list(map(lambda s: s["name"], filter(lambda s: s["score"] >= 80, data)))
print(f" {names_filter}")
print("
80点以上の学生の名前のみ(リスト内包表記):")
names_comp = [s["name"] for s in data if s["score"] >= 80]
print(f" {names_comp}")

実行結果:

=== 実用的な比較 === 80点以上の学生(filter関数): 田中: 85点 佐藤: 92点 高橋: 88点 80点以上の学生(リスト内包表記): 田中: 85点 佐藤: 92点 高橋: 88点 80点以上の学生の名前のみ(filter + map): ['田中', '佐藤', '高橋'] 80点以上の学生の名前のみ(リスト内包表記): ['田中', '佐藤', '高橋']

どちらを使っても結果は同じですが、用途に応じて使い分けると良いでしょう。

まとめ

Pythonのfilter関数について、基本から実践的な使い方まで詳しく解説しました。

重要なポイント

  • filter関数は条件に合う要素だけを抽出する
  • lambda式と組み合わせて簡潔に書ける
  • 実践的な場面でも幅広く活用できる
  • リスト内包表記との使い分けが大切

filter関数の特徴

  • 条件が明確で読みやすい
  • 既存の関数を活用しやすい
  • 大量データの処理に適している
  • 関数型プログラミングのスタイル

実践的な活用場面

  • データ分析での条件抽出
  • ログ分析での問題特定
  • ファイル処理での絞り込み
  • Webデータの整理

filter関数を使いこなすことで、データの条件抽出がとても効率的になります。 最初は簡単な数値や文字列のフィルタリングから始めて、徐々に複雑なデータ構造にも挑戦してみてください。

ぜひ実際のプログラムで、今回学んだfilter関数を活用してみてくださいね! きっとデータ処理がもっと楽しくなるはずです。

関連記事