Rには、1行に1つの個人を持つデータフレームがあります。個人が2行に表示されることがありますが、重複したIDに基づいてこれらの行を組み合わせたいと思います。
問題は、各個人が複数のIDを持っており、IDが2回表示される場合、必ずしも同じ列に表示されるとは限らないことです。
データフレームの例を次に示します。
dat <- data.frame(a = c('cat', 'canine', 'feline', 'dog'),
b = c('feline', 'puppy', 'meower', 'wolf'),
c = c('kitten', 'barker', 'kitty', 'canine'),
d = c('shorthair', 'collie', '', ''),
e = c(1, 5, 3, 8))
> dat
a b c d e
1 cat feline kitten shorthair 1
2 canine puppy barker collie 5
3 feline meower kitty 3
4 dog wolf canine 8
したがって、行1のb
IDa
は行3のIDと等しいため、行1と3を組み合わせる必要があります。同様に、a
行2のIDc
は行4のIDと等しいため、これらの行も組み合わせる必要があります。
理想的には、出力は次のようになります。
a.1 b.1 c.1 d.1 e.1 a.2 b.3 c.2 d.2 e.2
1 cat feline kitten shorthair 1 feline meower kitty 3
2 canine puppy barker collie 5 dog wolf canine 8
(空の文字列である共有IDに基づいて行が結合されていないことに注意してください。)
これをどのように行うことができるかについての私の考えは以下のとおりですが、私は間違った道を進んでいると確信しているので、おそらく問題の解決には役立たないでしょう。
各行に行IDを割り当てて、データを溶かすことができると思いました。その後、私は行ごとに通過することができました。IDの1つが前の行と一致する行を見つけた場合(たとえば、行3のIDの1つが行1のIDの1つと一致する場合)、現在の行の行IDのすべてのインスタンスを変更して前の行IDと一致させます(たとえば、3のすべての行IDが1に変更されます)。
これが私が使用しているコードです:
dat$row.id <- 1:nrow(dat)
library(reshape2)
dat.melt <- melt(dat, id.vars = c('e', 'row.id'))
for (i in 2:nrow(dat.melt)) {
# This next step is just to ignore the empty values
if (grepl('^[[:space:]]*$', dat.melt$value[i])) {
next
}
earlier.instance <- dat.melt$row.id[which(dat.melt$value[1:(i-1)] == dat.melt$value[i])]
if (length(earlier.instance) > 0) {
earlier.row.id <- earlier.instance[1]
dat.melt$row.id[dat.melt$row.id == dat.melt$row.id[i]] <- earlier.row.id
}
}
このアプローチには2つの問題があります。
row.id
し、variable
私は上記示した出力の種類を取得するためには、それをキャストする方法がわからないので、。dcast
ここで使用すると、集計関数を使用するように強制されます。出力:
e row.id variable value
1 1 3 a cat
2 5 2 a canine
3 3 3 a feline
4 8 2 a dog
5 1 3 b feline
6 5 2 b puppy
7 3 3 b meower
8 8 2 b wolf
9 1 3 c kitten
10 5 2 c barker
11 3 3 c kitty
12 8 2 c canine
13 1 3 d shorthair
14 5 2 d collie
15 3 3 d
16 8 2 d
新しい答え。これを介して作業するいくつかの楽しみ(/欲求不満)がありました。それが最速の解決策ではないと確信していますが、他の答えが中断したところを乗り越える必要があります。説明させてください:
dat <- data.table(a = c('cat', 'canine', 'feline', 'dog', 'cat','fido'),
b = c('feline', 'puppy', 'meower', 'wolf', 'kitten', 'dog'),
c = c('kit', 'barker', 'kitty', 'canine', 'feline','wolf'),
d = c('shorthair', 'collie', '', '','',''),
e = c(1, 2, 3, 4, 5, 6))
dat[, All := paste(a, b,c),]
2つの変更:dat$e
現在はインデックス列であるため、どちらの行でも数値の位置になります。e
それ以外の点で重要な場合は、新しい列を作成して置き換えることができます。
以下は最初のループです。これにより、3つの新しい列FirstMatchingID
などが作成されます。これらは以前と同様です。これらはdat$All
、a
b
およびに一致する最も早い(最も低い行番号)のインデックスを提供しますc
。
for(i in 2:nrow(dat)) {
x <- grepl(dat[i]$a, dat[i-(1:i)]$All)
y <- max(which(x %in% TRUE))
dat[i, FirstMatchingID := dat[i-y]$e]
x2 <- grepl(dat[i]$b, dat[i-(1:i)]$All)
y2 <- max(which(x2 %in% TRUE))
dat[i, SecondMatchingID := dat[i-y2]$e]
x3 <- grepl(dat[i]$c, dat[i-(1:i)]$All)
y3 <- max(which(x3 %in% TRUE))
dat[i, ThirdMatchingID := dat[i-y3]$e]
}
次に、を使用pmin
して、列の最も早い一致行を見つけ、MatchingID
それを独自の列に設定します。これは、a
行25に一致しb
、行12に一致する場合です。それはあなたに12を与えるでしょう(私はこれがあなたの質問に基づいてあなたが望むものであると思います)。
dat$MinID <- pmin(dat$FirstMatchingID, dat$SecondMatchingID, dat$ThirdMatchingID, na.rm=T)
最後に、このループは3つのことを実行し、以下FinalID
から一致するすべてのID番号を含む列を作成しますe
。
MinID
はどこにNA
設定されFinalID
ていますかe
MinID
が数字の場合、その行(最も早い一致)を見つけて、それ MinID
が数字かどうかを確認します。そうでない場合、以前の一致はなく、次のように設定さFinalID
れます。MinID
i
の最初の一致がそれ自体より前の一致を持つ特殊なケースです。これにより、その一致が検出され、に設定されFinalID
ます。for (i in 1:nrow(dat)) { x <- dat[i]$MinID if (is.na(dat[i]$MinID)) { dat[i, FinalID := e] } else if (is.na(dat[x]$MinID)) { dat[i, FinalID := MinID] } else dat[i, FinalID := dat[x]$MinID] }
これでうまくいくと思います。どうなるか教えてください。私はその効率や速度については何も主張しません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加