2016-05-27 9 views
6

データフレームから行のシーケンスを削除しようとしています。シーケンスは既知の文字列で始まり、既知の文字列で終わりますが、介在行の内容および数は不明である。データフレーム全体でこれを繰り返したいと思います。Rループを削除する列の1つの文字列から2番目の文字列への範囲

たとえば、データフレームが以下の場合、StringAのすべてのインスタンスからStringB(両端を含む)に行を削除しますが、StringBの次の行までStringBに続く行は保持します。次の例では、つまり、StringA、unknownC、unknownD、unknownS、StringBを含む行を削除したいが、unknownKとunknownRを保持してから、StringA、unknownU、unknownP、StringBで削除を続けるがunknownTを保持する。

Column 1 Column 2 
StringA  1 
unknownC 9 
unknownD 11 
unknownS 5 
StringB 7 
unknownK 6 
unknownR 1 
StringA 76 
unknownU 2 
unknownP 41 
StringB 3 
unknownT 9 

私が間違っていた、df2 <- df[1:which(df[,1]=="StringA")-1,]を試みたが、しようとする他のどのようなアプローチとして、途方に暮れています。ご指導いただきありがとうございます。

+2

stringAは常に後続の文字列Bとペアになっていることがわかっていますか?文字列AとBが常に交替することも確かに知られていますか(e、g。決してA ... A ... B)? – dww

+0

はい、そうです。それはいつもA ... B、決してA..A ... B – SPZ

答えて

5

あなたはMap機能を使用して、削除するインデックス構築することにより、このような何かを試すことができます。データ

indexToRemove <- unlist(Map(`:`, which(df$`Column 1` == "StringA"), 
           which(df$`Column 1` == "StringB"))) 

df[-indexToRemove, ] 
    Column 1 Column 2 
6 unknownK  6 
7 unknownR  1 
12 unknownT  9 

を:

structure(list(`Column 1` = structure(c(1L, 3L, 4L, 8L, 2L, 5L, 
7L, 1L, 10L, 6L, 2L, 9L), .Label = c("StringA", "StringB", "unknownC", 
"unknownD", "unknownK", "unknownP", "unknownR", "unknownS", "unknownT", 
"unknownU"), class = "factor"), `Column 2` = c(1L, 9L, 11L, 5L, 
7L, 6L, 1L, 76L, 2L, 41L, 3L, 9L)), .Names = c("Column 1", "Column 2" 
), class = "data.frame", row.names = c(NA, -12L)) 
+0

うーん、私はこの戦略Psidomのアイデアが好きですが、私は最初のステップをテストしたときに受け取ったこの警告を避ける方法がわかりません:mapply(FUN = f、...、SIMPLIFY = FALSE): 長い引数は長さの倍数ではありません – SPZ

+0

Spot on meです。 Bravo –

+0

あなたのコラムが 'A ... B ... A ...'や 'B ... A ... B..'のようなものならば、これが起こる可能性があります。 – Psidom

3

あなたはforループを使用することができます。これは、掲載されたベクトル化された解よりも遅くなりますが、同様の関連問題に適応し、予期しない入力データに対して頑強であるという点で多少のメリットがあります。

注:

  1. このメソッドは、入力データに奇妙に対して頑健である - それは常に交互に、常に、StringA ...列B組のペアになったに依存しない、またそれがいることを前提としないStringA StringBの前に常に発生します。 StringAが検出されるたびに、StringBが検出されるまで行の削除が開始されます。
  2. 非常に大規模なデータフレームでこのメソッドを使用すると、ループ内でデータフレームが増えているため、このメソッドを使用すると速度が遅くなる可能性があります(常に大規模な操作が遅くなることが保証されています)。

コード:

keep.line <- TRUE 
out.df <- data.frame() 

for (i in 1:NROW(my.df)) { 
    if (my.df[i,]$Column1 == "StringA") keep.line <- FALSE 
    if (keep.line) out.df <- rbind(out.df, my.df[i,]) 
    if (my.df[i,]$Column1 == "StringB") keep.line <- TRUE 
} 

out.df 
## Column1 Column2 
## unknownK 0.3679608 
## unknownR -0.8867749 
## unknownT 1.6277386 

一部のデータ: Psidomのデータ@使用

Column1 <-c( 
"StringA" ,  
"unknownC",  
"unknownD", 
"unknownS", 
"StringB" , 
"unknownK", 
"unknownR", 
"StringA" , 
"unknownU", 
"unknownP", 
"StringB" , 
"unknownT") 

my.df <- data.frame(Column1, Column2 = rnorm(12), stringsAsFactors = F) 
+0

ありがとう、私はこのループのアプローチが好きです。 – SPZ

3

:Sを提供するために

sel <- with(dat, 
    (cumsum(`Column 1`=="StringA") == cumsum(`Column 1`=="StringB")) 
    & 
    (!(`Column 1` %in% c("StringA","StringB"))) 
) 
dat[sel,] 

# Column 1 Column 2 
#6 unknownK  6 
#7 unknownR  1 
#12 unknownT  9 

omeの説明 - これは、cumsumを使用して、"StringA""StringB"の2つのカウンターをColumn 1に表示しています。数字が一致する場合は、1 Aと1に対応するBがあることを意味します。値のようにColumn 1%in%ターゲットStringA/B文字列のいずれかがそれを確定である場合を取り外す

cumsum(dat$`Column 1`=="StringA") 
#[1] 1 1 1 1 1 1 1 2 2 2 2 2 
cumsum(dat$`Column 1`=="StringB") 
#[1] 0 0 0 0 1 1 1 1 1 1 2 2 
#   = = =  = = 

以下=をマーク。

+0

これは興味深いようですが、それに従うのは難しいです。この仕組みを説明するために注釈を付けることができますか? – dww

+1

@dww - 説明を追加/ – thelatemail

関連する問題