簡體   English   中英

基於元組的子集pandas數據幀

[英]Subset pandas data frame based on tuple

我有這樣的數據集

Firstnames = ['AA','BB','CC','AA','CC']
Lastnames = ['P', 'Q', 'R', 'P', 'R']
values = [10, 13, 3, 22, 45]

df = pd.DataFrame(data = list(zip(Firstnames,Lastnames,values)), \
                  columns=['Firstnames','Lastnames','values'])
df

    Firstnames  Lastnames   values
0   AA          P           10
1   BB          Q           13
2   CC          R           3
3   AA          P           22
4   CC          R           45

我有一個這樣的元組數組

lst = array([('AA', 'P'), ('BB', 'Q')])

我想要子集df,這樣Firstname == 'AA' & Lastnames == 'P'Firstname == 'BB' & Lastnames == 'Q'

我可以手動執行此操作,但是我的數組非常大,我想以編程方式執行此操作

我的預期產量將是

Firstnames  Lastnames   values
AA          P           10
AA          P           22
BB          Q           13

agg + isin

由於元組是可清除的,因此您可以使用isin並將聚合值與last值進行比較。 直接使用lst和列表而不是np.array幫助。

>>> lst = [('AA', 'P'), 
           ('BB', 'Q')]

>>> mask = df[['Firstnames', 'Lastnames']].agg(tuple, 1).isin(lst)
>>> df[mask]

    Firstnames  Lastnames   values
0   AA          P           10
1   BB          Q           13
3   AA          P           22

如果需要,可以按名稱sort_values

>>> df[mask].sort_values(by=['Firstnames', 'Lastnames'])

    Firstnames  Lastnames   values
0   AA          P           10
3   AA          P           22
1   BB          Q           13

pd.concat

你也可以使用list comprehensionpd.concat來獲得更小的lst

>>> pd.concat([df[df.Firstnames.eq(a) & df.Lastnames.eq(b)] for a,b in lst])

    Firstnames  Lastnames   values
0   AA          P           10
3   AA          P           22
1   BB          Q           13

時序:

lst ,大df

df = pd.concat([df]*10000).reset_index(drop=True)

%timeit mask = df[['Firstnames', 'Lastnames']].agg(tuple, 1).isin(lst); df[mask].sort_values(by=['Firstnames', 'Lastnames'])
942 ms ± 71.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit pd.concat([df[df.Firstnames.eq(a) & df.Lastnames.eq(b)] for a,b in lst])
16.2 ms ± 355 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

對於大lst和小df

c = list(map(''.join, itertools.product(string.ascii_uppercase, string.ascii_uppercase)))
lst = [(a,b) for a,b in zip(c, list(string.ascii_uppercase)*26)]
df = pd.DataFrame({'Firstnames': c, 'Lastnames': list(string.ascii_uppercase)*26, 'values': 10})

%timeit mask = df[['Firstnames', 'Lastnames']].agg(tuple, 1).isin(lst); df[mask].sort_values(by=['Firstnames', 'Lastnames'])
15.1 ms ± 301 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit pd.concat([df[df.Firstnames.eq(a) & df.Lastnames.eq(b)] for a,b in lst])
781 ms ± 33.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

pd.Index.isin

將所選系列轉換為MultiIndex對象,然后將pd.Index.isin與元組列表一起使用:

lst = [('AA', 'P'), ('BB', 'Q')]
df_masked = df[df.set_index(['Firstnames', 'Lastnames']).index.isin(lst)]

績效基准

# Python 3.6.5, Pandas v0.23.0

lst = [('AA', 'P'), ('BB', 'Q')]
df = pd.concat([df]*10000).reset_index()

%timeit df[df.set_index(['Firstnames', 'Lastnames']).index.isin(lst)]  # 23.4 ms

您可以在這里使用numpy廣播來獲得高性能的解決方案。 在大量的DataFrame上,您可能會開始看到性能pd.Index.isin ,此時您應該使用pd.Index.isin 您應該避免轉換為tuple並對所有大小的DataFrame使用該類型的比較。

設定

lst = np.array([('AA', 'P'), ('BB', 'Q')])

idx = (df.values[:, :2] == lst[:, None]).any(axis=(0, -1))
df[idx]

  Firstnames Lastnames  values
0         AA         P      10
1         BB         Q      13
3         AA         P      22

性能

df = pd.concat([df]*10000).reset_index()

In [228]: %timeit df[df.set_index(['Firstnames', 'Lastnames']).index.isin(lst)]
15.5 ms ± 270 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [236]: %%timeit
     ...: mask = df[['Firstnames', 'Lastnames']].agg(tuple, 1).isin(lst)
     ...: df[mask]
     ...:
853 ms ± 22.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [231]: %%timeit
     ...: idx = (df.values[:, :2] == lst[:, None]).any(axis=(0, -1))
     ...: df[idx]
     ...:
11.6 ms ± 264 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM