Разделите значение в каждой ячейке на среднее геометрическое определенной строки по столбцам и преобразуйте его в журнал.

Я хотел бы разделить значение в каждой ячейке на среднее геометрическое определенной строки по столбцам и преобразовать ее в журнал (натуральный логарифм).

df1
      col1  col2  col3
row1  1     777   6
row2  136   1     665
row3  0     100   97

результат

df_new
      col1    col2      col3
row1  -2.81   3.83     
row2           
row3              

пример расчета для строки 1 введите здесь описание изображения


person giegie    schedule 04.02.2020    source источник
comment
Откуда 789? Я получаю произведение 1777 и 6 как 4662.   -  person meenaparam    schedule 04.02.2020
comment
извините, это должно быть 4662, вы правы. я исправлю это   -  person giegie    schedule 04.02.2020
comment
Я получаю другой ответ Джорджи, но я думаю, что это решение правильное.   -  person meenaparam    schedule 04.02.2020
comment
В чем разница?   -  person Georgery    schedule 04.02.2020


Ответы (3)


library(tidyverse)

geometric_mean <- function(x){
    exp(sum(log(x), na.rm = TRUE) / length(x))
}

yourCalculation <- function(x){
    log(x / geometric_mean(x))
}

myMatrix <- tribble(
    ~col1  ,~col2  ,~col3
    , 1     , 777   , 6
    , 136   , 1     , 665
    , 0     , 100   , 97) %>%
    as.matrix()


t(apply(myMatrix, 1, yourCalculation))

          col1      col2      col3
[1,] -2.815733  3.839707 -1.023974
[2,]  1.108508 -3.804147  2.695640
[3,]       NaN       Inf       Inf

Важно о средних геометрических: не вычисляйте их следующим образом: prod(x)^(1/length(x)). Проблема в том, что с уже векторами среднего размера x вы, вероятно, выйдете за границы своего типа, когда будете их все умножать, и поэтому он не будет вычисляться. Способ log() и exp() лучше.

person Georgery    schedule 04.02.2020

Вот ответ на ваш вопрос. См. это обсуждение для альтернативных формул для вычисления n-го корня.

# set up the data
df <- data.frame(c(1, 777, 6), c(136, 1, 665), c(0, 100, 97))
df <- t(df)
colnames(df) <- c("V1", "V2", "V3")
rownames(df) <- NULL

# define a function to calculate the nth root
nthroot <- function(x, n){
    x^(1/n) 
}

# define a function to do your required transformations
cell_transformer <- function(x) {
    log(x/(nthroot(sapply(apply(df, 1, prod), sum), length(x))))
}

# apply the cell_transformer to your dataframe in a row-wise fashion
apply(df, 1, function(x) cell_transformer(x))    
#>         [,1]      [,2]      [,3]
#> V1 -2.815733  2.096922      -Inf
#> V2  2.851293 -3.804147 0.8010229
#> V3       Inf       Inf       Inf

Создано 4 февраля 2020 г. с помощью пакета reprex (v0.3.0)

person meenaparam    schedule 04.02.2020

Возможно, вы можете попробовать код ниже, используя as.matrix для преобразования кадра данных в матрицу перед математической операцией. Кроме того, вы можете использовать Reduce(*,df1) для получения произведения столбцов в df1.

В этом случае однострочное решение задается как:

df_new <- data.frame(log(as.matrix(df1)/Reduce(`*`,df1)**(1/ncol(df1))))

такой, что

> df_new
          col1      col2      col3
row1 -2.815733  3.839707 -1.023974
row2  1.108508 -3.804147  2.695640
row3       NaN       Inf       Inf
person ThomasIsCoding    schedule 04.02.2020