在R中理解应用和外部功能

时间:2015-08-14 06:46:00

标签: r

假设我有一个看起来像这样的数据

ID A B C 
1  X 1 10
1  X 2 10
1  Z 3 15
1  Y 4 12
2  Y 1 15
2  X 2 13
2  X 3 13
2  Y 4 13
3  Y 1 16
3  Y 2 18
3  Y 3 19
3  Y 4 10

我想要将这些值相互比较,所以如果一个ID在一个B变量的周期(从1到4)中改变了它的A变量值,它就会进入数据帧K,如果它没有'然后它进入数据框L.

所以在这个数据集中K看起来像

ID A B C 
1  X 1 10
1  X 2 10
1  Z 3 15
1  Y 4 12
2  Y 1 15
2  X 2 13
2  X 3 13
2  Y 4 13

和L看起来像

ID A B C 
3  Y 1 16
3  Y 2 18
3  Y 3 19
3  Y 4 10

就嵌套循环和if then else语句而言,它可以像下面的

一样解决
for ( i in 1:length(ID)){
m=0
for (j in 1: length(B)){
ifelse( A[j] == A[j+1],m,m=m+1)
}
ifelse(m=0,  L=c[,df[i]], K=c[,df[i]])
}

我在一些帖子中读过,R嵌套循环可以用applyouter函数替换。如果有人能帮我理解在这种情况下如何使用它。

3 个答案:

答案 0 :(得分:5)

所以基本上你不需要这里有条件的循环,你需要做的就是检查{中是否有变化(然后用!将其转换为逻辑){在AB s)的每个周期内{1}}将ID转换为数字值(我假设其真实数据为A设置,如果不是因素,则可以在factor中使用FUN = function(x) length(unique(x)),然后使用ave。使用基数R,我们可以使用split来执行此类任务,例如

ave

或(如果indx <- !with(df, ave(as.numeric(A), ID , FUN = var)) 是字符而不是A

factor

然后只需运行indx <- with(df, ave(A, ID , FUN = function(x) length(unique(x)))) == 1L

split

这将返回包含两个数据帧的列表。

split(df, indx) # $`FALSE` # ID A B C # 1 1 X 1 10 # 2 1 X 2 10 # 3 1 Z 3 15 # 4 1 Y 4 12 # 5 2 Y 1 15 # 6 2 X 2 13 # 7 2 X 3 13 # 8 2 Y 4 13 # # $`TRUE` # ID A B C # 9 3 Y 1 16 # 10 3 Y 2 18 # 11 3 Y 3 19 # 12 3 Y 4 10

类似
data.table

library(data.table) setDT(df)[, indx := !var(A), by = ID] split(df, df$indx)

dplyr

答案 1 :(得分:2)

由于您想了解apply而不是简单地完成它,您可以考虑tapply。作为示范:

> tapply(df$A, df$ID, function(x) ifelse(length(unique(x))>1, "K", "L"))
  1   2   3 
"K" "K" "L" 

稍微简洁英语:浏览按df$A分组的所有df$ID,并在每个分组中应用df$A上的函数(即嵌入式函数中的x ):如果唯一值的数量大于1,则为“K”,否则为“L”。

答案 2 :(得分:2)

我们可以使用data.table执行此操作。我们将'data.frame'转换为'data.table'(setDT(df1))。按“ID”分组,我们检查“A”(length)中uniqueuniqueN(A)元素是否大于1,根据该列创建“ind”列。然后,我们可以基于此split数据集 'ind'栏。

 library(data.table)
 setDT(df1)[, ind:= uniqueN(A)>1, by = ID]
 setDF(df1)
 split(df1[-5],  df1$ind)
#$`FALSE`
#   ID A B  C
#9   3 Y 1 16
#10  3 Y 2 18
#11  3 Y 3 19
#12  3 Y 4 10

#$`TRUE`
#  ID A B  C
#1  1 X 1 10
#2  1 X 2 10
#3  1 Z 3 15
#4  1 Y 4 12
#5  2 Y 1 15
#6  2 X 2 13
#7  2 X 3 13
#8  2 Y 4 13

或类似地使用dplyr,我们可以使用n_distinct创建逻辑列,然后按该列拆分。

library(dplyr)
df2 <- df1 %>%
         group_by(ID) %>%
         mutate(ind= n_distinct(A)>1) 
split(df2, df2$ind) 

base R选项table。我们得到'df1'前两列的table,即'ID'和'A'。通过对输出进行双重否定(!!),我们可以将'0'值转换为'TRUE',将所有其他频率转换为'FALSE'。获取rowSums('indx')。我们将'df1'中的ID列与'indx'的names进行匹配,使用该列将'ID'替换为TRUE/FALSE,并将split数据集替换为这一点。

 indx <- rowSums(!!table(df1[1:2]))>1
 lst <- split(df1, indx[match(df1$ID, names(indx))])
 lst
#$`FALSE`
#   ID A B  C
#9   3 Y 1 16
#10  3 Y 2 18
#11  3 Y 3 19
#12  3 Y 4 10

#$`TRUE`
#  ID A B  C
#1  1 X 1 10
#2  1 X 2 10
#3  1 Z 3 15
#4  1 Y 4 12
#5  2 Y 1 15
#6  2 X 2 13
#7  2 X 3 13
#8  2 Y 4 13

如果我们需要在全局环境中获取单个数据集,请将list元素的名称更改为我们想要的对象名称并使用list2env(不建议使用)

list2env(setNames(lst, c('L', 'K')), envir=.GlobalEnv)