Фильтрация наблюдений с использованием многомерных условий столбца - PullRequest
0 голосов
/ 24 октября 2019

Я не очень опытный пользователь R, поэтому посоветуйтесь, как оптимизировать то, что я построил и в каком направлении двигаться дальше.

У меня есть один эталонный фрейм данных,он содержит четыре столбца с целочисленными значениями и одним идентификатором.

df <- matrix(ncol=5,nrow = 10)
colnames(df) <- c("A","B","C","D","ID")
# df
for (i in 1:10){
        df[i,1:4] <- sample(1:5,4, replace = TRUE)
}
df <- data.frame(df)
df$ID <- make.unique(rep(LETTERS,length.out=10),sep='')
df
 A B C D ID
1  2 4 3 5  A
2  5 1 3 5  B
3  3 3 5 3  C
4  4 3 1 5  D
5  2 1 2 5  E
6  5 4 4 5  F
7  4 4 3 3  G
8  2 1 5 5  H
9  4 4 1 3  I
10 4 2 2 2  J

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

df.man <- data.frame(matrix(ncol=5,nrow=1))
colnames(df.man) <- c("A","B","C","D","ID")
df.man$ID <- c("man")
df.man$A <- 4
df.man$B <- 4
df.man$C <- 3
df.man$D <- 4
df.man
 A B C D  ID
 4 4 3 4 man

Я хочу фильтровать строки по ссылке последовательно, следуя правилам:

Если в целом есть точное совпадениестрока между ссылка таблица и руководство , чем извлечь эти (те) из ссылки и показать мне эту строку, если нет, то уменьшите количество соответствующих столбцов справа налево, пока не будет совпадение, ноне менее чем между двумя переменными (столбцы A, B).

Итак, с учетом моих ограниченных знаний, я написал следующее:

# subtraction manual from reference 
df <- df %>% dplyr::mutate(Adiff=A-df.man$A)%>%
        dplyr::mutate(Bdiff=B-df.man$B)%>% 
        dplyr::mutate(Cdiff=C-df.man$C) %>% 
        dplyr::mutate(Ddiff=D-df.man$D)

# check manually how much in a row has zero difference and filter those
ifelse(nrow(df%>%filter(Adiff==0 & Bdiff==0 & Cdiff==0 & Ddiff==0)) != 0,
       df0<-df%>%filter(Adiff==0 & Bdiff==0 & Cdiff==0 & Ddiff==0),
       ifelse(nrow(df%>%filter(Adiff==0 & Bdiff==0 & Cdiff==0)) != 0,
              df0<-df%>%filter(Adiff==0 & Bdiff==0 & Cdiff==0),
              ifelse(nrow(df%>%filter(Adiff==0 & Bdiff==0)) != 0,
              df0<-df%>%filter(Adiff==0 & Bdiff==0),
              "less then two exact match")
       ))

tbl_df(df0[,1:5]) 

# A tibble: 1 x 5
      A     B     C     D ID   
  <int> <int> <int> <int> <chr>
1     4     4     3     3 G    

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

Второй вопрос - Я хочу усложнить условие.

Представьте, что у нас есть набор справочных данных.

A B C D ID
2 4 3 5  A
5 1 3 5  B
3 3 5 3  C
4 3 1 5  D
2 1 2 5  E
5 4 4 5  F
4 4 3 3  G
2 1 5 5  H
4 4 1 3  I
4 2 2 2  J

Ручной ввод

A B C D ID
4 4 2 2 man

Правила фильтрации должны быть следующими:

  1. Если существует точное совпадение во всей строке между ссылка table и manual , чем извлечь эти данные из ссылки и показать мне эту строку, если нет, то уменьшить количество совпадающих столбцов справа налево до совпадения, но не между менее чем двумя переменными(столбцы A, B).

  2. Из тех строк, в которых у меня только два совпадения переменных, отфильтруйте те, которые имеют ± 1 разность в столбцах справа. Поэтому я должен был отфильтровать дела G и I из справочной таблицы из приведенного выше примера.

