Я выбрал два столбца в объекте groupby. Как применить фильтр true или false к одному, а затем применить функцию к другому?

Допустим, у меня есть набор данных Airbnb с кучей столбцов. Интерес представляют «neighbourhood_cleansed», «host_is_superhost» и «price». Я хочу найти район, в котором разница между средними ценами суперхостов и несуперхостов максимальна.

Я хочу знать, можно ли это сделать полностью с помощью функций панд.

Моя логика заключается в том, чтобы сначала сгруппировать по «neighbourhood_cleansed», затем отфильтровать объект группировки по суперхостам и не суперхостам, а затем использовать медианную функцию.

Я определил функцию func

def func(host_is_superhost, price):
    superhost_prices = price[host_is_superhost == 't']
    notsuperhost_prices = price[host_is_superhost == 'f']
    return (superhost_prices.median() - notsuperhost_prices.median())
listings = pd.read_csv("https://storage.googleapis.com/public-data-337819/listings%202%20reduced.csv",low_memory=False)
neighbourhoods = listings.groupby('neighbourhood_cleansed')[['host_is_superhost', 'price']]

Когда я запускаю следующее:

neighbourhoods.apply(func)

Выданная ошибка

TypeError: func() missing 1 required positional argument: 'price'

Как мне это решить?

Есть ли у вас лучшие способы решения первоначального вопроса?

Ваш вопрос неполный. Вы должны предоставить четкий минимально воспроизводимый пример с явными входными данными для примера и соответствующим ожидаемым результатом.

mozway 02.07.2024 19:33
1
1
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш исходный func ожидал два аргумента, но получил только один, поэтому вы получили сообщение об ошибке.

Чтобы понять, что происходит при использовании apply, попробуйте этот пример:

Мы видим, что столбец 'source' имеет только два значения.

listings["source"].unique()
Out: array(['city scrape', 'previous scrape'], dtype=object)

Давайте попробуем более простую версию func с группировкой на 'source':

def func2(row):
    print(type(row))
    print(row.shape)
    
    
grpby = listings.groupby("source")[["host_is_superhost", "price"]]
grpby.apply(func2)

Распечатывает:

<class 'pandas.core.frame.DataFrame'>
(55934, 2)
<class 'pandas.core.frame.DataFrame'>
(32012, 2)

Это помогает нам понять, что при использовании applyfunc2 передается один pd.DataFrame объект различной длины.

Альтернативный подход, который должен достичь того, что вы хотите, может использовать pd.pivot_table, чтобы изменить форму данных и вычислить медиану price. (Обратите внимание, что «цена» не является числом и ее необходимо очистить, чтобы она была полезной). Например:

listings["price_cleaned"] = (
    listings["price"].apply(lambda row: row.strip("$").replace(",", "")).astype(float)
)
pt = pd.pivot_table(
    listings,
    values = "price_cleaned",
    index = "neighbourhood_cleansed",
    columns = "host_is_superhost",
    aggfunc = "median",
)
pt["diff"] = pt["t"] - pt["f"]
mask = pt["diff"] == pt["diff"].max()
print(pt.index[mask][0])  # there is only one neighborhood in this case

'Westminster'

Эй, это действительно интересно! Впервые сталкиваюсь с сводными таблицами, надо почитать о них. Я решил свою проблему, используя функцию func с тремя аргументами (merged,neighbhourhood_cleansed,price) и передав в функцию apply значения (func, 'neighbhourhood_cleansed', 'price'). Кажется, что аргумент «объединен» передает фрейм данных, и я могу получить доступ к столбцам, используя имена столбцов. Интересно, что на самом деле представляет собой объект groupby и как передача такого аргумента приводит к передаче кадра данных, состоящего из одной группы.

Advaita Mallik 03.07.2024 06:26

Также интересно, почему вы не использовали idxmax для pt['diff'] вместо фильтрации по максимальному значению. Это медленнее, чем при использовании max?

Advaita Mallik 03.07.2024 06:36

Максимальное значение может иметь более одного района. «Idxmax» возвращает только одно значение.

Capybara 03.07.2024 06:49

Другие вопросы по теме