中学理科1630641 views
中学英語811710 views
雑学1473612 views
いろは3010814 views
LaTeX962153 views
小学算数1200427 views
世界の国564520 views
ヒストリア290598 views
高校倫理1440106 views
高校日本史190571 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Python の set vs NumPy の集合演算(np.unique, np.intersect1d)

Python の組み込み set と NumPy の集合演算関数は、どちらも集合的な操作を提供するが、設計思想とパフォーマンス特性が大きく異なる。

基本的なアプローチの違い

Python の set はハッシュテーブルを使い、NumPy はソートベースのアルゴリズムを使う。

Python set

ハッシュテーブル。O(1) の検索。任意のハッシュ可能オブジェクト対応。

NumPy 集合演算

ソートベース。O(n log n) の前処理。数値配列に特化。ベクトル化による高速処理。

この違いが、それぞれの得意分野を決定している。

重複排除の比較

まず基本的な重複排除を比較する。

import numpy as np

# Python set
data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
unique_set = set(data)
print(unique_set)  # {1, 2, 3, 4, 5, 6, 9}

# NumPy
arr = np.array(data)
unique_np = np.unique(arr)
print(unique_np)  # [1 2 3 4 5 6 9](ソート済み)

np.unique() は結果がソートされる点が異なる。これはソートベースのアルゴリズムを使っているためだ。

積集合の比較

2 つの配列の共通要素を求める。

import numpy as np

a = [1, 2, 3, 4, 5]
b = [4, 5, 6, 7, 8]

# Python set
result_set = set(a) & set(b)
print(result_set)  # {4, 5}

# NumPy
result_np = np.intersect1d(a, b)
print(result_np)  # [4 5]

NumPy の np.intersect1d() は内部で両方の配列をソートし、マージソートのような走査で共通要素を見つける。

和集合と差集合

NumPy にも対応する関数がある。

import numpy as np

a = np.array([1, 2, 3, 4])
b = np.array([3, 4, 5, 6])

# 和集合
print(np.union1d(a, b))      # [1 2 3 4 5 6]

# 差集合
print(np.setdiff1d(a, b))    # [1 2]

# 対称差
print(np.setxor1d(a, b))     # [1 2 5 6]

Python の set 演算 |, -, ^ に対応している。

パフォーマンス比較

小規模データでは set が有利だが、大規模な数値配列では NumPy が逆転する。

import numpy as np
import time

# 100万要素のテスト
n = 1000000
list_a = list(range(n))
list_b = list(range(n // 2, n + n // 2))

arr_a = np.array(list_a)
arr_b = np.array(list_b)

# Python set
start = time.perf_counter()
result = set(list_a) & set(list_b)
print(f"set: {time.perf_counter() - start:.4f}s")

# NumPy
start = time.perf_counter()
result = np.intersect1d(arr_a, arr_b)
print(f"numpy: {time.perf_counter() - start:.4f}s")

NumPy は C 言語で実装されており、SIMD 命令を活用できるため、純粋な計算では高速だ。ただし、Python リストから NumPy 配列への変換コストを含めると、set のほうが速いこともある。

計算量の違い

操作Python setNumPy
重複排除O(n)O(n log n)
積集合O(min(m, n))O(m log m + n log n)
存在確認O(1)O(log n) または O(n)

set はハッシュテーブルの O(1) 検索を活かせる。NumPy はソート後のバイナリサーチか線形走査になる。

メモリ効率

NumPy 配列は連続したメモリに格納されるため、数値データではメモリ効率がよい。

import sys
import numpy as np

n = 10000
py_set = set(range(n))
np_arr = np.unique(np.arange(n))

print(f"set: {sys.getsizeof(py_set):,} bytes")
print(f"numpy: {np_arr.nbytes:,} bytes")

整数の場合、NumPy の int64 配列は要素あたり 8 バイトで済む。Python の set は各要素が Python オブジェクトとして格納されるため、オーバーヘッドが大きい。

np.isin による存在確認

NumPy で「配列の各要素が別の集合に含まれるか」を調べるには np.isin() を使う。

import numpy as np

data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
targets = np.array([2, 4, 6, 8])

mask = np.isin(data, targets)
print(mask)   # [False  True False  True False  True False  True False False]
print(data[mask])  # [2 4 6 8]

これは set の in 演算を配列全体に適用するようなもので、ベクトル化されているため高速だ。

assume_unique オプション

入力が既にユニークであることがわかっている場合、assume_unique=True で高速化できる。

import numpy as np

a = np.array([1, 2, 3, 4, 5])  # すでにユニーク
b = np.array([3, 4, 5, 6, 7])  # すでにユニーク

# 通常(ユニーク化処理が入る)
result1 = np.intersect1d(a, b)

# assume_unique=True(ユニーク化をスキップ)
result2 = np.intersect1d(a, b, assume_unique=True)

大規模データでは数十パーセントの高速化になることがある。

return_indices オプション

NumPy 特有の機能として、元の配列でのインデックスを返すオプションがある。

import numpy as np

a = np.array([10, 20, 30, 40, 50])
b = np.array([30, 50, 70])

common, idx_a, idx_b = np.intersect1d(a, b, return_indices=True)
print(common)  # [30 50]
print(idx_a)   # [2 4](a での位置)
print(idx_b)   # [0 1](b での位置)

これは set では直接できない操作で、後続の処理で元データを参照したい場合に便利だ。

使い分けの指針

Python set を選ぶ場面

文字列やオブジェクトを扱う。頻繁に存在確認を行う。動的に要素を追加・削除する。集合のサイズが小〜中規模。

NumPy を選ぶ場面

大規模な数値配列を扱う。結果がソートされていてほしい。インデックスも必要。他の NumPy 処理と組み合わせる。

両者を組み合わせることもできる。例えば、フィルタリング条件を set で持ち、NumPy 配列に適用する場合だ。

import numpy as np

valid_ids = {100, 200, 300, 400, 500}  # set で管理
data = np.array([100, 150, 200, 250, 300, 350])

# set を使ったフィルタリング
mask = np.array([x in valid_ids for x in data])
filtered = data[mask]
print(filtered)  # [100 200 300]

この例では set の O(1) 検索と NumPy の配列操作を組み合わせている。