Проверять строку, если значение присутствует в столбце, и обновлять новую строку столбца - PullRequest
0 голосов
/ 12 декабря 2018

В R, как я могу проверить для каждой строки, присутствует ли какое-либо значение в списке (например, 2, 3 или 4) в одном из трех столбцов, а затем изменить эту строку в четвертом столбце?

Скажем, у меня есть df:

 A B C D
 1 1 1
 2 1 1
 3 1 1

Я хотел бы написать (без цикла for), если строка n (столбец A или B или C) == 2 или 3 или 4, тогда D [1,] = 1, иначе = 0

По существу, проверьте строку, если мои числа присутствуют в каком-либо из трех определенных столбцов, и, если это так, обновите четвертый столбец с 1, если не с 0.

Спасибо

Ответы [ 6 ]

0 голосов
/ 12 декабря 2018

Вы можете использовать apply:

vec <- 2:4
df1$D <- apply(df1,1, function(x) any(vec %in% x)) +0
#   A B C D
# 1 1 1 1 0
# 2 2 1 1 1
# 3 3 1 1 1

или версию tidyverse, возможно, более эффективную, так как apply включает некоторые преобразования матрицы:

library(tidyverse)
df1 %>% mutate(D = pmap_int(.,~any(vec %in% .)))
#   A B C D
# 1 1 1 1 0
# 2 2 1 1 1
# 3 3 1 1 1

данные

df1 <- data.frame(A = c(1, 2,3), 
                   B = c(1, 1, 1), 
                   C = c(1, 1, 1))
0 голосов
/ 12 декабря 2018

Параметризован для имен столбцов и чисел интереса.

library(tidyverse)

data <-
  data.frame(
    A = c(1, 2, 3), 
    B = c(1, 1, 1), 
    C = c(1, 1, 1)
  )

nums <- c(2, 3, 4)
cols <- c('A', 'B', 'C')

data$D <-
  data[, cols] %>%
  map(~.x %in% nums) %>%
  reduce(`|`)
0 голосов
/ 12 декабря 2018

Один из способов сделать это в tidyverse:

df %>%
 rowid_to_column() %>% #Creating an unique row ID
 gather(var, val, -rowid) %>% #Transforming the data from wide to long
 group_by(rowid) %>% #Grouping
 mutate(D = ifelse(any(val %in% c(2, 3, 4)), 1, 0)) %>% #Testing whether any value from a given row is in the specified list 
 spread(var, val) %>% #Returning the data to wide format
 ungroup() %>%
 select(-rowid) #Deleting the redundant variable

      D     A     B     C
  <dbl> <int> <int> <int>
1    0.     1     1     1
2    1.     2     1     1
3    1.     3     1     1
0 голосов
/ 12 декабря 2018

Вот как вы можете использовать dplyr:

library(dplyr)
test <- data.frame(A = c(1, 2, 3), 
                   B = c(1, 1, 1), 
                   C = c(1, 1, 1))

testColumns <- c(2, 3, 4)                         # Values you want to flag 

Теперь, когда у нас есть фрейм данных и вектор со значениями, которые мы хотим пометить в новом столбце, давайте использовать rowwise() дляпопросите R просмотреть каждую строку фрейма данных, а затем комбинацию mutate() для создания нового столбца D , основанного на различных случаях.
Мы указываем тестовые случаи, а затемих желаемые значения, используя case_when().

Вместо присвоения результата нашего канала новому объекту, давайте используем прямой канал %<>%.

Вот как мы это делаем:

test %<>%                                         # Use forward pipe
  rowwise() %>%                                   # Look at test on a 'by row' basis'
  mutate(D = case_when(A %in% testColumns ~ 1,    # use mutate to create a new column D
                       B %in% testColumns ~ 1,
                       C %in% testColumns ~ 1, 
                       TRUE               ~ 0))

Это дает нам следующую таблицу:

print(test)
## A tibble: 3 x 4
#      A     B     C     D
#  <dbl> <dbl> <dbl> <dbl>
#1     1     1     1     0
#2     2     1     1     1
#3     3     1     1     1

Вот несколько полезных ссылок для некоторых функций, которые мы использовали:
mutate()
rowwise()
case_when()

0 голосов
/ 12 декабря 2018

Вот способ сделать это, используя data.table:

library(data.table)
test <- data.table(A = c(1, 2,3), 
                   B = c(1, 1, 1), 
                   C = c(1, 1, 1))
checkValues <- c(2, 3, 4)

test[, c("D"):= Reduce(`|`, lapply(.SD, function(x){x %in% checkValues}))]

test
   A B C     D
1: 1 1 1 FALSE
2: 2 1 1  TRUE
3: 3 1 1  TRUE

Было бы легко заменить FALSE=0, TRUE=1 (заменить Reduce( | , lapply(.SD, function(x){x %in% c(2, 3, 4)})) на as.numeric(Reduce(| , lapply(.SD, function(x){x %in% c(2, 3, 4)}))), но, похоже, вы используете D для хранения логического значения, поэтому для меня было бы целесообразно иметь его в качестве логического вектора.

Это также обновляет test, чтобы иметь столбецD по ссылке, которая более эффективна.

Можно также рассмотреть два ответа: Поиск строк, содержащих значение (или значения) в любом столбце и Добавить несколько столбцов в таблицу data.table за один вызов функции?

0 голосов
/ 12 декабря 2018

Только с этими тремя условиями вы можете выполнить

df1$D <- as.integer(rowSums(df1 == 2 | df1 == 3 | df1 == 4) >= 1) # or maybe df1 >=2 & df1 <= 4
df1
#  A B C D
#1 1 1 1 0
#2 2 1 1 1
#3 3 1 1 1

data

df1 <- structure(list(A = 1:3, B = c(1L, 1L, 1L), C = c(1L, 1L, 1L)), .Names = c("A", 
"B", "C"), class = "data.frame", row.names = c(NA, -3L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...