2012-02-23 59 views
3

我一直在考虑这一点,并且无法提出解决方案。我在列X中有数据用于在列Z中创建数据。我希望Z全部为1,直到X中有一行中有两个0,然后是全零。另外,在W列中,我希望从底部向上看Y时最终的元素为1,Y包含连续的两个0。希望这是有道理的。我已经把Z栏和W栏放在了他们最终应该看的地方。我正在尝试使用索引,但我很难弄清楚如何引用来自列X后面的行的Z行所在的行(因为Z行1中的值基于值X中第2行和第3行)。这些应该是两个独立的功能,一个是看开始,一个是看结尾。它们都将分别应用到每一行,因此第X列将生成两列,如下所示,以及另一列,在这种情况下将全为0。谢谢你的帮助!如何根据行上/下的行中的值创建列R

** * ** *我改变的列名从A B C d到X YŽW至避免混淆。对不起,当我输入它时没有想到!

** * ** * ** * *我真的希望能够做到这一点没有功能或循环,只使用索引。我想我可以使用一个函数来解决它,但由于它是一个大型数据集,我希望它尽可能快。

code X Y Z W 
A 1 0 1 0 
A 1 0 1 0 
A 0 0 1 0 
A 1 0 1 0 
A 1 0 1 0 
A 1 0 1 0 
A 1 0 1 0 
A 0 0 1 0 
A 1 0 1 0 
A 0 0 0 0 
A 0 0 0 0 
A 1 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 1 1 0 0 
B 0 0 0 0 
B 1 0 0 0 
B 0 0 0 0 
B 1 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 1 0 0 0 
B 0 1 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 0 1 0 1 
B 0 1 0 1 
B 0 1 0 1 
B 0 0 0 1 
B 0 1 0 1 
B 0 1 0 1 

以下用于聚合的函数应该给出我正在寻找的结果。感谢泰勒开始这个功能。我仍然觉得应该有一个更简单的方法来做到这一点,但现在应该这样做。感谢大家的投入!

我想我明白了,基于泰勒的代码,只是做了一些改变。我将只使用聚合应用这个函数,它应该全部解决。感谢所有的投入!

pat.finder <- function(var, value=0, fill1=1, fill2=0, rev=FALSE, seq=2){ 

if(var[1]==0 & rev==FALSE){ 

j<- rep(0,length(var))} else if(var[length(var)]==0 & rev == TRUE){ 

j<- rep(0,length(var))} else{ 

x <- if(rev) rle(rev(var)) else rle(var) 
n <- which(x[[1]]>(seq-1) & x[[2]]==value)[1]-1 
i <- sum(x[[1]][1:n]) 
j <- if(rev){ 
      rev(c(rep(fill1, i), rep(fill2, length(var)-i))) 
     } else { 
      c(rep(fill1, i), rep(fill2, length(var)-i)) 
     } 
} 

return(j) 
} 
+0

