Squeak.ru - шаблоны программирования

Удаление повторяющихся значений, которые встречаются более N раз

У меня есть фрейм данных с повторяющимися значениями в столбце «крышка». Я хочу использовать Pandas для удаления строк, значение которых в столбце «крышка» подсчитывается более 2 раз. Вот исходная таблица:

entity  pnb head#   state   lid
ABB001  A03 3   DOWN    A
ABB001  A03 3   DOWN    A
ABB001  A03 3   DOWN    A
ABB002  A02 4   DOWN    B
ABB002  A02 4   DOWN    B
ABB002  A02 2   DOWN    C
ABB002  A02 4   DOWN    D
ABB002  A02 4   DOWN    E
ABB002  A02 4   DOWN    E
ABB002  A02 4   DOWN    E

Вот результат:

entity  pnb head#   state   lid
ABB002  A02 4   DOWN    B
ABB002  A02 4   DOWN    B
ABB002  A02 2   DOWN    C
ABB002  A02 4   DOWN    D

Ответы:


1

Вариант 0
Использование value_counts и isin

df[~df.lid.isin(df.lid.value_counts().loc[lambda x: x > 2].index)]

   entity  pnb  head# state lid
3  ABB002  A02      4  DOWN   B
4  ABB002  A02      4  DOWN   B
5  ABB002  A02      2  DOWN   C
6  ABB002  A02      4  DOWN   D

Вариант 1
Лучше реализовать с np.in1d и pd.factorize

lids = df.lid.values
f, u = pd.factorize(df.lid.values)
df[np.in1d(lids, u[np.bincount(f) <= 2])]

   entity  pnb  head# state lid
3  ABB002  A02      4  DOWN   B
4  ABB002  A02      4  DOWN   B
5  ABB002  A02      2  DOWN   C
6  ABB002  A02      4  DOWN   D

Вариант 2
Использование np.bincount и pd.factorize

f, u = pd.factorize(df.lid)
df[np.bincount(f)[f] <= 2]

   entity  pnb  head# state lid
3  ABB002  A02      4  DOWN   B
4  ABB002  A02      4  DOWN   B
5  ABB002  A02      2  DOWN   C
6  ABB002  A02      4  DOWN   D

Для забавной демонстрации, чтобы подчеркнуть то, о чем мы с @cᴏʟᴅsᴘᴇᴇᴅ говорили в комментариях.

Люблю bincount один. Где-то тоже должен быть np.unique. – cᴏʟᴅsᴘᴇᴇᴅ

Да, есть. Однако я не использую np.unique, потому что @Jeff сообщил мне, что np.unique сортируется, когда вы берете счетчики, индексируете или инверсируете. pd.factorize не работает и равен O (n). С тех пор я подтвердил эту информацию. - piRSquared

Тест времени

def bincount_factorize(df):
    f, u = pd.factorize(df.lid.values)
    return df[np.bincount(f)[f] <= 2]

def bincount_unique(df):
    u, f = np.unique(df.lid.values, return_inverse=True)
    return df[np.bincount(f)[f] <= 2]

def in1d_factorize(df):
    lids = df.lid.values
    f, u = pd.factorize(df.lid.values)
    return df[np.in1d(lids, u[np.bincount(f) <= 2])]

def transform(df):
    return df[df.groupby('lid')['lid'].transform('size') <= 2]

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000,
           30000, 100000, 300000, 1000000],
    columns=['bincount_factorize', 'bincount_unique',
             'in1d_factorize', 'transform'],
    dtype=float
)

for i in res.index:
    d = pd.concat([df] * i, ignore_index=True)
    for j in res.columns:
        stmt = f'{j}(d)'
        setp = f'from __main__ import d, {j}'
        res.at[i, j] = timeit(stmt, setp, number=100)

res.div(res.min(1), 0)

         bincount_factorize  bincount_unique  in1d_factorize  transform
10                 1.421827         1.000000        1.119577   3.751167
30                 1.008412         1.037297        1.000000   3.072631
100                1.000000         1.531300        1.028267   3.304560
300                1.000000         2.666583        1.182812   3.637235
1000               1.065213         5.563098        1.000000   2.556469
3000               1.024658        10.480027        1.000000   2.238765
10000              1.073403        14.716801        1.000000   1.574780
30000              1.000000        16.387130        1.053180   1.494161
100000             1.000000        18.533078        1.003031   1.369867
300000             1.078129        20.183122        1.000000   1.530698
1000000            1.166800        24.571463        1.000000   1.670423

res.plot(loglog=True)

введите здесь описание изображения

