#python #pandas #dataframe
#python #pandas #фрейм данных
Вопрос:
У меня есть фрейм данных, который проиндексирован таким образом.
Value Size
A B Market Cap
2019-07-01 AAPL 89.583458 9.328360 2.116356e 06
AMGN 49.828466 10.058943 1.395518e 05
2019-10-01 AAPL 74.297570 11.237253 2.116356e 06
AMGN 56.841946 10.237481 1.395518e 05
2019-12-31 AAPL 97.435257 14.736749 2.116356e 06
AMGN 71.400903 12.859612 1.395518e 05
Я хочу применить функцию к каждому из его столбцов для каждой даты (так что 89.583458 и 49.828466 идут вместе, 9.328360 и 10.058943 идут вместе и так далее)
winsorized_df = pipeline_df.groupby(level=0, axis=0).apply(
lambda level_0_col: level_0_col.groupby(level=1, axis=1).apply(
lambda series: mstats.winsorize(a=series, limits=winsorize_bounds))
)
Это дает мне
Market Cap ... B
2019-07-01 [[139551.76568603513], [139551.76568603513]] ... [[49.828465616227064], [49.828465616227064]]
2019-10-01 [[139551.76568603513], [139551.76568603513]] ... [[56.84194615992103], [56.84194615992103]]
2019-12-31 [[139551.76568603513], [139551.76568603513]] ... [[71.40090272484755], [71.40090272484755]]
Но теперь мне нужно восстановить потерянные индексы (чтобы вернуть ту же структуру, что и исходная), но не удалось установить as_index=False
, разархивировать или использовать pd.MultiIndex.from_frame. Есть идеи? Возможно, есть лучший способ получить именно это из groupby
вызова?
Ответ №1:
Проблема в том, что winsorize
возвращает массив numpy. Итак, вы заменяете фрейм данных массивом numpy (именно поэтому вы видите [[...]]
в своем выводе). Вместо этого вы должны заменить значения фрейма данных. Вот пример:
import pandas
from scipy.stats.mstats import winsorize
# Recreating your dataframe
data = [
{"date": "2019-07-01", "group": "AAPL", "A": 89.583458, "B": 9.328360, "Market Cap": 2.116356e 06},
{"date": "2019-07-01", "group": "AMGN", "A": 49.828466, "B": 10.058943, "Market Cap": 1.395518e 05},
{"date": "2019-10-01", "group": "AAPL", "A": 74.297570, "B": 11.237253, "Market Cap": 2.116356e 06},
{"date": "2019-10-01", "group": "AMGN", "A": 56.841946, "B": 10.237481, "Market Cap": 1.395518e 05},
{"date": "2019-12-31", "group": "AAPL", "A": 97.435257, "B": 14.736749, "Market Cap": 2.116356e 06},
{"date": "2019-12-31", "group": "AMGN", "A": 71.400903, "B": 12.859612, "Market Cap": 1.395518e 05},
]
index = [
[pandas.to_datetime(line.get("date")) for line in data],
[line.get("group") for line in data],
]
columns = [
["Value", "Value", "Size"],
["A", "B", "Market Cap"]
]
df = pandas.DataFrame(data=[[line.get("A"), line.get("B"), line.get("Market Cap")] for line in data], index=index, columns=columns)
# Your lambda function in a separate definition
def process_group(group):
# Nested
def _sub(sub):
# winsorize returns an numpy array, sub is a dataframe; sub[:] replaces the "values" of the dataframe, not the dataframe itself
sub[:] = winsorize(a=sub, limits=[0.4, 0.6]) # I didn't know your limits so I've guessed...
return sub
# Return the result of the processing on the nested group
return group.groupby(level=1, axis=1).apply(_sub)
# Process the groups
df = df.groupby(level=0, axis=0).apply(process_group)
Вывод:
Value Size
A B Market Cap
2019-07-01 AAPL 49.828466 9.328360 139551.8
AMGN 49.828466 9.328360 139551.8
2019-10-01 AAPL 56.841946 10.237481 139551.8
AMGN 56.841946 10.237481 139551.8
2019-12-31 AAPL 71.400903 12.859612 139551.8
AMGN 71.400903 12.859612 139551.8
Комментарии:
1. Это красивое, элегантное решение. Намного проще отлаживать поведение. Я буду использовать этот шаблон при применении / отображении функций. Слава! 🙂