我看看'zoo'包中的'rollapply()'。像'which(rollapply(zoo(DF $ A,width = 2,function(X)all(X == 0)))[1]'''''''''''''''''''''''''''''''''''''''' '这是0,然后是0. – 2012-02-23 20:05:05

回答

1

有可能是一个更快的方法,但是这是我想出了:

dat <- read.table(text="code A B C D #read in your data 
A 1 0 1 0 
A 1 0 1 0 
A 0 0 1 0 
A 1 0 1 0 
A 1 0 1 0 
A 1 0 1 0 
A 1 0 1 0 
A 0 0 1 0 
A 1 0 1 0 
A 0 0 0 0 
A 0 0 0 0 
A 1 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
A 0 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 1 1 0 0 
B 0 0 0 0 
B 1 0 0 0 
B 0 0 0 0 
B 1 0 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 1 0 0 0 
B 0 1 0 0 
B 0 0 0 0 
B 0 0 0 0 
B 0 1 0 1 
B 0 1 0 1 
B 0 1 0 1 
B 0 0 0 1 
B 0 1 0 1 
B 0 1 0 1", header=T) 

现在代码:

A.rle <- rle(dat$A) 
n <- which(A.rle[[1]]>1 & A.rle[[2]]==0)[1]-1 
i <- sum(A.rle[[1]][1:n]) 
dat$C <- c(rep(1, i), rep(0, nrow(dat)-i)) 

B.rle <- rle(rev(dat$B)) 
n2 <- which(B.rle[[1]]>1 & B.rle[[2]]==0)[1]-1 
i2 <- sum(B.rle[[1]][1:n2]) 
dat$D <- rev(c(rep(1, i2), rep(0, nrow(dat)-i2))) 

编辑:我不完全理解你想要什么我认为,所以我试图创建一个功能,以满足您的需求。使用rev=TRUE看看到底:

pat.finder <- function(var, value=0, fill1=1, fill2=0, rev=FALSE, seq=2){ 
    x <- if(rev) rle(rev(var)) else rle(var) 
    n <- which(x[[1]]>(seq-1) & x[[2]]==value)[1]-1 
    i <- sum(x[[1]][1:n]) 
    j <- if(rev){ 
       rev(c(rep(fill1, i), rep(fill2, length(var)-i))) 
      } else { 
       c(rep(fill1, i), rep(fill2, length(var)-i)) 
      } 
    return(j) 
} 

#TRY IT OUT 
pat.finder(dat$B, rev=TRUE) 

transform(dat, C=pat.finder(A), D = pat.finder(B, rev=TRUE)) #what I think you want 

transform(dat, C=pat.finder(A, fill1='foo', fill2='bar'), 
    D = pat.finder(A, rev=TRUE)) 

transform(dat, C=pat.finder(A, value=1), D = pat.finder(B, rev=TRUE)) 
+0

好吧,对不起,我正在编辑,然后达到了时间限制:感谢您的开始,唯一的问题是“代码”列中有近500种不同的可能性,所以我需要一个单独引用这部分数据的方式,而不是为每个数据创建单独的变量(并且我想避免执行循环)。这是我目前所拥有的,其中C最初只是一列0。但是,显然这是行不通的。 C [A [as.numeric(rownames(A))+ 1]!= 1&A [as.numeric(rownames(A))+ 2]!= 1] < - 1我需要rownames()只是不知道是什么。 – user1228982 2012-02-23 19:50:13

+0

@ user1228982 - 如果你愿意,你可以随时删除你以前的评论之一(因为一旦你得到它,我会做这件事)。欢呼,欢迎来到SO! – 2012-02-23 19:59:55

+0

我认为在将这个功能放入功能后,它应该能够满足您的需求。我在转换中使用它,因为这更容易,代码更少,但是可以使用隔离每列的函数:'pat.finder(var,value = 0,fill1 = 1,fill2 = 0,rev = FALSE,seq = 2)' 。 var是你的列,value是你要查找的模式,fill1是你想要填充字符串的第一部分的内容,fill2与下半部分是相同的,rev给你看后面的能力列的结尾,seq会告诉您要查找的模式有多少次重复。 – 2012-02-23 20:11:24

1

考虑sum(dat$A[i:(i+1)])。如果你连续有两个零,那就是零。使用循环(或lapply)或其中一个运行函数来查找返回零的最小“i”,并且您已找到将C列从1切换到0的位置。我真的不得不问:“你想解决什么问题?”我几乎可以保证,如果您告诉我们A列和B列的数据来自哪里,我们可以向您展示更直接的方法来确定您在C列和D列设置的断点。

PS:一旦一个解决方案是设立dat$C,只是做相同,但由“IMAX” 1向下循环,从而获得dat$D

+0

基本上,列X和Y中的数据表示与A关联的值是否小于与A关联的数据的第一个四分位数。此外,如果该特定行的日期更长,则X仅给出值1比某个日期。 X栏基本上在寻找“新”项目。如果该特定行的日期少于特定日期,则Y列仅给出1。 Y栏基本上在寻找已经停产的物品。列Z和W在那里通过创建一个具有更好定义模式的向量来进一步优化这个过程。非常清楚,对吧? – user1228982 2012-02-23 21:16:47

1

这可能适用于您的需求(只做A列)。如果您可以更具体地了解您正在寻找什么,董事会可以进一步提供帮助。

## read in your data 
df1 = read.table(text="code A B C D 
A 1 0 1 0 
A 1 0 1 0 
... 
") 

## create forward-lagged A column 
require(taRifx) 
df1$lagA = shift(df1$A,wrap=F,pad=T) 

myfun1 = function(x,y) { 
    BB = x + y 
    BB = ifelse(BB > 0, 1, 0) 
    BB 
} 

df1$A2 = apply(df1[,c(2,6)], 1, function(x,y) myfun1(x[1],x[2])) 
tvec = rep(1,which(df1$A2 == 0)[1] -1) 
bvec = vector(length = nrow(df1) - which(df1$A2 == 0)[1] + 1, mode="numeric") 

## the column you are looking for: 
df1$nA = c(tvec,bvec) 
+0

您可能会在'taRifx'包中找到'shift'函数对此有所帮助。如果你的'flagum'函数做到了我认为的那样,'shift'可以做同样的事情和更多。 – 2012-02-23 20:42:40

+0

酷;谢谢。然后,我可以替换上面的代码来读取df1 $ lagA = shift(df1 $ A,wrap = F,pad = T)。 – 2012-02-23 22:24:39

+0

是的。这是主意。 – 2012-02-23 23:21:59

1

假设问题中显示的数据帧是DF。那么如果x的第i个元素和下一个元素是0并且结果的第i个元素否则为1,那么pmax的结果的第i个元素为0。由于'x'的最后一个元素没有下一个元素,我们在末尾附加1。然后,我们将其与0进行比较,然后将cummin移到此过程中发现的前0个位置。

two0 <- function(x) cummin(c(pmax(x[-1], x[-length(x)]), 1) != 0) 
DF.out <- transform(DF, Z = two0(X), W = rev(two0(rev(Y)))) 

!=0使得two0integer结果。如果我们希望我们可以放弃它,结果将是numeric

编辑:澄清的整数/数字方面。

+0

比我的解决方案更流畅。 – 2012-02-23 22:45:23