Как сохранить только верхние n% строк каждой группы в панде? - PullRequest
0 голосов
/ 18 ноября 2018

Я видел вариант этого вопроса, в котором сохраняются первые n строк каждой группы в кадре данных панд, а решения используют здесь абсолютное число, а не процент Панды получают n самых верхних записей в каждой группе.Однако в моем фрейме данных каждая группа имеет разное количество строк, и я хочу сохранить n% верхних строк каждой группы.Как бы я подошел к этой проблеме?

Ответы [ 2 ]

0 голосов
/ 18 ноября 2018

Вот еще один вариант, который основывается на некоторых ответах в посте, который вы упомянули.

Прежде всего, здесь есть быстрая функция для округления в большую или меньшую сторону.Если мы хотим, чтобы верхние 30% строк в кадре данных имели длину 8 строк, мы бы попытались взять 2,4 строки.Таким образом, нам нужно будет либо округлить вверх или вниз.

Мой предпочтительный вариант - округлить.Это потому, что, например, если бы мы взяли 50% строк, но имели одну группу, в которой был только один ряд, мы все равно сохранили бы эту одну строку.Я держал это отдельно, так что вы можете изменить округление по своему усмотрению

def round_func(x, up=True):
    '''Function to round up or round down a float'''
    if up:
        return int(x+1)
    else:
        return int(x)

Далее я создаю фрейм данных для работы и устанавливаю параметр p, чтобы быть частью строк из каждой группы, которую мыдолжны держать.Все следует, и я прокомментировал это, так что, надеюсь, вы можете следовать.

import pandas as pd
df = pd.DataFrame({'id':[1,1,1,2,2,2,2,3,4],'value':[1,2,3,1,2,3,4,1,1]})

p = 0.30 # top fraction to keep. Currently set to 80%
df_top = df.groupby('id').apply(                        # group by the ids
    lambda x: x.reset_index()['value'].nlargest(        # in each group take the top rows by column 'value'
        round_func(x.count().max()*p)))        # calculate how many to keep from each group

df_top = df_top.reset_index().drop('level_1', axis=1)   # make the dataframe nice again

df выглядел так

   id  value
0   1      1
1   1      2
2   1      3
3   2      1
4   2      2
5   2      3
6   2      4
7   3      1
8   4      1

df_top выглядит так

   id  value
0   1      3
1   2      4
2   2      3
3   3      1
4   4      1
0 голосов
/ 18 ноября 2018

Вы можете создать логическую серию флагов и отфильтровать их перед вами groupby. Сначала давайте создадим примерный фрейм данных и посмотрим номер строки для каждого уникального значения в первой серии:

np.random.seed(0)
df = pd.DataFrame(np.random.randint(0, 2, (10, 3)))

print(df[0].value_counts())

0    6
1    4
Name: 0, dtype: int64

Затем определите дробь, например, На 50% ниже и построим логическую серию для фильтрации:

n = 0.5

g = df.groupby(0)
flags = (g.cumcount() + 1) <= g[1].transform('size') * n

Затем примените условие, установите индекс в качестве первого ряда и (при необходимости) отсортируйте индекс:

df = df.loc[flags].set_index(0).sort_index()

print(df)

   1  2
0      
0  1  1
0  1  1
0  1  0
1  1  1
1  1  0

Как видите, результирующий информационный кадр имеет только 3 0 индексы и 2 1 индексы, в каждом случае половину числа в исходном информационном кадре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...