продолжать идти так, как я делалвыше, я бы сделал следующее:

ifelse(nrow(df0%>%filter(Cdiff %in% (-1:1) & Ddiff %in% (-1:1)))>0,
       df01 <- df0%>%filter(Cdiff %in% (-1:1) & Ddiff %in% (-1:1)),
       ifelse(nrow(df0%>%filter(Cdiff %in% (-1:1)))>0,
              df01<- df0%>%filter(Cdiff %in% (-1:1)),
       "NA"))

В конце будет около 11 столбцов, но я предполагаю, что это не имеет большого значения.

Помняэта цель - как бы вы предложили продолжить? Спасибо!

1 Ответ

0 голосов
/ 25 октября 2019

Это много, чтобы разобраться, но у меня есть некоторые идеи, которые могут быть полезны.

Во-первых, вы можете сохранить свою df матрицу и использовать названия строк для своих букв. Что-то вроде:

set.seed(2)

df

  A B C D
A 5 1 5 1
B 4 5 1 2
C 3 1 3 2
D 3 1 1 4
E 3 1 5 3
F 1 5 5 2
G 2 3 4 3
H 1 1 5 1
I 2 4 5 5
J 4 2 5 5

А для демонстрации вы можете использовать вектор для manual, так как это ввод:

# Complete match example
vec.man <- c(3, 1, 5, 3)

Для проверки на полное совпадение между ручным вводом и заданием(все 4 столбца), со всеми числами, вы можете сделать:

df[apply(df, 1, function(x) all(x == vec.man)), ]

A B C D 
3 1 5 3

Если у вас нет полного соответствия, будет рассчитываться разница между df и vec.man:

# Change example vec.man
vec.man <- c(3, 1, 5, 2)

df.diff <- sweep(df, 2, vec.man)

   A B  C  D
A  2 0  0 -1
B  1 4 -4  0
C  0 0 -2  0
D  0 0 -4  2
E  0 0  0  1
F -2 4  0  0
G -1 2 -1  1
H -2 0  0 -1
I -1 3  0  3
J  1 1  0  3

Дифференциалы, начинающиеся с и продолжающиеся с 0, будут вашими лучшими совпадениями (аналогично итерациям справа налево). Тогда вашим лучшим соответствием будет столбец первого ненулевого элемента в каждой строке:

df.best <- apply(df.diff, 1, function(x) which(x!=0)[1])

A B C D E F G H I J 
1 1 3 3 4 1 1 1 1 1 

Вы можете видеть, что наилучшим соответствием является E, которое было ненулевым в 4-м столбце (последнийколонка не совпадает). Вы можете извлечь строки, которые имеют 4 в df.best как ваши лучшие совпадения:

df.match <- df[which(df.best == max(df.best, na.rm = T)), ]

A B C D 
3 1 5 3 

Наконец, если вы хотите, чтобы все строки с самым близким соответствием +/- 1, если только 2 совпадения, вы можете проверить номериз лучших матчей (должно быть 3). Затем сравните различия с вектором c(0,0,1), который будет означать 2 совпадения, а затем отключение 3-го столбца на +/- 1:

# Example vec.man with only 2 matches
vec.man <- c(3, 1, 6, 9)

> df.match
  A B C D
C 3 1 3 2
D 3 1 1 4
E 3 1 5 3

if (max(df.best, na.rm = T) == 3) {
  vec.alt = c(0, 0, 1)
  df[apply(df.diff[,1:3], 1, function(x) all(abs(x) == vec.alt)), ]
}

A B C D 
3 1 5 3

Это должно быть масштабируемым для 11 столбцов и 4 совпадений.

Для обобщения для различного числа столбцов @IlyaT предложил:

n.cols <- max(df.best, na.rm=TRUE) 
vec.alt <- c(rep(0, each=n.cols-1), 1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...