Панды создают дополнительные значения в новом столбце на основе определенных условий

#python #pandas #dataframe

Вопрос:

У меня есть фрейм данных в этой форме:

 Name Rank  Months
A     'A3'  2
A     'A3'  2
A     'A2'  3
A     'A2'  3
A     'A2'  3
B     'A1'  4
B     'A1'  4
B     'A1'  4
B     'A1'  4
C     'A3'  2
C     'A3'  2
C     'A2'  1
 

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

 Name Rank  Months  NewIncremental
A     'A3'  2       'P4'
A     'A3'  2       'P5'
A     'A2'  3       'P1'
A     'A2'  3       'P2'
A     'A2'  3       'P3'
B     'A1'  4       'P1'
B     'A1'  4       'P2'
B     'A1'  4       'P3'
B     'A1'  4       'P4'
C     'A3'  2       'P2'
C     'A3'  2       'P3'
C     'A2'  1       'P1'
 

Таким образом, условием будет порядок рангов, который равен A1->A2->>A3. Это означает, что если есть имя с рангом A2, я присваиваю меньшее добавочное значение. Я думаю, сортировка на основе этого может помочь?

ИЗМЕНИТЬ: отредактированный порядок, так что мне нужно указать произвольный порядок рангов

Ответ №1:

Один подход:

 ranks = df.sort_values(by=["Rank"],
                    key=lambda x: x.str.replace(r"D ", "", regex=True).astype(int))
        .groupby("Name").transform("cumcount")   1
ranks = ranks.apply("P{}".format)

df["NewIncremental"] = ranks
print(df)
 

Выход

    Name Rank  Months NewIncremental
0     A   A1       2             P1
1     A   A1       2             P2
2     A   A2       3             P3
3     A   A2       3             P4
4     A   A2       3             P5
5     B   A1       4             P1
6     B   A1       4             P2
7     B   A1       4             P3
8     B   A1       4             P4
9     C   A3       2             P2
10    C   A3       2             P3
11    C   A2       1             P1
 

Шаг за шагом

 # sort df by the given criteria, then group-by
sorted_by_rank = df.sort_values(by=["Rank"], key=lambda x: x.str.replace(r"D ", "", regex=True).astype(int))

# get the ranks and apply the expected format
ranks = sorted_by_rank.groupby("Name").transform("cumcount")   1
ranks = ranks.apply("P{}".format)

# assign the new column
df["NewIncremental"] = ranks
print(df)
 

Ответ №2:

Решает ли это проблему для вас?

 df['NewIncrement'] = 'P'   df.sort_values(['Name', 'Rank']).groupby('Name').rank(method="first", ascending=True).astype(int).astype(str)
 

Ответ №3:

IIOC вы можете просто использовать rank :

 df["new"] = "P" df.groupby("Name")["Rank"].rank(method="first").astype(int).astype(str)
print (df)

   Name  Rank  Months new
0     A  'A1'       2  P1
1     A  'A1'       2  P2
2     A  'A2'       3  P3
3     A  'A2'       3  P4
4     A  'A2'       3  P5
5     B  'A1'       4  P1
6     B  'A1'       4  P2
7     B  'A1'       4  P3
8     B  'A1'       4  P4
9     C  'A3'       2  P2
10    C  'A3'       2  P3
11    C  'A2'       1  P1
 

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

1. Можно ли использовать какой-то пользовательский порядок рангов? Потому что, насколько я понимаю first , метод ранжируется на основе того, как эти значения отображаются в кадре данных. Если бы » А2 » появилось в первом ряду, это бы больше не работало?

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