2017-06-05 55 views
1

變量錯誤地輸入到多列,例如:「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

這是一個基本的解決方案,即沒有包。

首先定義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 
+0

感謝您仔細解釋它! – LLL

0

我們不妨用splitstackshape

library(splitstackshape) 
nm1 <- sub("_\\d+", "", names(dataf1)) 
tbl <- table(nm1) > 1 
merged.stack(dataf1, var.stubs = names(tbl)[tbl], sep="_") 
0

我不知道你的例子是正確的。例如,在第三行中,您已經獲得了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 
+0

我要確保,如果給定的人的年齡已經進入了既是65(age_1)和92(age_3),輸出爲NA(盡我所能」要確定哪個年齡是正確的,我希望能夠將這個觀察/行列出來)。謝謝! – LLL

+0

上面編輯了我的答案。您可以對條目進行計數並刪除任何重複的行 – NeilC