16.01.2018
  • Люблю bincount один. Где-то тоже должен быть np.unique. 16.01.2018
  • Да, есть. Однако я не использую np.unique, потому что @Jeff сообщил мне, что np.unique сортируется, когда вы берете подсчеты, индексируете или инверсируете. pd.factorize нет и является O(n). С тех пор я подтвердил эту информацию. 16.01.2018

  • 2

    Используйте groupby + transform.

    df[~df.lid.groupby(df.lid).transform('count').gt(2)]
    

       entity  pnb  head# state lid
    3  ABB002  A02      4  DOWN   B
    4  ABB002  A02      4  DOWN   B
    5  ABB002  A02      2  DOWN   C
    6  ABB002  A02      4  DOWN   D
    

    transform gets you a series of counts of the same size.

    v = df.lid.groupby(df.lid).transform('count')
    v
    
    0    3
    1    3
    2    3
    3    2
    4    2
    5    1
    6    1
    7    3
    8    3
    9    3
    Name: lid, dtype: int
    

    Используйте это, чтобы выяснить, какие строки нужно пройти.

    ~v.gt(2)
    
    0    False
    1    False
    2    False
    3     True
    4     True
    5     True
    6     True
    7    False
    8    False
    9    False
    Name: lid, dtype: bool
    

    Используйте маску для индексации df.

    16.01.2018

    3

    Используйте transform с < a href="http://pandas.pydata.org/pandas-docs/stable/indexing.html#boolean-indexing" rel="nofollow noreferrer">boolean indexing:

    df = df[df.groupby('lid')['lid'].transform('size') <= 2]
    
    print (df)
       entity  pnb  head# state lid
    3  ABB002  A02      4  DOWN   B
    4  ABB002  A02      4  DOWN   B
    5  ABB002  A02      2  DOWN   C
    6  ABB002  A02      4  DOWN   D
    

    Деталь:

    print (df.groupby('lid')['lid'].transform('size'))
    0    3
    1    3
    2    3
    3    2
    4    2
    5    1
    6    1
    7    3
    8    3
    9    3
    Name: lid, dtype: int64
    
    print (df.groupby('lid')['lid'].transform('size') <= 2)
    0    False
    1    False
    2    False
    3     True
    4     True
    5     True
    6     True
    7    False
    8    False
    9    False
    Name: lid, dtype: bool
    

    Другое более медленное решение с filter:

    df = df.groupby('lid').filter(lambda x: len(x) <= 2)
    print (df)
       entity  pnb  head# state lid
    3  ABB002  A02      4  DOWN   B
    4  ABB002  A02      4  DOWN   B
    5  ABB002  A02      2  DOWN   C
    6  ABB002  A02      4  DOWN   D
    

    Время:

    #jez1
    In [34]: %timeit (df[df.groupby('lid')['lid'].transform('size') <= 2000])
    10 loops, best of 3: 57.8 ms per loop
    
    #jez2
    In [35]: %timeit df.groupby('lid').filter(lambda x: len(x) <= 2000)
    10 loops, best of 3: 124 ms per loop
    
    #cᴏʟᴅsᴘᴇᴇᴅ
    In [36]: %timeit (df[~df.lid.groupby(df.lid).transform('count').gt(2000)])
    10 loops, best of 3: 93.6 ms per loop
    
    #pir1
    In [37]: %timeit (df[~df.lid.isin(df.lid.value_counts().loc[lambda x: x > 2000].index)])
    10 loops, best of 3: 137 ms per loop
    
    #pir2
    In [38]: %timeit (pir(df))
    10 loops, best of 3: 32.9 ms per loop
    

    Настройка:

    np.random.seed(123)
    N = 1000000
    L = list('abcde') 
    df = pd.DataFrame({'lid': np.random.choice(L, N, p=(0.75,0.0001,0.0005,0.0005,0.2489)),
                       'A':np.random.randint(10000,size=N)})
    df = df.sort_values(['A','lid']).reset_index(drop=True)
    #print (df)
    
    
    print (df[~df.lid.groupby(df.lid).transform('count').gt(2000)])
    print (df[df.groupby('lid')['lid'].transform('size') <= 2000])
    print (df[~df.lid.isin(df.lid.value_counts().loc[lambda x: x > 2000].index)])
    
    
    def pir(df):
        f, u = pd.factorize(df.lid)
        return df[np.bincount(f)[f] <= 2000]
    
    print (pir(df))
    

    Осторожно

    Результаты не учитывают производительность с учетом количества групп, что сильно повлияет на время для некоторых из этих решений.

    16.01.2018
  • Я не записал это с учетом скорости. Но если мы это сделаем, вы захотите использовать pd.factorize(df.lid.values) в pir 16.01.2018
  • я получаю In [40]: %timeit (pir(df)) 10 loops, best of 3: 33.5 ms per loop 16.01.2018
  • с def pir(df): f, u = pd.factorize(df.lid.values) return df[np.bincount(f)[f] <= 2000], так что тут вроде тоже самое 16.01.2018
  • Ну, тогда я думаю, что это не имеет большого значения для больших данных (-: 16.01.2018
  • @piRSquared - Точно. И я удивлен, что Исин такой медленный :( 16.01.2018
  • Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...