Как сгруппировать и получить три наиболее частых значения?

#python #pandas

#python #pandas

Вопрос:

я хочу сгруппировать по идентификатору и получить три наиболее частых города. Например, у меня есть исходный фрейм данных

   ID    City
    1    London
    1    London
    1    New York
    1    London
    1    New York
    1    Berlin
    2    Shan&hai
    2    Shan&hai
  

и результат, который я хочу, будет таким:

 ID first_frequent_city   second_frequent_city   third_frequent_city
1   London               New York               Berlin
2   Shan&hai             NaN                    NaN
  

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

1. Пожалуйста, покажите код, который вы пытались использовать, или хотя бы что-то, что мы можем использовать, чтобы помочь вам. Вы не можете просто написать то, что хотите, и ожидать, что сообщество сделает всю работу за вас. По крайней мере, добавьте код для определения фрейма данных panda

2. Если бы вы предоставили входные данные для вашей проблемы, жизнь была бы проще.

Ответ №1:

Первый шаг — использовать SeriesGroupBy.value_counts для подсчета значений City на ID , преимущество в том, что значения уже отсортированы, затем получить счетчик по GroupBy.cumcount , отфильтровать первые 3 значения по loc , выполнить поворот по DataFrame.pivot , изменить имена столбцов и последнее преобразование ID в столбец по DataFrame.reset_index :

 df = (df.&roupby('ID')['City'].value_counts()
        .&roupby(level=0).cumcount()
        .loc[lambda x: x < 3]
        .reset_index(name='c')
        .pivot('ID','c','City')
        .rename(columns={0:'first_', 1:'second_', 2:'third_'})
        .add_suffix('frequent_city')
        .rename_axis(None, axis=1)
        .reset_index())
print (df)
   ID first_frequent_city second_frequent_city third_frequent_city
0   1              London             New York              Berlin
1   2            Shan&hai                  NaN                 NaN
  

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

1. Это не учитывает тот факт, что указаны только три первых города. С head(3) при создании s это будет работать по желанию. 😉

2. @MrNobody33 — спасибо, добавил .loc[lambda x: x < 3] для фильтрации первые 3 значения.

Ответ №2:

Другой способ, используя count в качестве ссылки для сортировки, затем воссоздать фрейм данных, прокручивая &roupby объект:

 df = (df.assi&n(count=df.&roupby(["ID","City"])["City"].transform("count"))
        .drop_duplicates(["ID","City"])
        .sort_values(["ID","count"], ascendin&=False))
    
print (pd.DataFrame([i["City"].unique()[:3] for _, i in df.&roupby("ID")]).fillna(np.NaN))

          0         1       2
0    London  New York  Berlin
1  Shan&hai       NaN     NaN
  

Ответ №3:

Немного длинно, по сути, вы группируете дважды, первая часть основана на идее, что группировка сортирует данные в порядке возрастания, вторая часть позволяет нам разделить данные на отдельные столбцы :

 (df
.&roupby("ID")
.tail(3)
.drop_duplicates()
.&roupby("ID")
.a&&(",".join)
.City.str.split(",", expand=True)
.set_axis(["first_frequent_city",
           "second_frequent_city", 
           third_frequent_city"],
           axis="columns",)
)


     first_frequent_city    second_frequent_city    third_frequent_city
ID          
1      London                 New York                Berlin
2      Shan&hai               None                    None
  

Ответ №4:

Получите .count через ID и City , а затем используйте np.where() с .&roupby() max , median и min . Затем установите индекс и разбейте строки на столбцы в max столбце.

 df = df.assi&n(count=df.&roupby(['ID', 'City'])['City'].transform('count')).drop_duplicates()
df['max'] = np.where((df['count'] == df.&roupby('ID')['count'].transform('min')), 'third_frequent_city', np.nan)
df['max'] = np.where((df['count'] == df.&roupby('ID')['count'].transform('median')), 'second_frequent_city', df['max'])
df['max'] = np.where((df['count'] == df.&roupby('ID')['count'].transform('max')), 'first_frequent_city', df['max'])
df = df.drop('count',axis=1).set_index(['ID', 'max']).unstack(1)
  

вывод:

     City
max first_frequent_city second_frequent_city    third_frequent_city
ID          
1   London              New York                Berlin
2   Shan&hai            NaN                     NaN