Возвращает имя переменной, которая удовлетворяет условию только для числовых переменных - PullRequest
0 голосов
/ 12 марта 2019

Я пытаюсь создать новую переменную в моем фрейме данных, которая возвращает имя переменной, для которой выполняется условие, однако у меня также есть переменная chr в наборе данных, поэтому необходимо применить какую-то числовую оболочку.

Набор данных до:

          ChrV   |   V1  |   V2  |   V3       
 Obs 1 |  chr1   |  <b>0.65</b> |  0.30 |  0.40
 Obs 2 |  chr2   |  0.35 |  <b>0.75</b> |  0.42
 Obs 3 |  chr3   |  0.10 |  0.43 |  <b>0.80</b>

Мое решение:

  • Сохранить переменную chr.

    ChrV <- ds$ChrV
    
  • Удалить переменную chr из набора данных (альтернатива числовой оболочке)

    ds$ChrV <- NULL
    
  • Создать новый столбец - применить ко всем строкам набора данных: функция - вставить имена столбцов, для которых абсолютное значение x больше или равно 0,5.

    ds$V4 <- apply(ds, 1, function(x) paste(names(which(abs(x) >= 0.5))))
    
  • Привязать переменную chr к набору данных.

    ds <- cbind(ChrV, ds)
    

Выход:

          ChrV   |   V1  |   V2  |   V2  |   V4       
 Obs 1 |  chr1   |  <b>0.65</b> |  0.30 |  0.40 |  <b>Var 1</b>
 Obs 2 |  chr2   |  0.35 |  <b>0.75</b> |  0.42 |  <b>Var 2</b>
 Obs 3 |  chr3   |  0.10 |  0.43 |  <b>0.80</b> |  <b>Var 3</b>

Моя проблема:

Хотя мое решение работает, мне нужно найти более элегантное решение, которое игнорирует переменную chr (поэтому оно учитывает только числовые переменные, и мне не нужно удалять переменные и связывать их позже), и это также применимо к любому набору данных независимо от количества столбцов и строк.

dput (DS)

structure(list(
ChrV = c("chr1", "chr2", "chr3"), 
V1 = c(3, 2, 1), 
V2 = c(1, 3, 2), 
V3 = c(1, 2, 3)), 
row.names = c(NA, -6L), 
class = c("data.table", "data.frame"),
 .internal.selfref = <pointer: 0x0000000002541ef0>)   

Ответы [ 3 ]

1 голос
/ 12 марта 2019

Вы можете установить подкадр данных в функции применения:

ds$V4 <- apply(ds[colnames(ds) != "ChrV"], 1, function(x) 
paste(names(which(abs(x) >= 0.5))))

EDIT

Для класса data.frame, удаление пасты и поднабор вывода apply:

> ds <- data.frame(
+   ChrV = c("chr1", "chr2", "chr3"), 
+   V1 = c(3, 2, 1), 
+   V2 = c(1, 3, 2), 
+   V3 = c(1, 2, 3))
> 
> 
> ds$V4 <- apply(ds[colnames(ds) != "ChrV"], 1, function(x) {
+   names(which(abs(x) >= 0.5))
+ })[,1]
> 
> ds
  ChrV V1 V2 V3 V4
1 chr1  3  1  1 V1
2 chr2  2  3  2 V2
3 chr3  1  2  3 V3
> 

Bye!

1 голос
/ 12 марта 2019

Вы все еще можете сделать это с max.col

ds$V4 <- paste("Var", max.col(abs(ds[2:4]) > 0.5))

df
#     ChrV   V1   V2   V3    V4
#Obs1 chr1 0.65 0.30 0.40 Var 1
#Obs2 chr2 0.35 0.75 0.42 Var 2
#Obs3 chr3 0.10 0.43 0.80 Var 3

Или, если вы хотите, чтобы имена столбцов

ds$V4 <- names(ds)[2:4][max.col(abs(ds[2:4]) > 0.5)]

Если вы хотите динамически выбирать только числовые столбцы, мы можем использовать Filter, как предложено @ markus

new_ds <- Filter(is.numeric, ds)
ds$V4 <- names(new_ds)[max.col(abs(new_ds) > 0.5)]
1 голос
/ 12 марта 2019

Если приемлемо tidyverse решение, вы можете сделать это следующим образом:

library(tidyverse)

df %>%
  rownames_to_column() %>%
  gather(cname, val, V1:V3) %>%
  group_by(ChrV) %>%
  mutate(V4 = cname[abs(as.numeric(val)) >= .5] %>% str_c(collapse = ' ')) %>%
  spread(cname, val)
...