#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