您可以創建值轉換爲string
到新列e
的組合,然後使用SeriesGroupBy.nunique
:
df['e'] = df.c.astype(str) + df.d.astype(str)
df = df.groupby(['a','b'])['e'].nunique().reset_index()
print (df)
a b e
0 1 10 1
1 1 20 2
您還可以使用Series
,而無需創建新列:
df =(df.c.astype(str)+df.d.astype(str)).groupby([df.a, df.b]).nunique().reset_index(name='f')
print (df)
a b f
0 1 10 1
1 1 20 2
另一種更多鈔票的解決方案是創建元組:
df=(df[['c','d']].apply(tuple, axis=1)).groupby([df.a, df.b]).nunique().reset_index(name='f')
print (df)
a b f
0 1 10 1
1 1 20 2
本answer另一個numpy的解決方案:
def f(x):
a = x.values
c = len(np.unique(np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1]))), return_counts=True)[1])
return c
print (df.groupby(['a','b'])[['c','d']].apply(f))
時序:
#[1000000 rows x 5 columns]
np.random.seed(123)
N = 1000000
df = pd.DataFrame(np.random.randint(30, size=(N,5)))
df.columns = list('abcde')
print (df)
In [354]: %timeit (df.groupby(['a','b'])[['c','d']].apply(lambda g: len(g) - g.duplicated().sum()))
1 loop, best of 3: 663 ms per loop
In [355]: %timeit (df.groupby(['a','b'])[['c','d']].apply(f))
1 loop, best of 3: 387 ms per loop
In [356]: %timeit (df.groupby(['a', 'b', 'c', 'd']).size().groupby(level=['a', 'b']).size())
1 loop, best of 3: 441 ms per loop
In [357]: %timeit ((df.c.astype(str)+df.d.astype(str)).groupby([df.a, df.b]).nunique())
1 loop, best of 3: 4.95 s per loop
In [358]: %timeit ((df[['c','d']].apply(tuple, axis=1)).groupby([df.a, df.b]).nunique())
1 loop, best of 3: 17.6 s per loop
難道你不能簡單地創建一個'f'列作爲'c'和'd'的組合嗎? –
@NilsGudat,是的我雖然關於這種方法,但我不知道這是否是一個正確的方式去。我有以下擔憂。我在這兩列都有數字值,我應該如何從它們中構造出唯一的值?我可以將它們轉換爲字符串,然後連接字符串,但可能太慢。 – Roman
沒有答案適合你? ;) – IanS