2017-06-05 4 views
1

"aaa_1"、 "aaa_2"、 "aaa_3"、または "ccc_1"、 "ccc_2"、 "ccc_3"などの複数の列に変数を誤って入力しています。いくつかの変数は現在( "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を返します。

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

てみてください。たとえば、3行目には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を()の行は、同じ行に複数の値を持っているので、それが実行にする必要があります。あなたは1つの値しか持っていなければ(あなたはすべきだと思いますか?)、この2つの行を削除することができます。あなたのデータが間違っていると実行されないので、それがなければより良いでしょう。

下記のコメントを編集してください。これにより、複製された項目はすべて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 
+0

は私が与えられた人の年齢は、両方の65(age_1)として入力されている場合は92(age_3)、出力はNAであることを確認する(「私はできる限りどの年代が正しいか確かめて、私はその観察/行を裏付けることができるようにしたい)。ありがとう! – LLL

+0

上記の私の答えを編集しました。あなたはエントリを数え、重複している行を削除することができます – NeilC

関連する問題