假设我有一个看起来像这样的数据
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嵌套循环可以用apply
和outer
函数替换。如果有人能帮我理解在这种情况下如何使用它。
答案 0 :(得分:5)
所以基本上你不需要这里有条件的循环,你需要做的就是检查{中是否有变化(然后用!
将其转换为逻辑){在A
(B
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
)中unique
个uniqueN(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)