Чтобы передать номер строки в другой столбец

У меня есть датафрейм.

Мне нужно найти минимальное значение в 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 
Другие вопросы по тегам