按R中的多个条件排列
Arrange by multiple conditions in R
具有以下数据集:
test <- data.frame(name= c("A", "B", "C", "D", "E"), v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))
name v1 v2
A 2 3
B 4 4
C 1 2
D 1 1
E 2 5
我想测试一个 actor/node 支配的概念,这意味着对于每个 row/entry 我想看看它是否在数据集中具有最高值。例如,对于 v1 和 v2,B 都高于 A、C 和 D。所以它 "dominates" 所有其他行。例如E只比A、C、D高,所以它支配这3行。
从数学上讲,我要搜索的是 i >= j, for v1_i >= v1_j and v2_i >= v2_j.
按列排列或排序不起作用,因为它并没有真正显示一行将如何强加另一行,因为它先按一列排序,然后再按另一列排序。
编辑:仅添加一个示例,最终输出将是:
B dominates A, C, D
E dominates A, D, C
C dominates D
A dominates C, D
它看起来如何并不重要。如果它的形式是定向 network/matrix 或带有所有字母的变量的 table。
这是一个建议。这可能不是最优雅的解决方案。
我们可以有一个函数 compare
检查一个字母是否支配另一个字母(除非是相同的字母),然后使用两个嵌套的 sapply
s.
my_letters <- c("A", "B", "C", "D", "E")
test <- data.frame(name= my_letters, v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))
get_row<-function(letter){
test[test$name==letter,2:ncol(test)]
}
compare<-function(letter,i){
if(letter!=i){
if(!sum(get_row(letter) < get_row(i))){
return(i)
}
}
}
result <- sapply(my_letters, function(let) unlist(sapply(my_letters, compare, letter=let)))
列表中的结果:
$A
C D
"C" "D"
$B
A C D
"A" "C" "D"
$C
D
"D"
$D
NULL
$E
A C D
"A" "C" "D"
我找到了出路希望这对你有帮助:)
c$v3= rowSums(x = c[,-1])
c = c[order(c$v3,decreasing = T),]
k = length(c$name)
for (i in 1:k ) {
if (i == k) {
}else {
a = c$name[i+1:k]
a = as.character(a[!is.na(a)])
b = c$name[i]
b = as.character(b[!is.na(b)])
cat(b,"greater than ", a,"\n",sep=" ")
}
}
所以你的输出将是
B greater than E A C D
E greater than A C D
A greater than C D
C greater than D
for
循环在 R 中非常 低效 。请避开它们!
您可以简单地使用 apply
:
# Names column
names = c("A", "B", "C", "D", "E")
# Dataframe
test <- data.frame(name= names, v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))
# Display function
findLowerValues <- function(row, test, names) {
rep <- test$v1 <= row["v1"] & test$v2 <= row["v2"] & test$name != row["name"]
cat(row["name"], 'dominates', names[rep], "\n")
}
# Apply the display function
# axis : row
# Extra args: the full dataset and names
apply(test, 1, findLowerValues, test=test, names=names)
# A dominates C D
# B dominates A C D
# C dominates D
# D dominates
# E dominates A C D
# NULL
我们首先将每一行 split
放入行列表并将其传递给 mapply
,rep
将每一行吃 nrow(test)
次,将它们与整个数据帧进行比较 test
和 select name
的所有值都大于该行。因为这也会将行与自身匹配,所以我们使用 setdiff
删除那些 name
值。
mapply(function(x, y) setdiff(
test$name[rowSums(x[rep(1, nrow(test)),] >= test[-1]) == ncol(test) - 1], y),
split(test[-1], test$name), test$name)
#$A
#[1] "C" "D"
#$B
#[1] "A" "C" "D"
#$C
#[1] "D"
#$D
#character(0)
#$E
#[1] "A" "C" "D"
数据
test <- data.frame(name= c("A", "B", "C", "D", "E"), v1 = c(2, 4, 1, 1, 2),
v2 = c(3, 4, 2, 1, 5), stringsAsFactors = FALSE)
如果您不介意 data.table
解决方案,可以使用 non-equi 连接,如下所示:
library(data.table)
setDT(test)
test[test, on=.(v1<=v1, v2<=v2), .(actor=i.name, node=x.name), by=.EACHI, allow.cartesian=TRUE][
actor!=node, .(actor, node)]
输出:
actor node
1: A C
2: A D
3: B A
4: B C
5: B D
6: C D
7: E A
8: E C
9: E D
具有以下数据集:
test <- data.frame(name= c("A", "B", "C", "D", "E"), v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))
name v1 v2
A 2 3
B 4 4
C 1 2
D 1 1
E 2 5
我想测试一个 actor/node 支配的概念,这意味着对于每个 row/entry 我想看看它是否在数据集中具有最高值。例如,对于 v1 和 v2,B 都高于 A、C 和 D。所以它 "dominates" 所有其他行。例如E只比A、C、D高,所以它支配这3行。
从数学上讲,我要搜索的是 i >= j, for v1_i >= v1_j and v2_i >= v2_j.
按列排列或排序不起作用,因为它并没有真正显示一行将如何强加另一行,因为它先按一列排序,然后再按另一列排序。
编辑:仅添加一个示例,最终输出将是:
B dominates A, C, D
E dominates A, D, C
C dominates D
A dominates C, D
它看起来如何并不重要。如果它的形式是定向 network/matrix 或带有所有字母的变量的 table。
这是一个建议。这可能不是最优雅的解决方案。
我们可以有一个函数 compare
检查一个字母是否支配另一个字母(除非是相同的字母),然后使用两个嵌套的 sapply
s.
my_letters <- c("A", "B", "C", "D", "E")
test <- data.frame(name= my_letters, v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))
get_row<-function(letter){
test[test$name==letter,2:ncol(test)]
}
compare<-function(letter,i){
if(letter!=i){
if(!sum(get_row(letter) < get_row(i))){
return(i)
}
}
}
result <- sapply(my_letters, function(let) unlist(sapply(my_letters, compare, letter=let)))
列表中的结果:
$A
C D
"C" "D"
$B
A C D
"A" "C" "D"
$C
D
"D"
$D
NULL
$E
A C D
"A" "C" "D"
我找到了出路希望这对你有帮助:)
c$v3= rowSums(x = c[,-1])
c = c[order(c$v3,decreasing = T),]
k = length(c$name)
for (i in 1:k ) {
if (i == k) {
}else {
a = c$name[i+1:k]
a = as.character(a[!is.na(a)])
b = c$name[i]
b = as.character(b[!is.na(b)])
cat(b,"greater than ", a,"\n",sep=" ")
}
}
所以你的输出将是
B greater than E A C D
E greater than A C D
A greater than C D
C greater than D
for
循环在 R 中非常 低效 。请避开它们!
您可以简单地使用 apply
:
# Names column
names = c("A", "B", "C", "D", "E")
# Dataframe
test <- data.frame(name= names, v1 = c(2, 4, 1, 1, 2), v2 = c(3, 4, 2, 1, 5))
# Display function
findLowerValues <- function(row, test, names) {
rep <- test$v1 <= row["v1"] & test$v2 <= row["v2"] & test$name != row["name"]
cat(row["name"], 'dominates', names[rep], "\n")
}
# Apply the display function
# axis : row
# Extra args: the full dataset and names
apply(test, 1, findLowerValues, test=test, names=names)
# A dominates C D
# B dominates A C D
# C dominates D
# D dominates
# E dominates A C D
# NULL
我们首先将每一行 split
放入行列表并将其传递给 mapply
,rep
将每一行吃 nrow(test)
次,将它们与整个数据帧进行比较 test
和 select name
的所有值都大于该行。因为这也会将行与自身匹配,所以我们使用 setdiff
删除那些 name
值。
mapply(function(x, y) setdiff(
test$name[rowSums(x[rep(1, nrow(test)),] >= test[-1]) == ncol(test) - 1], y),
split(test[-1], test$name), test$name)
#$A
#[1] "C" "D"
#$B
#[1] "A" "C" "D"
#$C
#[1] "D"
#$D
#character(0)
#$E
#[1] "A" "C" "D"
数据
test <- data.frame(name= c("A", "B", "C", "D", "E"), v1 = c(2, 4, 1, 1, 2),
v2 = c(3, 4, 2, 1, 5), stringsAsFactors = FALSE)
如果您不介意 data.table
解决方案,可以使用 non-equi 连接,如下所示:
library(data.table)
setDT(test)
test[test, on=.(v1<=v1, v2<=v2), .(actor=i.name, node=x.name), by=.EACHI, allow.cartesian=TRUE][
actor!=node, .(actor, node)]
输出:
actor node
1: A C
2: A D
3: B A
4: B C
5: B D
6: C D
7: E A
8: E C
9: E D