Представьте себе следующие данные (код для воспроизведения всех выходных данных находится в конце):
df
cars horsepower year safety
1 Toyota 140 2008 4
2 Chrysler 120 2009 4
3 Ford 140 2010 5
4 BMW 150 2008 3
5 Mercedes-Benz 150 2008 3
6 Hyundai 120 2009 4
7 Jaguar 150 2007 3
8 Tesla 120 2010 5
Я бы хотел поменять местами машины, чтобы получить что-то вроде:
cars_initial cars_match horsepower year safety horsepowerMatch yearMatch safetyMatch
1 Toyota BMW 140 2008 4 150 2008 3
2 Tesla Chrysler 120 2010 5 120 2009 4
3 Mercedes-Benz Ford 150 2008 3 140 2010 5
4 Jaguar Hyundai 150 2007 3 120 2009 4
5 Hyundai Jaguar 120 2009 4 150 2007 3
6 Ford Mercedes-Benz 140 2010 5 150 2008 3
7 Chrysler Tesla 120 2009 4 120 2010 5
8 BMW Toyota 150 2008 3 140 2008 4
Теперь это типичная проблема назначения, которая в вышеописанном случае решалась случайным образом, т. Е. По матрице затрат во всех случаях равной 0.
Меня интересуют результаты.В приведенном выше случае решение дает следующую статистику:
stats
horsepower year safety
1 0.25 0.25 0
То есть 1/4 свопов имели равную мощность и т. Д.
Вот мой вопрос: какрешать такие задания, устанавливая ограничения на то, что именно должно быть статистикой результатов напрямую, без метода проб и ошибок с установкой затрат?
Например, что, если я хотел бы иметь решение, где safety
имеет более 0,20 совпадений и year
не менее 0,10, как показано ниже?
desiredOutput
cars_initial cars_match
1 Toyota Chrysler
2 Tesla Mercedes-Benz
3 Mercedes-Benz BMW
4 Jaguar Toyota
5 Hyundai Tesla
6 Ford Hyundai
7 Chrysler Jaguar
8 BMW Ford
statsDesired
horsepower year safety
1 0.25 0.12 0.25
Конечно, я мог бы просто установить матрицу затрат на меньшее число во всех случаях, когда safety
автомобилейравно.
Но есть ли способ повлиять на результат, напрямую установив ограничение на то, какой должна быть статистика результатов?
Возможно, есть способ оптимизировать затраты, чтобы достичь желаемогорезультат?
Код:
library(lpSolve)
library(dplyr)
library(tidyr)
set.seed(1)
df <- data.frame(
cars = c("Toyota", "Chrysler", "Ford", "BMW", "Mercedes-Benz", "Hyundai", "Jaguar", "Tesla"),
horsepower = c(140, 120, 140, 150, 150, 120, 150, 120),
year = c(2008, 2009, 2010, 2008, 2008, 2009, 2007, 2010),
safety = c(4, 4, 5, 3, 3, 4, 3, 5)
)
mat <- df %>% select(cars) %>%
crossing(df %>% select(cars)) %>%
mutate(val = 0) %>%
spread(cars, val)
solved <- lp.assign(mat %>% select(-cars1) %>% as.matrix())$solution
matches <- as.data.frame(solved) %>%
setNames(., names(mat %>% select(-cars1))) %>%
bind_cols(mat %>% select(cars1)) %>%
gather(key, val, -cars1) %>%
filter(val == 1) %>% select(-val, cars_initial = cars1, cars_match = key)
nms <- c("cars", paste0(names(df %>% select(-cars)), "Match"))
matches <- matches %>%
left_join(df, by = c("cars_initial" = "cars")) %>%
left_join(df %>% setNames(., nms), by = c("cars_match" = "cars"))
stats <- matches %>%
summarise(
horsepower = round(sum(horsepower == horsepowerMatch) / n(), 2),
year = round(sum(year == yearMatch) / n(), 2),
safety = round(sum(safety == safetyMatch) / n(), 2)
)
desiredOutput <- data.frame(cars_initial = matches$cars_initial, cars_match = c("Chrysler", "Mercedes-Benz", "BMW", "Toyota", "Tesla", "Hyundai", "Jaguar", "Ford"))
statsDesired <- desiredOutput %>%
left_join(df, by = c("cars_initial" = "cars")) %>%
left_join(df %>% setNames(., nms), by = c("cars_match" = "cars")) %>%
summarise(
horsepower = round(sum(horsepower == horsepowerMatch) / n(), 2),
year = round(sum(year == yearMatch) / n(), 2),
safety = round(sum(safety == safetyMatch) / n(), 2)
)
Надеюсь, приведенных выше примеров достаточно, это мой первый вопрос, поэтому, пожалуйста, дайте мне знать, если мне нужно предоставить что-то еще.
Код находится в R
, но я также добавил тег Python
, так как я не особо обращаю внимание на язык возможных решений.