2017-02-21 9 views
1

Я пытаюсь применить функцию масштабирования к data.frame группой «категория». Функция масштабирования требует определенного скаляра в зависимости от его категории. Вычисление: каждое значение «t» делится на общее число «t» на «кот», а затем умножается на скаляр, который соответствует «cat» (т.е. «fac.a» для cat = a и т. Д.), ,Получить переменную по тексту по группе для применения функции

Я использую «получить», чтобы вызвать конкретный скаляр, но только с использованием значения для 1-й линии и применяя ко всему data.frame:

# my scaling factors: 
fac.a <- 15 
fac.b <- 12 
fac.c <- 20 

# dummy data.frame 
set.seed(10) 
df <- data.frame(t = sample(1:100,15),cat = rep(c("a","b","c"),each=5)) 

# apply function that groups & sums the df$t values by df$cat, divides each df$t by its 
# repsective category total and applies the correct scalar with a get function. 
df$scaled <- apply(df[1], 2, function(x) (df$t/ave(df$t, df$cat, FUN=sum))*get(paste0("fac.",df$cat))) 

К сожалению, я только получать право ответ для 1-й категории, поскольку функция get вызывает только 1-й скаляр.

Это можно сделать с относительной легкостью в 4-5 строках (создание отдельных атрибутов и т. Д.), Но я бы хотел добиться этого в функции приложения.

N.B. почему новый атрибут, называемый «t» в data.frame, но «масштабированный», когда я просматриваю имена (df)?

ответ

1

Мы можем использовать data.table

library(data.table) 
setDT(df)[, newt := sum(t), cat][, 
    scaled := (t/newt) * get(paste0('fac.', cat)), 1:nrow(df)][, newt := NULL][] 
#  t cat scaled 
# 1: 51 a 3.8059701 
# 2: 31 a 2.3134328 
# 3: 42 a 3.1343284 
# 4: 68 a 5.0746269 
# 5: 9 a 0.6716418 
# 6: 22 b 1.1046025 
# 7: 26 b 1.3054393 
# 8: 94 b 4.7196653 
# 9: 57 b 2.8619247 
#10: 40 b 2.0083682 
#11: 59 c 3.6875000 
#12: 100 c 6.2500000 
#13: 10 c 0.6250000 
#14: 52 c 3.2500000 
#15: 99 c 6.1875000 

Или быстрее вариантом будет создать ключ/значение набора данных, смыкаются с исходными данными, чтобы создать столбец «масштабируется»

df2 <- setnames(setDT(stack(mget(ls(pattern="fac\\.")))[2:1]), 
         1, "cat")[, cat := sub(".*\\.", "", cat)][] 
setDT(df)[df2, scaled := (t/sum(t))*values, on = .(cat), by = .EACHI] 
df 
#  t cat scaled 
# 1: 51 a 3.8059701 
# 2: 31 a 2.3134328 
# 3: 42 a 3.1343284 
# 4: 68 a 5.0746269 
# 5: 9 a 0.6716418 
# 6: 22 b 1.1046025 
# 7: 26 b 1.3054393 
# 8: 94 b 4.7196653 
# 9: 57 b 2.8619247 
#10: 40 b 2.0083682 
#11: 59 c 3.6875000 
#12: 100 c 6.2500000 
#13: 10 c 0.6250000 
#14: 52 c 3.2500000 
#15: 99 c 6.1875000 
+0

да, я жадный пользователь data.table, люблю его. Но я отчаянно пытаюсь понять это в применении, используя get. Возможно, я глуп, но это проблема, которую я бы хотел решить! спасибо за ваш ответ, хотя – Sam

+0

@Sam Я бы сказал, что лучше не использовать 'apply' здесь, поскольку есть один столбец, а' apply' преобразует вывод в 'matrix' – akrun

+0

ok спасибо. Кроме того, ваши масштабированные цифры выглядят немного низко .... первый масштабированный результат должен быть примерно 3,8, например. Я думаю, что вы разделились на скаляр, а не на умножение, я ставлю, что это мой плохой вопрос :) – Sam