Начиная с кадра данных в R, как показано ниже (df):
year_1 <- c('James','Mike','Jane', NA)
year_2 <- c('Evelyn', 'Jackson', 'James', 'Avery')
year_3 <- c('Harper', 'Avery', NA, NA)
df <- data.frame(year_1, year_2, year_3)
... Я хотел бы преобразовать его во что-то вроде df1 (конечно, у меня есть сотни элементов в моем исходном фрейме данных, поэтому я не могу идти вручную)
names <- c('James','Mike','Jane','Evelyn', 'Jackson', 'Avery', 'Harper')
year_1 <- c('YES','YES','YES', 'NO', 'NO', 'NO', 'NO')
year_2 <- c('YES','NO','NO', 'YES', 'YES', 'YES', 'NO')
year_3 <- c('NO','NO','NO', 'NO', 'NO', 'YES', 'YES')
df_1 <- data.frame(year_1, year_2, year_3)
rownames(df_1) <- names
Я пытался:
Есть идеи?
Спасибо!!
"Ошибка в stack.data.frame(df): не выбрано ни одного векторного столбца"
Убедитесь, что ваши столбцы являются символами, а не факторами.
вот вариант с tidyverse
, где мы преобразуем данные в «длинный» формат pivot_longer
, получаем строки distinct
, создаем столбец «ДА» и возвращаемся к «широкому» с помощью pivot_wider
library(dplyr)
library(tidyr)
library(tibble)
df %>%
pivot_longer(cols = everything(), values_drop_na = TRUE) %>%
distinct %>%
mutate(new = 'YES') %>%
pivot_wider(names_from = name, values_from = new, values_fill = 'NO') %>%
column_to_rownames("value")
-выход
# year_1 year_2 year_3
#James YES YES NO
#Evelyn NO YES NO
#Harper NO NO YES
#Mike YES NO NO
#Jackson NO YES NO
#Avery NO YES YES
#Jane YES NO NO
Супер ответ. Очень быстро и чисто!! Большое спасибо
Как насчет этого?
sapply(df, function(x) sapply(na.omit(unique(unlist(df))), `%in%`, x))
# year_1 year_2 year_3
# James TRUE TRUE FALSE
# Mike TRUE FALSE FALSE
# Jane TRUE FALSE FALSE
# Evelyn FALSE TRUE FALSE
# Jackson FALSE TRUE FALSE
# Avery FALSE TRUE TRUE
# Harper FALSE FALSE TRUE
Базовый вариант R с использованием stack
+ table
> as.data.frame(ifelse(table(stack(df)) == 1, "YES", "NO"))
year_1 year_2 year_3
Avery NO YES YES
Evelyn NO YES NO
Harper NO NO YES
Jackson NO YES NO
James YES YES NO
Jane YES NO NO
Mike YES NO NO
+1, но я бы, вероятно, использовал lapply(df, as.character)
, учитывая их комментарий под их вопросом, и замену []
вместо ifelse
. Что-то вроде: x <- table(stack(lapply(df, as.character))) + 1; x[] <- c("NO", "YES")[x]; x
.
@ A5C1D2H2I1M1N2O1R2T1 Да, это имеет смысл, и мы можем использовать type.convert(df,as.is = TRUE)
, если это возможно
Чтобы предложить другой вариант, сначала мы можем извлечь уникальные имена из df, используя вложенный цикл for. Мы проверяем, есть ли имя уже в нашем списке, и дополнительно проверяем, ищем ли мы NA.
people<-c()
for (i in 1:length(colnames(df))){
for (j in 1:length(df[,1])){
pers<-df[j,i]
if (!(pers %in% people)){
if (!is.na(pers)){
people<-c(people,toString(pers))
}
}
}
}
Отсюда мы можем повторять простую проверку %in% каждый год и объединять ее в полный фрейм данных. Приведенные выше ответы, вероятно, более просты, но я обнаружил, что такой код полезен, если вам нужно внести другие небольшие изменения в данные, когда они проходят через сценарий.
for (i in 1:length(colnames(df))){
colname<-colnames(df)[i]
peoplein<-people %in% df[,i]
if (i == 1){
df1<-cbind(people,peoplein)
colnames(df1)[i+1]<-colname
} else {
df1<-cbind(df1,peoplein)
colnames(df1)[i+1]<-colname
}
}
Полученный df1 показан ниже.
people year_1 year_2 year_3
[1,] "James" "TRUE" "TRUE" "FALSE"
[2,] "Mike" "TRUE" "FALSE" "FALSE"
[3,] "Jane" "TRUE" "FALSE" "FALSE"
[4,] "Evelyn" "FALSE" "TRUE" "FALSE"
[5,] "Jackson" "FALSE" "TRUE" "FALSE"
[6,] "Avery" "FALSE" "TRUE" "TRUE"
[7,] "Harper" "FALSE" "FALSE" "TRUE"
Вы можете сделать что-то вроде
as.data.frame.matrix(table(stack(df)))
.