(Я хочу разделить каждый элемент в строке на соответствующее значение строки. Знаменатель должен иметь значение «Ac», когда элемент строки присутствует.
Ac V1 V2 V3 V4 V5 V6 V7
6.6 NA NA NA NA 0 5.6 5.2
8.4 NA 0 82.5 31 0 0 1.1
Output:
V1 V2 V3 V4 V5 V6 V7
NA 0/8.4 82.5/8.4 31/8.4 (0*6.6+0*6.6)/(6.6+8.4) (5.6*6.6+0*8.4)/(6.6+8.4) (5.2*6.6+1.1*8.4)/(6.6+8.4)
Мы могли бы разделить каждую строку с первым значением в строке и взять по столбцам sum
colSums(df[, -1]/df[[1]], na.rm = TRUE)
# V1 V2 V3 V4 V5 V6 V7
#0.00000 0.00000 9.82143 3.69048 0.00000 0.84848 0.91883
Если мы хотим сохранить первый элемент как NA
(NA^(colSums(is.na(df[, -1])) == nrow(df))) * colSums(df[,-1]/df[[1]], na.rm = TRUE)
# V1 V2 V3 V4 V5 V6 V7
# NA 0.00000 9.82143 3.69048 0.00000 0.84848 0.91883
@NUdu обновил ответ. Теперь он также должен работать с data.table
.
попробуйте использовать цикл и преобразовать вывод в фрейм данных или список
for (i in 2:8){
temp1 = df[1,i]/df[1,1]
temp2 = df[2,i]/df[2,1]
temp= ifelse(!is.na(temp1)&!is.na(temp2), temp1+temp2,
ifelse(is.na(temp1) &!is.na(temp2), temp2,
ifelse(!is.na(temp1) &is.na(temp2), temp1,NA)))
assign(paste0("V", i-1), temp)
rm(temp1, temp2, temp)
}
output <- c(V1, V2, V3, V4, V5, V6, V7)
output <- data.frame(output)
output
1 NA
2 0.0000000
3 9.8214286
4 3.6904762
5 0.0000000
6 0.8484848
7 0.9188312
Если фрейм данных имеет дополнительные столбцы, измените индекс в цикле (2:8).
Ваши данные:
library(dplyr)
df <- data.frame(V1 = c(rep(NA,4), 0, 5.6, 5.2),
V2 = c(NA, 0 , 82.5, 31, 0, 0, 1.1))
df <- df %>%
t %>% as.data.frame() %>%
dplyr::mutate(Ac = c(6.6, 8.4)) %>%
dplyr::select(Ac, V1:V7)
df
> df
Ac V1 V2 V3 V4 V5 V6 V7
1 6.6 NA NA NA NA 0 5.6 5.2
2 8.4 NA 0 82.5 31 0 0.0 1.1
resp <- df %>%
dplyr::select(-Ac) %>%
t %>% as.data.frame() %>%
dplyr::mutate(V1_1 = V1/df[1,1],
V2_2 = V2/df[2,1]) %>%
dplyr::rowwise() %>%
dplyr::mutate(resp = ifelse(is.na(V1_1) & is.na(V2_2), NA,
sum(V1_1, V2_2, na.rm = T))) %>%
dplyr::select(resp) %>% t %>% as.data.frame()
resp
> resp
V1 V2 V3 V4 V5 V6 V7
resp NA 0 9.821429 3.690476 0 0.8484848 0.9188312
Вот один из вариантов с tidyverse
. Мы делим все столбцы, кроме столбца «Ac», на «Ac», затем summarise_all
возвращаем sum
, если присутствует какой-либо элемент, не относящийся к NA, или возвращаем NA
library(tidyverse)
df %>%
transmute_at(-1, list(~ ./Ac)) %>%
summarise_all(list(~ if (all(is.na(.))) NA else sum(.,na.rm = TRUE)))
# V1 V2 V3 V4 V5 V6 V7
#1 NA 0 9.821429 3.690476 0 0.8484848 0.9188312
Это также можно сделать за один шаг
df %>%
summarise_at(-1, list(~ if (all(is.na(.))) NA else (sum(./Ac, na.rm = TRUE)) ))
# V1 V2 V3 V4 V5 V6 V7
#1 NA 0 9.821429 3.690476 0 0.8484848 0.9188312
Судя по комментариям,
df %>%
summarise_at(-1, list(~ if (all(is.na(.))) NA
else if (sum(is.na(.)) == 1) (sum(./Ac, na.rm = TRUE))
else (sum(Ac* ., na.rm = TRUE)/sum(Ac, na.rm = TRUE)) ))
# V1 V2 V3 V4 V5 V6 V7
#1 NA 0 9.821429 3.690476 0 2.464 2.904
Тот же метод можно перевести и на data.table
library(data.table)
setDT(df)[, lapply(.SD, function(x) if (all(is.na(x))) NA
else sum(x/Ac, na.rm = TRUE)), .SDcols = 2:ncol(df)]
# V1 V2 V3 V4 V5 V6 V7
#1: NA 0 9.821429 3.690476 0 0.8484848 0.9188312
Обновленное решение data.table
setDT(df)[, lapply(.SD, function(x) if (all(is.na(x))) NA
else if (sum(is.na(x)) == 1) (sum(x/Ac, na.rm = TRUE))
else (sum(Ac* x, na.rm = TRUE)/sum(Ac, na.rm = TRUE)) ), .SDcols = 2:ncol(df)]
# V1 V2 V3 V4 V5 V6 V7
#1: NA 0 9.821429 3.690476 0 2.464 2.904
df <- structure(list(Ac = c(6.6, 8.4), V1 = c(NA_real_, NA_real_),
V2 = c(NA, 0), V3 = c(NA, 82.5), V4 = c(NA, 31), V5 = c(0,
0), V6 = c(5.6, 0), V7 = c(5.2, 1.1)), class = "data.frame",
row.names = c(NA,
-2L))
Спасибо. Как я могу изменить это, если только одна строка является NA, делит число на соответствующий «Ac», как показано в моем выходном столбце V3.
@Nude Для меня ваш результат отображается 82.5/8.4# [1] 9.821429
как тот, что у меня есть
только что обновил мой вывод. Для столбцов V5, V6 и V7 мне нужно разделить на сумму обоих «Ac», если в обеих строках есть числа.
@NUdu Разве код не делает это прямо сейчас. Вам нужно df %>% summarise_at(-1, list(~ if (all(is.na(.))) NA else (sum(./sum(Ac), na.rm = TRUE)) ))
Нет, код этого не делает. Например, для столбца V7 значение Output должно быть 2,904. ((5,2*6,6)+(1,1*8,4))/(6,6+8,4). Этот метод, только если данные существуют в обеих строках, в противном случае ваш метод правильный.
@NUdu Итак, вам нужен суммарный продукт
да. ТОЛЬКО ЕСЛИ в обеих строках есть числа, в противном случае разделите на соответствующее значение «Ac».
@NUdu Как насчет этого df %>% summarise_at(-1, list(~ if (all(is.na(.))) NA else (sum(Ac* ., na.rm = TRUE)/sum(Ac, na.rm = TRUE)) )) V1 V2 V3 V4 V5 V6 V7 1 NA 0 46.2 17.36 0 2.464 2.904
Нет. Например, ответ для столбца V3 должен быть 9,82 (82,5/8,4), потому что данные есть только в одной строке. Но V6, V7 верны, когда в обеих строках есть данные. Я предпочитаю метод таблицы данных.
@NUdu Непонятна логика. Вы делаете 82.5/8.4
как насчет части умножения?
@NUdu Может быть это df %>% summarise_at(-1, list(~ if (all(is.na(.))) NA else if (sum(is.na(.)) == 1) (sum(./Ac, na.rm = TRUE)) else (sum(Ac* ., na.rm = TRUE)/sum(Ac, na.rm = TRUE)) )) V1 V2 V3 V4 V5 V6 V7 1 NA 0 9.821429 3.690476 0 2.464 2.904
Спасибо. Именно этого я и добиваюсь. Не могли бы вы помочь мне с ответом таблицы данных, пожалуйста?
V1 должен быть NA и каким будет подход к таблице данных.