Допустим, у меня есть набор данных 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'
Как мне это решить?
Есть ли у вас лучшие способы решения первоначального вопроса?
Ваш исходный 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)
Это помогает нам понять, что при использовании apply
func2
передается один 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 и как передача такого аргумента приводит к передаче кадра данных, состоящего из одной группы.
Также интересно, почему вы не использовали idxmax для pt['diff'] вместо фильтрации по максимальному значению. Это медленнее, чем при использовании max?
Максимальное значение может иметь более одного района. «Idxmax» возвращает только одно значение.
Ваш вопрос неполный. Вы должны предоставить четкий минимально воспроизводимый пример с явными входными данными для примера и соответствующим ожидаемым результатом.