Как использовать R для проверки согласованности данных (убедитесь, что нет противоречий между регистром и значением)?

Допустим, у меня есть:

Person   Movie    Rating
Sally    Titanic  4
Bill     Titanic  4
Rob      Titanic  4
Sue      Cars     8
Alex     Cars     **9**
Bob      Cars     8

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

Возможно, я мог бы заставить R выполнить логическую проверку, если все случаи Movie соответствуют первому рейтингу его первой итерации? Для всего, что возвращает «нет», я могу посмотреть это вручную? Как бы я написал эту функцию?

Спасибо


person Hutchins    schedule 13.12.2014    source источник
comment
Почему фильм всегда должен иметь одинаковый рейтинг для каждого человека? (Что, если бы Алекс любил Тачки больше, чем Сью или Боб?)   -  person David Robinson    schedule 13.12.2014
comment
Вы хотите удалить Алекса или исправить его значение Rating? Кроме того, вы всегда предполагаете, что большинство правы?   -  person David Arenburg    schedule 13.12.2014


Ответы (4)


Вот data.table решение

Определите функцию

Myfunc <- function(x) {
  temp <- table(x)  
  names(temp)[which.max(temp)]
}

library(data.table)

Создайте столбец с правильным рейтингом (по ссылке)

setDT(df)[, CorrectRating := Myfunc(Rating), Movie][]
#    Person   Movie Rating CorrectRating
# 1:  Sally Titanic      4             4
# 2:   Bill Titanic      4             4
# 3:    Rob Titanic      4             4
# 4:    Sue    Cars      8             8
# 5:   Alex    Cars      9             8
# 6:    Bob    Cars      8             8

Или если вы хотите удалить "плохие" оценки

df[Rating == CorrectRating][]
#    Person   Movie Rating CorrectRating
# 1:  Sally Titanic      4             4
# 2:   Bill Titanic      4             4
# 3:    Rob Titanic      4             4
# 4:    Sue    Cars      8             8
# 5:    Bob    Cars      8             8
person David Arenburg    schedule 13.12.2014

Похоже, что в каждой группе, определяемой параметром «Фильм», вы ищете любые экземпляры рейтинга, которые не совпадают с наиболее распространенным значением.

Вы можете решить эту проблему, используя dplyr (который хорош для «группировки по одному столбцу, а затем выполняет операцию в каждой группе») вместе с функцией «Режим» определенный в этом ответе, который находит наиболее распространенный элемент в векторе:

Mode <- function(x) {
  ux <- unique(x)
  ux[which.max(tabulate(match(x, ux)))]
}

library(dplyr)
dat %>% group_by(Movie) %>% filter(Rating != Mode(Rating))

Это находит все случаи, когда строка не согласуется с остальной частью группы. Если вместо этого вы хотите удалить их, вы можете сделать следующее:

newdat <- dat %>% group_by(Movie) %>% filter(Rating == Mode(Rating))

Если вы хотите исправить их, выполните

newdat <- dat %>% group_by(Movie) %>% mutate(Rating = Mode(Rating))

Вы можете проверить вышеизложенное с помощью воспроизводимой версии ваших данных:

dat <- data.frame(Person = c("Sally", "Bill", "Rob", "Sue", "Alex", "Bob"),
                  Movie = rep(c("Titanic", "Cars"), each = 3),
                  Rating = c(4, 4, 4, 8, 9, 8))
person David Robinson    schedule 13.12.2014

Если цель состоит в том, чтобы увидеть, все ли значения в группе одинаковы (или есть некоторые различия), то это может быть простое приложение tapply (или aggregate и т. д.), используемое с функцией, такой как var (или вычисление диапазон). Если все значения одинаковы, то дисперсия и диапазон будут равны 0. Если это любое другое значение (за пределами ошибки округления), то должно быть другое значение. Функция which может помочь идентифицировать группу/индивида.

tapply(dat$Rating, dat$Movie, FUN=var)
which(.Last.value > 0.00001)
tapply(dat$Rating, dat$Movie, FUN=function(x)diff(range(x)))
which(.Last.value != 0)

which( abs(dat$Rating - ave(dat$Rating, dat$Movie)) > 0)
which.max( abs(dat$Rating - ave(dat$Rating, dat$Movie)) )
dat[.Last.value,]
person Greg Snow    schedule 13.12.2014

Я бы добавил переменную для режима, чтобы я мог видеть, происходит ли что-то странное с данными, например, отсутствующие данные, текст, множество разных ответов вместо редкой аномалии и т. д. Я использовал «x» в качестве вашего набора данных

# one of many functions to find mode, could use any other
modefunc <- function(x){
  names(table(x))[table(x)==max(table(x))]
}

# add variable for mode split by Movie
x$mode <- ave(x = x$Rating,x$Movie,FUN = modefunc)

# do whatever you want with the records that are different
x[x$Rating != x$mode, ]

Если вам нужна другая функция для режима, попробуйте другие функции для режима< /а>

person ARobertson    schedule 14.12.2014