Панды ГруппБи с соотношением

#python #pandas #dataframe #numpy

Вопрос:

Я работаю над набором данных, который выглядит примерно так:

 ID  Amount Type
1   50    A
1   1000  A
1   500   B
1   200   B
2   1000  A
2   500   B
 

Я пытаюсь сделать 2 вещи: найти длину самой длинной последовательности каждого типа и найти соотношение A/B и B/A для этих последовательностей для каждого идентификатора.

Объяснение атрибута отношения: Рассчитайте общую сумму в самой длинной последовательности для каждого идентификатора(скажем, длина n). Если последовательность относится к типу A, то получите соотношение с немедленной суммой типа B(n 1 сумма). Если последовательность относится к типу B, то получите соотношение с непосредственным предшественником типа A(количество n-1).

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

 ID Longest_Sequence_A Longest_Sequence_B Ratio_A_B  Ratio B_A
1  2                  2                  0.47        0.7
2  1                  1                  0.5         0.5
 

Объяснение строки 1: Самые длинные последовательности-это просто длина самой длинной последовательности типа A и типа B.

Для соотношения A_B: Это случай 1, как определено ранее , поэтому рассчитывается сумма всех типов A в самой длинной последовательности(1050), затем берется соотношение с ближайшей последовательной суммой типа B(500), соотношение 500/1050=0,47

Для соотношения B_A: Это случай 2, как определено ранее, поэтому рассчитывается сумма всех типов B в самой длинной последовательности(700), затем берется соотношение с ближайшим предшественником суммы типа A(1000),
соотношение 700/1000=0,7

Это довольно сложный вопрос, который я не в состоянии решить. Был бы очень признателен, если бы кто-нибудь помог с этим.

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

1. Звучит как вопрос для домашнего задания. Что вы сделали до сих пор?

2. Это не вопрос домашнего задания(на несколько лет слишком поздно для этого) ,я работаю над набором данных транзакций, чтобы построить модель. Я пробовал использовать GroupBy, но тогда я не уверен, какую лямбда-функцию передать для отношения

Ответ №1:

Вот попытка:

 def ratios(df):
    df = df.reset_index(drop=True)
    groups = (df.Type != df.Type.shift(1)).cumsum()
    result = {}
    for t in ('A', 'B'):
        if t in df.Type.values:
            max_num = groups[df.Type.eq(t)].mode().iat[-1]
            max_group = df[groups.eq(max_num)]
            result[f'Longest_Sequence_{t}'] = len(max_group)
            amounts = max_group.Amount.sum()
            idx = max_group.index
            ratio = None
            if t == 'A':
                if idx[-1] != df.index[-1] and amounts != 0:
                    ratio = df.Amount.at[idx[-1]   1] / amounts
            elif t == 'B':
                if idx[0] != df.index[0]:
                    denom = df.Amount.at[idx[0] - 1]
                    if denom != 0:
                        ratio = amounts / denom
            result[f'Ratio_{t}'] = ratio
        else:
            result[f'Longest_Sequence_{t}'] = 0
            result[f'Ratio_{t}'] = None
    return pd.DataFrame([result])

df = df.groupby('ID').apply(ratios).reset_index(level=1, drop=True)
 

Результат для фрейма данных

    ID  Amount Type
0   1      50    A
1   1    1000    A
2   1     500    B
3   1     200    B
4   2    1000    A
5   2     500    B
 

является

     Longest_Sequence_A  Ratio_A  Longest_Sequence_B  Ratio_B
ID                                                          
1                    2  0.47619                   2      0.7
2                    1  0.50000                   1      0.5
 

Имена и порядок столбцов немного отличаются, но это не должно иметь значения.


Некоторые объяснения (я использую весь фрейм данных в качестве примера):

Это groups = (df.Type != df.Type.shift(1)).cumsum() идентифицирует последовательности:

 0    1
1    1
2    2
3    2
4    3
5    4
Name: Type, dtype: int64
 

Для groups[df.Type.eq('A')]

 0    1
1    1
4    3
Name: Type, dtype: int64
 

.mode() определяет 'A' порядковый номер-для последовательности максимальной длины (в случае, если есть максимальные последовательности одинаковой длины .iat[-1] , выбирается последняя):

 0    1
dtype: int64
 

Теперь здесь с max_num == 1 помощью этого max_group = df[groups.eq(max_num)] выбирается соответствующая группа с индексом от df (последний пункт важен для остальных):

    ID  Amount Type
0   1      50    A
1   1    1000    A
 

Все остальное-это попытка следовать вашим инструкциям по расчету и тем самым позаботиться о крайних случаях. Использование индекса idx относительно df позволяет перемещаться вперед и назад, df чтобы выбрать другие значения, необходимые для коэффициентов. (В начале функции индекс преобразуется в стандартный индекс, просто чтобы убедиться, потому что я хочу иметь возможность использовать /- его.)

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

1. Это не работает. Я получаю ошибку индекса для строки: max_num = группы[df. Amount.eq(t)].mode().iat[-1] Ошибка индекса: индекс -1 выходит за рамки для оси 0 с размером 0

2. Из того, что я могу сказать, он терпит неудачу в каком-то крайнем случае, возможно, в случае, когда в нем есть только суммы одного типа

3. Мое подозрение: ID в кадре есть только один вид Type -ценности. Я скорректировал код для этого случая.

4. Извините, только что увидел ваш последний комментарий: это именно то, о чем я думал.

5. Теперь это работает, спасибо. Вероятно, вы придумаете обходной путь для соотношения=Ничего в зависимости от моего варианта использования. Все равно очень полезно! Спасибо