Добавление более одной группировки фрейма данных

#python #pandas

#python #панды

Вопрос:

У меня есть df :

Это выглядит так:

     A  Wave Dept  Ratio
1   1     1    A     10
2   4     1    A      6
3   7     2    A      3
4   2     2    A      4
5   6     2    B      9
6   5     2    B      7
7   5     1    B     12
8   5     1    B      4
9   5     2    C      9
10  5     1    C      3
11  5     1    C      4
12  5     2    C      7
  

В настоящее время я группирую данные по Dept и проверяю каждую строку Ratio на соответствие всем другим соотношениям с тем же отделом и увеличиваю количество, если значение соотношения превышает пороговое значение.

Код для этого выглядит следующим образом:

     import pandas as pd
    lowerThreshold=1.2
    
    def main():
        print()
        df = pd.DataFrame([
                [1, 1, 'A', 10], 
                [4, 1 ,'A', 6], 
                [7, 2 ,'A', 3],
                [2, 2 ,'A', 4],
                [6, 2 ,'B', 9],
                [5, 2 ,'B', 7],
                [5, 1 ,'B', 12],
                [5, 1 ,'B', 4],
                [5, 2 ,'C', 9],
                [5, 1 ,'C', 3],
                [5, 1 ,'C', 4],
                [5, 2 ,'C', 7]
                ],
             index=['1', '2', '3','4','5','6','7','8','9','10','11','12'],
             columns=['A', 'Wave', 'Dept', 'Ratio'])
        print('df input:')
        print(df)
        
    df['Output']=df.groupby('Dept')['Ratio'].transform(lambda dept: compareLower(dept.values,lowerThreshold))
    df[df['Wave'] <= 3]
    
    print()
    print('df - output')
    print(df)

def compareLower(dept,lowerThreshold):
    print('x:',dept)
    #print('y:',y)
    return (dept[:,None] < lowerThreshold*dept).sum(-1) 
  

Вывод для этого выглядит следующим образом:

     A  Wave Dept  Ratio  Output
1   1     1    A     10       1
2   4     1    A      6       2
3   7     2    A      3       4
4   2     2    A      4       3
5   6     2    B      9       2
6   5     2    B      7       3
7   5     1    B     12       1
8   5     1    B      4       4
9   5     2    C      9       1
10  5     1    C      3       4
11  5     1    C      4       3
12  5     2    C      7       2
  

Теперь я хотел бы добавить дополнительную группировку , которая также группируется Wave . Я хотел бы включать в группу только в том случае, если Wave значения набора данных равны или меньше волны записи. Например, если волна записей равна 1, а отдел равен A, то группировка будет включать только записи, у которых волна равна или меньше 1и значение Dept, равное A. Если волна равна 2, а Dept равно A, то группировка будет включать любую запись, у которой значение Dept равно A, а волна равна или меньше 2 (таким образом, включая записи со значением волны 1, а также 2).

Таким образом, пересмотренный вывод будет выглядеть следующим образом:

     A  Wave Dept  Ratio  Output
1   1     1    A     10       0
2   4     1    A      6       1
3   7     2    A      3       3
4   2     2    A      4       2
5   6     2    B      9       1
6   5     2    B      7       2
7   5     1    B     12       0
8   5     1    B      4       1
9   5     2    C      9       0
10  5     1    C      3       1
11  5     1    C      4       0
12  5     2    C      7       1
  

Я попытался добавить новую группировку:

 df['Output']=df.groupby('Dept','Wave<=??')['Wave','Ratio'].transform(lambda x: compareLower(x.values,lowerThreshold))
  

Но я не знаю, как сделать волну динамической (поскольку каждая строка имеет разное значение волны). Также возможно более 2 волн.

Комментарии:

1. Это ваше Wave единственное 1 и 2 или будут более высокие значения?

2. @QuangHoang спасибо — существует потенциал для более высоких значений Wave

3. Кроме того, ваш ожидаемый результат начинается с 1 или с 0 самого высокого?

4. Спасибо — Wave начнется с 1 и увеличится

Ответ №1:

Давайте попробуем вашу логику здесь, заполнив Output столбцы рейтингами, когда мы удаляем Wave один за другим:

 waves = sorted(set(df['Wave']))[::-1]

df['Output'] = np.nan

for thresh in waves:
    df['Output'] = (df[df['Wave'].le(thresh)].groupby('Dept')
                       .Ratio.rank(ascending=False).sub(1)
                       .reindex(df.index)
                       .fillna(df['Output'])
                    )
  

Вывод:

     A  Wave Dept  Ratio  Output
1   1     1    A     10     0.0
2   4     1    A      6     1.0
3   7     2    A      3     3.0
4   2     2    A      4     2.0
5   6     2    B      9     1.0
6   5     2    B      7     2.0
7   5     1    B     12     0.0
8   5     1    B      4     1.0
9   5     2    C      9     0.0
10  5     1    C      3     1.0
11  5     1    C      4     0.0
12  5     2    C      7     1.0