как я могу применить формулу для каждой строки

#r #dataframe #apply #sapply

#r #фрейм данных #применить #sapply

Вопрос:

У меня есть такие данные

 df<-structure(list(data = structure(c(8L, 2L, 3L, 2L, 2L, 2L, 2L, 
1L, 7L, 5L, 6L, 5L, 4L), .Label = c("1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"M1yrtr", "Mitered"), class = "factor")), row.names = c(NA, -13L), class = "data.frame")
 

Я пытаюсь вычислить следующее для каждой строки

например, для второй строки, которая

 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 

Я хочу рассчитать это

 n =5
(-(2/n)*log2(2/n))   (-(1/n)*log2(1/n))  (-(1/n)*log2(1/n))  (-(1/n)*log2(1/n)) 
 

для третьего, который является

 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 

Я рассчитаю это

 (-(2/n)*log2(2/n))   (-(2/n)*log2(2/n))   (-(1/n)*log2(1/n))
 

таким образом, результат выглядит следующим образом

 dfout<- structure(list(data = structure(c(8L, 2L, 3L, 2L, 2L, 2L, 2L, 
1L, 7L, 5L, 6L, 5L, 4L), .Label = c("1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0", 
"M1yrtr", "Mitered"), class = "factor"), X = structure(c(8L, 
3L, 2L, 3L, 3L, 3L, 3L, 1L, 7L, 6L, 4L, 6L, 5L), .Label = c("0.2604594", 
"1.03563", "1.168964", "2.020935", "2.077468", "2.204594", "M1yrtr", 
"Mitered"), class = "factor")), class = "data.frame", row.names = c(NA, 
-13L))
 

Ответ №1:

В R все основные операции (сложение, вычитание, умножение, логарифмы, …) векторизуются. Это означает, что, например, если x это вектор, то log(x) это просто компонентная log функция, или 1 / x это просто компонентное разделение.

Поэтому вы можете сделать следующее:

 x <- as.numeric(str_split(df[2, ], ", ", simplify = T))
n <- 5
sum((-(x[x > 0]/n)*log2(x[x > 0]/n)))
[1] 1.921928
 

Если вы хотите применить это для всех строк, вы можете использовать sapply функцию следующим образом:

 myfun <- function(x){
 if (! grepl(",", x)) return(as.character(x))
  n <- 5
  y <- as.numeric(str_split(x, ", ", simplify = T))
  as.character(sum((-(y[y > 0]/n)*log2(y[y > 0]/n))))
}

df$newcol <- sapply(df[,1], myfun) 
 

Комментарии:

1. Я больше заинтересован в том, чтобы делать это более программно. если я захочу использовать ваш метод, он будет таким же, как я делаю это один за другим. есть ли способ получить результат, подобный тому, что я показал выше?

2. Я добавил способ сделать это для всего data.frame

3. большое вам спасибо за ваше время, но все же то, что вы вычисляете, отличается от того, что я рассчитал выше

4. значения в dfout не соответствуют приведенной вами формуле. Например: (-(2/n)*log2(2/n)) (-(1/n)*log2(1/n)) (-(1/n)*log2(1/n)) (-(1/n)*log2(1/n)) = 1.921928. Но у dfout вас есть 1.168964

5. Я думаю, что у меня достаточно вашего времени, я постараюсь это выяснить. Большое спасибо. Мне понравился и принял ваш ответ