numpy.isin でデータを一気にフィルタリングする方法

# はじめに

`numpy`ライブラリの`np.isin` について、詳細はご本家のマニュアルがありますが、

https://numpy.org/doc/stable/reference/generated/numpy.isin.html

使いなれるために具体例を紹介したいと思います。

## Python の `np.isin` を使って一気にフィルタリング！

Pythonでデータのフィルタリングを行う際に便利な関数の一つに、`numpy`ライブラリの`np.isin`があります。この記事では、この`np.isin`関数の使い方を具体例を交えて解説します。また、フィルタリング前後のデータを可視化する方法についても紹介します。


## `np.isin`とは？

`np.isin`は、ある配列の要素が別の配列に含まれているかどうかをチェックし、その結果をブール値の配列で返す関数です。これを使うことで、特定の条件に基づいたデータのフィルタリングが簡単に行えます。

## `np.isin`の簡単な具体例

まずは、`np.isin`の基本的な使い方を見てみましょう。

```python
import numpy as np

# サンプルデータの生成
array = np.array([1, 2, 3, 4, 5])
values_to_check = [2, 4]

# np.isinを使用して値をチェック
result = np.isin(array, values_to_check)

print("Array:", array)
print("Values to check:", values_to_check)
print("Result:", result)
```

このコードを実行すると、次のような結果が得られます。

```
Array: [1 2 3 4 5]
Values to check: [2, 4]
Result: [False  True False  True False]
```

ここでは、`array`の要素が`values_to_check`に含まれているかどうかをチェックし、その結果がブール値の配列で返されています。`True`はその要素が`values_to_check`に含まれていることを示し、`False`は含まれていないことを示します。

### `invert=True`を使った逆論理の具体例

`np.isin`には`invert=True`オプションを指定することができます。これにより、指定した値に含まれない要素を選択することができます。

```python
# np.isinを使用して逆論理で値をチェック
result_inverted = np.isin(array, values_to_check, invert=True)

print("Array:", array)
print("Values to check:", values_to_check)
print("Inverted result:", result_inverted)
```

このコードを実行すると、次のような結果が得られます。

```
Array: [1 2 3 4 5]
Values to check: [2, 4]
Inverted result: [ True False  True False  True]
```

ここでは、`array`の要素が`values_to_check`に含まれていないかどうかをチェックし、その結果がブール値の配列で返されています。

## サンプルデータの生成

次に、より実践的な例として、4つのカラムを持つデータを生成します。今回使用するデータは、次の4つのカラムを持つデータです：

- `pixel`: 0から35の整数
- `itype`: 0から5の整数
- `time`: 単調増加の正実数
- `energy`: 0から10000の整数

以下のコードでサンプルデータを生成します。

```python
import numpy as np

# データの生成
np.random.seed(42)  # 再現性のためのシード
n_samples = 1000

pixel = np.random.randint(0, 36, n_samples)
itype = np.random.randint(0, 6, n_samples)
time = np.cumsum(np.random.random(n_samples))
energy = np.random.randint(0, 10001, n_samples)
```

## `np.isin`を使ったフィルタリング

次に、`np.isin`を使ってデータをフィルタリングします。今回は、`pixel`が`[3, 10, 15]`のいずれかであり、かつ`itype`が`[1, 3, 4]`のいずれかであるデータを抽出します。

```python
# フィルタリング条件
selected_pixels = [3, 10, 15]
selected_itype = [1, 3, 4]

# np.isin関数を使ってフィルタリング
filtered_indices = np.where(np.isin(pixel, selected_pixels) & np.isin(itype, selected_itype))

filtered_pixel = pixel[filtered_indices]
filtered_itype = itype[filtered_indices]
filtered_time = time[filtered_indices]
filtered_energy = energy[filtered_indices]
```

ここで、`np.isin`関数は`pixel`および`itype`の値が指定したリストに含まれているかをチェックし、その結果に基づいてフィルタリングを行います。

## `invert=True`を使った逆論理のフィルタリング

逆に、`pixel`が`[3, 10, 15]`のいずれでもなく、かつ`itype`が`[1, 3, 4]`のいずれでもないデータを抽出するには、`invert=True`オプションを使用します。

```python
# np.isin関数を使って逆論理でフィルタリング
filtered_indices_inverted = np.where(np.isin(pixel, selected_pixels, invert=True) & np.isin(itype, selected_itype, invert=True))

filtered_pixel_inverted = pixel[filtered_indices_inverted]
filtered_itype_inverted = itype[filtered_indices_inverted]
filtered_time_inverted = time[filtered_indices_inverted]
filtered_energy_inverted = energy[filtered_indices_inverted]
```

## データの可視化

フィルタリング前後のデータを可視化するために、`matplotlib`を使います。`itype`は0から5の整数なので、離散カラーマップを使用して色分けを行います。

```python
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

# 離散カラーマップの作成
cmap = mcolors.ListedColormap(['red', 'green', 'blue', 'orange', 'purple', 'brown'])
bounds = np.arange(7) - 0.5
norm = mcolors.BoundaryNorm(bounds, cmap.N)

# 可視化
plt.figure(figsize=(14, 10))

# フィルタリング前のデータ
plt.subplot(2, 2, 1)
sc = plt.scatter(pixel, energy, c=itype, cmap=cmap, norm=norm, alpha=0.6)
plt.colorbar(sc, ticks=np.arange(6), label='itype')
plt.xlabel('Pixel')
plt.ylabel('Energy')
plt.title('Pixel vs. Energy (Before Filtering)')

plt.subplot(2, 2, 2)
sc = plt.scatter(time, energy, c=itype, cmap=cmap, norm=norm, alpha=0.6)
plt.colorbar(sc, ticks=np.arange(6), label='itype')
plt.xlabel('Time')
plt.ylabel('Energy')
plt.title('Time vs. Energy (Before Filtering)')

# フィルタリング後のデータ
plt.subplot(2, 2, 3)
sc = plt.scatter(filtered_pixel, filtered_energy, c=filtered_itype, cmap=cmap, norm=norm, alpha=0.6)
plt.colorbar(sc, ticks=np.arange(6), label='itype')
plt.xlabel('Pixel')
plt.ylabel('Energy')
plt.title('Pixel vs. Energy (After Filtering)')

plt.subplot(2, 2, 4)
sc = plt.scatter(filtered_time, filtered_energy, c=filtered_itype, cmap=cmap, norm=norm, alpha=0.6)
plt.colorbar(sc, ticks=np.arange(6), label='itype')
plt.xlabel('Time')
plt.ylabel('Energy')
plt.title('Time vs. Energy (After Filtering)')

plt.tight_layout()
plt.show()
```

![スクリーンショット 2024-07-25 2.23.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/7e78ffe7-0612-8430-6400-ad55f8abdb07.png)


## まとめ

`np.isin`を使うことで、特定の条件に基づいたデータのフィルタリングが簡単に行えます。`invert=True`オプションを使用することで、逆論理を適用して指定した値に含まれない要素をフィルタリングすることもできます。また、フィルタリング前後のデータを可視化することで、その効果を視覚的に確認することができます。この記事が、`np.isin`の使い方の理解に役立てば幸いです。