Чтобы передать номер строки в другой столбец
У меня есть датафрейм.
Мне нужно найти минимальное значение в 1-м столбце для каждого значения 2-го столбца. Но я должен вернуть значение в 3-м столбце из той же строки, что и минимум, найденный в 1-м столбце.
Первая часть кажется решена tapply(1,2, min)
Но как передать этот же ряд в 3-й столбец?
Более сложная задача - когда минимум не является уникальным в 1-м столбце. Затем мне нужно выбрать имя (из нескольких) в алфавитном порядке и снова, чтобы найти соответствующее значение из той же строки из 3-го столбца.
3 ответа
Непонятно после прочтения комментариев.
library(dplyr)
df %>%
group_by(zone) %>%
filter(population==min(population)) %>%
#ungroup() %>% #if you don't need zone
select(name)
# zone name
# 1 3 American-Samoa
# 2 1 Andorra
# 3 2 Angola
Обновить
devtools::install_github("hadley/dplyr")
devtools::install_github("hadley/lazyeval")
library(dplyr)
library(lazyeval)
fun2 <- function(grp, Column, grpDontShow=TRUE){
stopifnot(is.numeric(df[,grp]) & Column %in% colnames(df))
df1 <- df %>%
group_by_(grp) %>%
filter_(interp(~x==min(x), x=as.name(Column)))%>%
arrange(name) %>%
filter(row_number()==1) %>%
select(name)
if(grpDontShow){
ungroup(df1) %>%
select(name)
}
else {
df1
}
}
fun2("zone", "population", TRUE)
# Source: local data frame [3 x 1]
# name
#1 Andorra
#2 Angola
#3 American-Samoa
fun2("zone", "landmass", FALSE)
#Source: local data frame [3 x 2]
#Groups: zone
# zone name
#1 1 Albania
#2 2 Angola
#3 3 American-Samoa
fun2("ozone", "landmass", FALSE)
#Error in `[.data.frame`(df, , grp) : undefined columns selected
fun2("name", "landmass", FALSE)
#Error: is.numeric(df[, grp]) & Column %in% colnames(df) is not TRUE
Update2
Если вам нужна функция, использующая base R
funBase <- function(grp, Column, grpDontShow = TRUE) {
stopifnot(is.numeric(df[, grp]) & Column %in% colnames(df))
v1 <- c(by(df[, c(Column, "name")], list(df[, grp]),
FUN = function(x) sort(x[,2][x[, 1] == min(x[, 1],
na.rm = TRUE)])[1]))
if (grpDontShow) {
data.frame(name = v1, stringsAsFactors = FALSE)
}
else {
setNames(data.frame(as.numeric(names(v1)),
v1, stringsAsFactors = FALSE), c(grp, "name"))
}
}
funBase("zone", "landmass")
# name
#1 Albania
#2 Angola
#3 American-Samoa
funBase("zone", "population", FALSE)
# zone name
#1 1 Andorra
#2 2 Angola
#3 3 American-Samoa
данные
df <- structure(list(name = c("Afghanistan", "Albania", "Algeria",
"American-Samoa", "Andorra", "Angola"), landmass = c(5L, 3L,
4L, 6L, 3L, 4L), zone = c(1L, 1L, 1L, 3L, 1L, 2L), area = c(648L,
29L, 2388L, 0L, 0L, 1247L), population = c(16L, 3L, 20L, 0L,
0L, 7L)), .Names = c("name", "landmass", "zone", "area", "population"
), class = "data.frame", row.names = c("1", "2", "3", "4", "5",
"6"))
Воспроизводимый пример будет полезен для полного понимания вашего вопроса.
Тем не менее, я думаю, что вы можете использовать Ave для этого.
a<-c(1:10)
b<-c(rep(1,3),rep(2,4),rep(3,3))
c<-c(101:110)
df<-cbind(a,b,c)
который дает
df
a b c
[1,] 1 1 101
[2,] 2 1 102
[3,] 3 1 103
[4,] 4 2 104
[5,] 5 2 105
[6,] 6 2 106
[7,] 7 2 107
[8,] 8 3 108
[9,] 9 3 109
[10,] 10 3 110
Итак, я собираюсь найти минус a my b и сохранить соответствующий c.
rows<-df[which(ave(df[,1],df[,2],FUN=function(x) x==min(x))==1),]
который дает
rows
a b c
[1,] 1 1 101
[2,] 4 2 104
[3,] 8 3 108
Пытаться:
> ddf
col1 col2 col3
1: 5 a A
2: 2 a B
3: 3 a C
4: 6 a D
5: 4 b E
6: 2 b F
7: 6 b G
8: 2 b H
9: 7 c I
10: 2 c J
11: 6 c K
12: 4 c L
13: 2 c M
>
> sapply(split(ddf, ddf$col2),
function(x) {x = x[order(x$col3),]; x$col3[which.min(x$col1)]})
a b c
B F J
Levels: A B C D E F G H I J K L M
Используя данные @lynghonig:
> sapply(split(ddf, ddf$b),
function(x) {x = x[order(x$c),]; x$c[which.min(x$a)]})
1 2 3
101 104 108
С данными ОП (из комментариев):
> sapply(split(ddf, ddf$landmass), function(x) {x = x[order(x$zone),]; x$zone[which.min(x$name)]})
3 4 5 6
1 1 1 3