You can use groupby for this purpose.
To find how many Num with different ID :
groups = df.groupby("Num").apply(lambda x: len(set(x["ID"])))
result = sum(groups > 1)
And for the other way around :
groups = df.groupby("ID").apply(lambda x: len(set(x["Num"])))
result = sum(groups > 1)
Edit 1: As proposed by @Grzegorz Skibinski in comment, nunique() may be more concise, so :
result = sum(df.groupby("Num")["ID"].nunique() > 1)
Edit 2: Benchmark
I created dataframe with 2 columns (integer and str)
import pandas as pd
import numpy as np
import random
import string
df = pd.DataFrame({
"col1": np.random.randint(0, 100, 1000_000),
"col2": ["".join(random.sample(string.ascii_lowercase[:5], 3)) for _ in range(1000_000)]
})
Counting on the str column: nunique() wins over len(set()).
However Counting on the int column: len(set()) wins over nunique()
%%timeit -n 10
df.groupby("col1").apply(lambda x: len(set(x["col2"])))
# output: 10 loops, best of 5: 467 ms per loop
%%timeit -n 10
df.groupby("col1")["col2"].nunique()
# output: 10 loops, best of 5: 296 ms per loop
%%timeit -n 10
df.groupby("col2").apply(lambda x: len(set(x["col1"])))
# output: 10 loops, best of 5: 286 ms per loop
%%timeit -n 10
df.groupby("col2")["col1"].nunique()
# output: 10 loops, best of 5: 306 ms per loop