Удаление строк, в которых несколько столбцов равны точному числу R

Я хотел бы разделить строки, где x1 и x2 == 9. В моем реальном наборе более 200 столбцов, в которых имя столбца начинается с той же строки. Приведенный ниже фиктивный код создает меньшую выборку данных. В идеале я бы хотел сделать это с помощью пакета R data.table, если это возможно.

df <- data.frame('id'=c(1,2,3), 'x1'=c(9,9,4), 'x2'=c(9,9,4))
head(df)

# does not work, but thought perhaps I could have defined the columns via a paste and then subset where columns were equal to 9.
df[which(paste0("x", 1:2)==9), ]

Обновление: извините, если я не понял. Я знаю, что просто добавляю фильтр для x1 и x2. Проблема в том, что реальные данные состоят из более чем 200 столбцов: x1:x200. Я ищу более чистое решение, чем то, что предлагается ниже.

Поскольку вы хотите использовать data.table, я предполагаю, что эффективность имеет значение. Я бы рекомендовал использовать более крупный пример, который подойдет для тестирования. Может что то типа set.seed(47); nc = 40; nr = 5000; dt = data.table(matrix(sample(c(0, 9), size = nc * nr, replace = TRUE, prob = c(1, 99)), nrow = nr)); dt$id = 1:nr; setkey(dt, id)

Gregor Thomas 16.07.2018 22:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
220
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Пытаться:

df[df$x1 == 9 & df$x2 == 9,]

РЕДАКТИРОВАТЬ (неправильно понял, теперь это должно сработать):

for (i in 2:200) {df = df[df[,i] == 9,]}

Проблема в том, что у меня 200 столбцов с аналогичным соглашением об именах ... так что x1: x200, что сделало бы это решение беспорядочным.

yokota 16.07.2018 22:28

Что-то вроде этого, может быть?

df[apply(df[, paste0("x", 1:200)] == 9, 1, all), ]

Это на самом деле чище, чем то, что я нашел. Считаю это лучшим ответом. Спасибо, Грегор.

yokota 16.07.2018 22:47

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

Gregor Thomas 16.07.2018 22:49

Хорошо. Звучит разумно. Еще раз спасибо за ответ. Сэкономил несколько волос.

yokota 16.07.2018 22:51

подумайте о том, чтобы принять ответ, если он решит вашу проблему @yokota (зеленая галочка слева)

Moody_Mudskipper 17.07.2018 00:01

@Moody_Mudskipper yokota принял мой ответ через несколько минут после того, как я его разместил. Я рекомендовал им подождать несколько часов, если у кого-то есть лучшее решение.

Gregor Thomas 17.07.2018 00:02

Хорошо, но я был бы удивлен, возможно, rowSums будет быстрее, чем apply, или вы могли бы использовать startsWith, поэтому он не зависит от суффиксов строк, судя по всему, это довольно просто.

Moody_Mudskipper 17.07.2018 00:08

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

# Select all columns that have (colnames) "x"  
col.names <- grep("x",colnames(df), value = TRUE)
# Select rows where row == 9
sel <- apply(df[,col.names], 1, function(row) 9 %in% row)
df[sel,]

И на выходе

  id x1 x2
1  1  9  9
2  2  9  9

Спасибо, @Miha. Это решение тоже хорошо работает. Я воспользуюсь советом Грегора и к концу дня попробую протестировать различные решения, чтобы получить «ответ».

yokota 16.07.2018 22:51

Разница между этим ответом и моим ответом заключается в том, как строятся имена столбцов - это хорошо для сопоставления с образцом, мое - для их построения. Основная часть ответа - apply - мой ответ применяет функцию all, здесь используется %in% - так что мой вернет ИСТИНА, только если все столбцов равно 9, этот возвращает ИСТИНА, если любой столбцов равно 9. Вам нужно уточнить какой вы хотите.

Gregor Thomas 16.07.2018 23:13

Расплав может позволить вам не записывать каждый столбец (для вашего случая> 2 столбцов):

> aTbl = as.data.table(df)

> aTbl[, all9sP := F]
> aTbl[, .SD
       ][, !'all9sP'
       ][, melt(.SD, id.vars=c('id'))
       ][, NVars := uniqueN(variable)
       ][value == 9
       ][, .(N9s=.N), .(id, NVars)
       ][, all9sP := N9s == NVars
       ][, aTbl[.SD, all9sP := i.all9sP, on=.(id)]
       ][all9sP == T
       ][, all9sP := NULL
       ][, .SD
       ]

   id x1 x2
1:  1  9  9
2:  2  9  9
> 
Ответ принят как подходящий

Если вам нужно эффективное базовое решение R, я бы просто использовал rowSums, например.

cols <- paste0("x", 1:2) 
df[rowSums(df[cols] == 9) == length(cols), ]
#   id x1 x2
# 1  1  9  9
# 2  2  9  9

Если вам нужно решение data.table, я бы использовал двоичное соединение, например

library(data.table)
setDT(df)[as.list(rep(9, length(cols))), on = cols]
#    id x1 x2
# 1:  1  9  9
# 2:  2  9  9

Данные

df <- data.frame(id = 1:3, x1 = c(9, 9, 4), x2 = c(9, 9, 4))

Спасибо за решение DT и предупреждение о применении @David Arenburg

yokota 17.07.2018 18:55

Решение с использованием data.table

Создать набор данных

ncols <- 5
cnms <- paste0("x", 1:ncols)
X <- data.table(ID = 1:1e6)
X[, (cnms) := NA_integer_]
X[, (cnms) := lapply(X = 1:ncols, sample, size = .N, x = 1:10)]

Найдите строки, в которых сумма равна 9

X1 <- X[, s := rowSums(.SD), .SDcols = cnms][s == 9, ][, s:= NULL][]
X1

Найдите строки, в которых все столбцы равны 9

X[, s := NULL]
ind <- rowSums(X[, lapply(.SD, is.element, set = 9), .SDcols = cnms])
X2 <- X[ind == length(cnms)][]
X2

Редактировать На самом деле это намного быстрее:

X[, s := NULL]
ind <- rowSums(X[, .SD , .SDcols = cnms] == 9)
X2 <- X[ind == length(cnms)][]
X2

Edit2 См. Ответ от https://stackoverflow.com/users/3001626/david-arenburg. Намного быстрее.

В tidyverse попробуйте rowwise и используйте filter как обычно

df %>% 
  rowwise() %>% 
  filter(x1 %in% 9 & x2 %in% 9 )

Source: local data frame [2 x 3]
Groups: <by row>

# A tibble: 2 x 3
     id    x1    x2
  <dbl> <dbl> <dbl>
1     1     9     9
2     2     9     9

Другие вопросы по теме