2016-04-02 4 views
1

私は非常に乱雑な家族データを扱っています。子供たちを複数の家族でグループ化することが可能です。次のようにデータが構成されています2つのベクトルの情報に基づいて重なり合うグループの相対的なサイズを特定する

famid <- c("A","A","B","C","C","D","D") 
kidid <- c("1","2","1","3","4","4","5") 
df <- as.data.frame(cbind(famid, kidid)) 

私は、その家族の中で子供たちのすべてが別にグループ化された基準に基づいて、より大きな、家族をドロップすることができた家族を識別します。例えば

ファミリーBが完全ファミリーA内に含まれているので、家族Aは、子供1と子供2ファミリーBを含有するキッド1含まれ、Iは、あるいは家族B.

をドロップする、ファミリーCは、キッド3含有家族のDにはKid 4とKid 5が含まれています。どちらの家族も完全に他の家族に含まれていないので、当分の間はどちらも落ちたくありません。

私のデータには、子供1人あたり最大6家族、家族あたり最大8人の子供がいることがあります。何千もの家族と何千人もの子供たちがいます。

私は子供1人1列、子供が関連する各家族の列、子供が関連付けられている各家族の各兄弟、追加の列を持つ非常に幅広いdata.frameを作成することでこれを解決しようとしました(sibgrp)を使用して、すべての兄弟を連結します。しかし、連結された文字列内の個々の兄弟を検索しようとしたとき、私はこれを行う方法がわかりませんでした。greplはパターン引数としてベクトルをとらないでしょう。

その後、交差や類似の機能を調べ始めましたが、ベクトル内の他の観測値に対する観測値ではなく、ベクトル全体を比較します。 (意味 - 文字列df[1,2]と文字列df[1,3]の間の交差点を見つけることができません。代わりに、df[2]df[3]の間の交差を識別します)。

このアプローチに対応するために私の思考を変えようとしました。少なくとも1つの兄弟が共有されていることを既に知っていると仮定して、兄弟のベクトルを互いに比較することができました。私はこれをやっても、どれくらいの種類の家族があるか、どれくらいの人が共通の子供でも互いに関係していない場合、どのようにして始めるかを理解できませんでした。

私はここで何が欠けていますか?フィードバックをいただければ幸いです。ありがとうございました!

答えて

0

この機能は、タスクの実行にも使用できます。これは、削除可能なファミリの名前を含む文字ベクトルを返します。

test_function <- function(dataset){ 

## split the kidid on the basis of famid 
kids_family <- split.default(dataset[['kidid']],f = dataset[['famid']]) 

family <- names(kids_family) 

## This function generates all the possible combinations if we select any two families from family 
combn_family <- combn(family,2) 

family_removed <- character(0) 
apply(combn_family,MARGIN = 2, function(x){ 

    if (length(setdiff(kids_family[[x[1]]],kids_family[[x[2]]])) == 0) 
    family_removed <<- c(family_removed,x[1]) 
    else if (length(setdiff(kids_family[[x[2]]],kids_family[[x[1]]])) == 0) 
    family_removed <<- c(family_removed,x[2]) 

}) 

return (family_removed) 
} 
> df <- data.frame(famid = c("A","A","B","C","C","D","D", "E", "E", "E", "F", "F"), 
+     kidid = c(1, 2, 1, 3, 4, 4, 5, 7, 8, 9, 7, 9)) 
> test_function(df) 
[1] "B" "F" 
+0

詳細を教えてください。 –

+0

@VincentBonhommeそれは私が何を求めていたのです。 –

+0

ありがとう、@KunalPuri。私は週末の仕事を中止していますが、明日最初にこれを試してみます。それは非常にエレガントなソリューションのように見えますが、私はその内部の仕組みを完全に理解していないことを認めなければなりません。 – szw

0

私は試したことがありません。チャンスはありません。setdiffもっと良い方法があることを願って、この厄介な解決策を投稿しました。

# dependencies for melting tables and handling data.frames 
require(reshape2) 
require(dplyr) 


# I have added two more cases to your data.frame 
# kidid is passed as numeric (with quoted would have been changed to vector by default) 
df <- data.frame(famid = c("A","A","B","C","C","D","D", "E", "E", "E", "F", "F"), 
       kidid = c(1, 2, 1, 3, 4, 4, 5, 7, 8, 9, 7, 9)) 

# let's have a look to it 
df 
famid kidid 
1  A  1 
2  A  2 
3  B  1 
4  C  3 
5  C  4 
6  D  4 
7  D  5 
8  E  7 
9  E  8 
10  E  9 
11  F  7 
12  F  9 

# we build a contingency table 
m <- table(df$famid, df$kidid) 

# a family A only contains a family B, if A has all the elements of B, 
# and at least one that B doesnt have 
m 

    1 2 3 4 5 7 8 9 
A 1 1 0 0 0 0 0 0 
B 1 0 0 0 0 0 0 0 
C 0 0 1 1 0 0 0 0 
D 0 0 0 1 1 0 0 0 
E 0 0 0 0 0 1 1 1 
F 0 0 0 0 0 1 0 1 

# an helper function to implement that and return a friendly data.frame 
family_contained <- function(m){ 
    res <- list() 
    for (i in 1:nrow(m)) 
    # for each line in m, we calculate the difference to all other lines 
    res[[i]] <- t(apply(m[-i, ], 1, function(row) m[i, ] - row)) 
    # here we test if all values are 0+ (ie if the selected family has all element of the other) 
    # and if at least one is >=1 (ie if the selected family has at least one element that the other doesnt have) 
    tab <- sapply(res, function(m) apply(m, 1, function(x) all(x>=0) & any(x>=1))) 
    # we format it as a table to have nice names 
    tab %>% as.table() %>% 
    # we melt it into a data.frame 
    melt() %>% 
    # only select TRUE and get rid of this column 
    filter(value) %>% select(-value) %>% 
    # to make things clear we name columns 
    `colnames<-`(c("this_family_is_contained", "this_family_contains")) 
} 

family_contained(m) 
# this_family_is_contained this_family_contains 
# 1   B    A 
# 2   F    E 

# finally you can filter them with 
filter(df, !(famid %in% family_contained(m)$this_family_is_contained)) 
+0

これを徹底的に調べてくれてありがとう、@VincentBonhomme – szw

関連する問題