Умножить столбцы на подстроки в R
Предположим, у меня есть фрейм данных, который имеет несколько компонентов и их свойства перечислены в нескольких столбцах, и я хочу запустить несколько функций для столбцов. Мой подход состоял в том, чтобы попытаться основать его на подстроке в заголовке каждого столбца, но я не смог понять, как это сделать. Ниже приведен пример фрейма данных.
Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2
AAA Apple 10 2.5 Banana 9 2
BBB Peach 5 6 Melon 20 5
По сути, я хочу привязать два новых столбца к концу этого кадра данных, который умножает Qty и P, чтобы вы получили два новых столбца в конце, как показано ниже.
F_Total_1 F_Total_2
25 18
30 100
Ввод динамический, поэтому иногда в некоторых корзинах может быть 2 или 10 фруктов. Но я могу понять эту часть, более того, он пытается выяснить, как умножить столбцы на основе подстрок "1" или "2".
Я ценю вашу помощь и любые другие подходы, которые вы можете иметь!
6 ответов
Мы создаем функцию, которая находит конкретные имена, а затем вычисляет линейные произведения. Тяжелоатлет этой функции является mapply
функция. Добавляем последний шаг для переименования результирующего data.frame
,
fun1 <- function(data){
qty_names <- names(data)[grepl(pattern = "Qty", x = names(data))]
p_names <- names(data)[grepl(pattern = "P", x = names(data))]
setNames(
data.frame(
mapply(qty_names, p_names,
FUN = function(n1, n2) apply(data[c(n1,n2)], 1, prod))),
paste0('F_Total_', 1:length(p_names)))
}
cbind(dat, fun1(dat))
Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2 F_Total_1 F_Total_2
1 AAA Apple 10 2.5 Banana 9 2 25 18
2 BBB Peach 5 6.0 Melon 20 5 30 100
setNames(df[grepl("F_Qty",names(df))]*df[grepl("F_P",names(df))],paste0("F_Total_",1:2))
F_Total_1 F_Total_2
1 25 18
2 30 100
В базе R вы можете использовать [[]]
Форма для доступа к столбцу со строкой, так что вы можете легко зацикливаться
df <- read.table(text = "Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2
AAA Apple 10 2.5 Banana 9 2
BBB Peach 5 6 Melon 20 5",header = T)
for(i in 1:2)
{
df[[paste0("F_Total_",i)]] <- as.numeric(df[[paste0("F_P_",i)]])*as.numeric(df[[paste0("F_Qty_",i)]])
}
Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2 F_Total_1 F_Total_2
1 AAA Apple 10 2.5 Banana 9 2 25 18
2 BBB Peach 5 6.0 Melon 20 5 30 100
Вот метод, использующий tidyverse
функции для изменения ваших данных. В основном используя tidyr
глаголы, мы преобразовываем ваши данные в более "аккуратный" формат.
# library(dplyr); library(tidyr)
dd %>% select(Basket, contains("_Qty_"), contains("_P_")) %>%
gather("key", "value", -Basket) %>%
separate(key, c("F", "Val", "Grp")) %>%
group_by(Basket, Grp) %>%
spread(Val, value) %>%
mutate(Total=P*Qty, GrpN=paste0("Total_", Grp)) %>%
ungroup() %>%
select(Basket, GrpN, Total) %>%
spread(GrpN ,Total)
# Basket Total_1 Total_2
# <fct> <dbl> <dbl>
# 1 AAA 25 18
# 2 BBB 30 100
Создать данные
library(data.table)
df <- fread("
Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2
AAA Apple 10 2.5 Banana 9 2
BBB Peach 5 6 Melon 20 5
")
df
# Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2
# 1: AAA Apple 10 2.5 Banana 9 2
# 2: BBB Peach 5 6.0 Melon 20 5
Для номеров от 1 до sum(grepl('F_P_', names(df)))
, задавать F_Total_{number}
как F_Qty_{number}*F_P_{number}
for(i in seq(sum(grepl('F_P_', names(df)))))
df[, paste0('F_Total_', i) := Reduce(`*`, .SD)
, .SDcols = paste0(c('F_Qty_', 'F_P_'), i)]
df
# Basket F_Type_1 F_Qty_1 F_P_1 F_Type_2 F_Qty_2 F_P_2 F_Total_1 F_Total_2
# 1: AAA Apple 10 2.5 Banana 9 2 25 18
# 2: BBB Peach 5 6.0 Melon 20 5 30 100
Или в базе R с df
как data.frame
for(i in seq(sum(grepl('F_P_', names(df)))))
df[paste0('F_Total_', i)] <- Reduce(`*`, df[paste0(c('F_Qty_', 'F_P_'), i)])
Предложение: Если бы вы могли хранить ваши данные в длинном формате, это сделает будущее обслуживание намного чище.
Basket Item Type Qty Price Total
AAA 1 Apple 10 2.5 25
AAA 2 Banana 9 2 18
BBB 1 Peach 5 6.0 30
BBB 2 Melon 20 5 100
BBB 3 Orange 11 2.7 29.7
Затем, когда вам действительно нужны данные в вышеуказанном формате, используйте data.table
пакет для транспонирования данных.
library(data.table)
fruits <- data.frame("Basket" = c("AAA", "AAA", "BBB", "BBB", "BBB"),
"Item" = c(1,2,1,2,3),
"Type" = c("Apple", "Banana", "Peach", "Melon", "Orange"),
"Qty" = c(10, 9, 5, 20, 11),
"Price" = c(2.5, 2, 6.0, 5, 2.7)
)
fruits$Total <- fruits$Qty * fruits$Price
fruits.New <- data.table::dcast(setDT(fruits),
formula = Basket ~ Item,
value.var = c("Type", "Price", "Qty", "Total"))
Таким образом, вам нужно поддерживать только одну формулу и не беспокоиться о apply
, давая вам возможность иметь переменные номера столбцов тоже.
Имя столбца должно быть относительно легко исправить, если оно важно.