多列处理和动态命名新列
Multiple columns processing and dynamically naming new columns
变量被错误地输入到多个列中,例如:"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"等)。
谢谢!
我们可以试试 splitstackshape
library(splitstackshape)
nm1 <- sub("_\d+", "", names(dataf1))
tbl <- table(nm1) > 1
merged.stack(dataf1, var.stubs = names(tbl)[tbl], sep="_")
我不确定你举的例子是否正确。例如,在第三行中,您有 age_1 和 age_3 的值,然后在该行的所需输出 NA 中。
如果我已经理解您要执行的操作,那么如果您将列转置为行、修复它们然后再次转置回来,就会容易得多。尝试使用 dplyr 和 tidyr 的 'tidyverse' 作为起点。
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() 行使其成为 运行,因为您在同一行中有多个值。如果您只有一个值(我认为您应该这样做?),那么您可以删除这两行。没有它们会更好,因为如果您的数据有误,它就不会 运行。
编辑下面的评论。这将使任何重复的条目不适用。
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
这是基本解决方案,即没有包。
首先定义 get_only
,当给定一个列表时,它会将其转换为 data.frame 并将 get_only
应用于每一行。当给定一个向量时,它 returns 其中的单个非 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
变量被错误地输入到多个列中,例如:"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"等)。
谢谢!
我们可以试试 splitstackshape
library(splitstackshape)
nm1 <- sub("_\d+", "", names(dataf1))
tbl <- table(nm1) > 1
merged.stack(dataf1, var.stubs = names(tbl)[tbl], sep="_")
我不确定你举的例子是否正确。例如,在第三行中,您有 age_1 和 age_3 的值,然后在该行的所需输出 NA 中。
如果我已经理解您要执行的操作,那么如果您将列转置为行、修复它们然后再次转置回来,就会容易得多。尝试使用 dplyr 和 tidyr 的 'tidyverse' 作为起点。
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() 行使其成为 运行,因为您在同一行中有多个值。如果您只有一个值(我认为您应该这样做?),那么您可以删除这两行。没有它们会更好,因为如果您的数据有误,它就不会 运行。
编辑下面的评论。这将使任何重复的条目不适用。
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
这是基本解决方案,即没有包。
首先定义 get_only
,当给定一个列表时,它会将其转换为 data.frame 并将 get_only
应用于每一行。当给定一个向量时,它 returns 其中的单个非 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