变量被错误地输入到多个列中,例如:“aaa_1”,“aaa_2”和“aaa_3”,或“ccc_1”,“ccc_2”和“ccc_3”。需要创建单个新列(例如“aaa”)或者“ccc”)。有些变量目前只在一列中(“hhh_1”),但可以添加更多列(hhh_2等)。
这就是我得到的:
aaa_1 <- c(43, 23, 65, NA, 45)
aaa_2 <- c(NA, NA, NA, NA, NA)
aaa_3 <- c(NA, NA, 92, NA, 82)
ccc_1 <- c("fra", NA, "spa", NA, NA)
ccc_2 <- c(NA, NA, NA, "wez", NA)
ccc_3 <- c(NA, "ija", NA, "fda", NA)
ccc_4 <- c(NA, NA, NA, NA, NA)
hhh_1 <- c(183, NA, 198, NA, 182)
dataf1 <- data.frame(aaa_1,aaa_2,aaa_3,ccc_1,ccc_2, ccc_3,ccc_4,hhh_1)
这就是我想要的:
aaa <- c(43, 23, NA, NA, NA)
ccc <- c("fra", "ija", "spa", NA, NA)
hhh <- c(183, NA, 198, NA, 182)
dataf2 <- data.frame(aaa,ccc,hhh)
需要一般解决方案,因为有大约100个变量(例如“aaa”,“hhh”,“ccc”,“ttt”,“eee”,“hhh”等)。
谢谢!
答案 0 :(得分:0)
我们可以尝试使用splitstackshape
library(splitstackshape)
nm1 <- sub("_\\d+", "", names(dataf1))
tbl <- table(nm1) > 1
merged.stack(dataf1, var.stubs = names(tbl)[tbl], sep="_")
答案 1 :(得分:0)
我不确定你的例子是对的。例如,在第三行中,您获得了age_1和age_3的值,然后是该行的所需输出NA。
如果我已经理解了您尝试做的事情,那么将列转换为行,修复它们然后再转置回来会更容易。尝试使用&#39; tidyverse&#39;作为起点。 dplyr和tidyr。
library(tidyverse)
library(stringr)
age_1 <- c(43, 23, 65, NA, 45)
age_2 <- c(NA, NA, NA, NA, NA)
age_3 <- c(NA, NA, 92, NA, 82)
country_1 <- c("fra", NA, "spa", NA, NA)
country_2 <- c(NA, NA, NA, "wez", NA)
country_3 <- c(NA, "ija", NA, "fda", NA)
country_4 <- c(NA, NA, NA, NA, NA)
hight_1 <- c(183, NA, 198, NA, 182)
dataf1 <- data.frame(age_1,age_2,age_3,country_1,country_2, country_3,country_4,hight_1)
data <- dataf1 %>%
mutate(row_num = row_number()) %>% #create a row number to track values
gather(key, value, -row_num) %>% #flatten your data
drop_na() %>% #drop na rows
mutate(key = str_replace(key, "_.", "")) %>% #remove the '_x' part of names
group_by(row_num) %>%
top_n(1) %>%
spread(key, value) #pivot back to columns
对于您的示例,您需要group_by()和top_n()行才能使其运行,因为您在同一行中有多个值。如果你只有一个值(我认为你应该这样做?)那么你可以删除这两行。没有它们会更好,因为如果你的数据错误,它就不会运行。
编辑以下评论。这将使任何重复的条目NA。
data <- dataf1 %>%
mutate(row_num = row_number()) %>% #create a row number to track values
gather(key, value, -row_num) %>% #flatten your data
drop_na() %>% #drop na rows
mutate(key = str_replace(key, "_.", "")) %>% #remove the '_x' part of names
group_by(row_num, key) %>%
mutate(count = n()) %>% #count how many entries for each row/key combo
mutate(value = ifelse(count > 1, NA, value)) %>% #set NA for rows with duplicates
drop_na() %>%
spread(key, value) %>% #pivot back to columns
select(-count) #drop the `count` variable
答案 2 :(得分:0)
这是一个基本解决方案,即没有包裹。
首先定义get_only
,当给定列表时,将其转换为data.frame并将get_only
应用于每一行。当给定一个向量时,它返回单个非NA,如果不存在,则返回NA。
将root
定义为没有后缀的列名。
将数据框转换为列列表,按root
对其进行分组,并将get_only
应用于每个此类组。
最后,将结果列表转换为数据框。
get_only <- function(x) UseMethod("get_only")
get_only.list <- function(x) apply(data.frame(x), 1, get_only)
get_only.default <- function(x) if (sum(!is.na(x)) == 1) na.omit(x) else NA
root <- sub("_.*", "", names(dataf1))
as.data.frame(lapply(split(as.list(dataf1), root), FUN = get_only))
,并提供:
age country hight
1 43 fra 183
2 23 ija NA
3 NA spa 198
4 NA <NA> NA
5 NA <NA> 182