Задача, с которой я часто сталкиваюсь, похожа на следующее преобразование:
от:
home_team_id away_team_id home_team away_team
1 1 2 Arsenal Tottenham
2 2 3 Tottenham Chelsea
к
team value
1 Arsenal 1
2 Tottenham 2
3 Tottenham 2
4 Chelsea 3
В своей голове я называю это «двойным поворотом», хотя, возможно, есть более подходящее название.
В R я могу сделать это (списано с головы - я уверен, что gsub можно несколько оптимизировать/очистить):
library(tidyverse)
example_df_R = data.frame(
home_team_id = c(1, 2),
away_team_id = c(2,3),
home_team = c("Arsenal", "Tottenham"),
away_team = c("Tottenham", "Chelsea")
)
example_df_R %>%
pivot_longer(cols = ends_with("id")) %>%
pivot_longer(cols = ends_with("team"), values_to = "team", names_to = "team_location") %>%
filter(gsub("_id$", "", name) == team_location) %>%
select(team, value)
В python кажется, что это должно быть эквивалентно:
import pandas as pd
example_df_py = pd.DataFrame(
{
"home_team_id": [1, 2],
"away_team_id": [2, 3],
"home_team": ["Arsenal", "Tottenham"],
"away_team": ["Tottenham", "Chelsea"],
}
)
result = (
example_df_py.melt(id_vars=["home_team", "away_team"])
.melt(id_vars=["variable", "value"], var_name = "team_location", value_name = "team")
.loc[lambda dfr: dfr["variable"].str.startswith(dfr["team_location"].iloc[0])][
["team", "value"]
]
)
result
однако это дает мне:
team value
0 Arsenal 1
1 Tottenham 2
4 Tottenham 1
5 Chelsea 2
Я полностью понимаю, почему я получаю этот результат (я включил iloc, что означает, что он не работает построчно в обоих столбцах, чтобы запустить код), но не уверен, что эквивалентно правильному, «элегантному» (т.е. предпочтительно в цепочке для контекста, который мне часто приходится использовать), код pythonic для R, опубликованного выше
Большое спасибо!






Я не знаю, лучший ли это способ сделать это (или самый элегантный XD), но мне удалось добиться ожидаемых результатов с помощью кортежей и метода взорвать.
(example_df_py
.assign(team=lambda df: df[["home_team", "away_team"]].apply(tuple, axis=1), # (team1, team2), ...
value=lambda df: df[["home_team_id", "away_team_id"]].apply(tuple, axis=1)) # (id1, id2), ...
.explode(["team", "value"])
.loc[:, ["team", "value"]]
.reset_index(drop=True)
)
team value
0 Arsenal 1
1 Tottenham 2
2 Tottenham 2
3 Chelsea 3
о, это действительно приятно - не встречал explode раньше
В R короче использовать только один pivot_longer:
example_df_R %>% pivot_longer(ends_with("id")) %>% mutate(team = ifelse(name == "home_team_id", home_team, away_team)) %>% select(team, value)