R:关于向量的子集化

时间:2014-10-01 08:01:33

标签: r matrix dataframe subset

我试图弄清楚如何将某个函数仅应用于最后一列上具有相同条目的矩阵行,但直到现在都没有运气。

我的矩阵(我们将简称为matrix并假设它是5x4)看起来像这样:

d1.1   d1.2   d1.3   NAME1 
d2.1   d2.2   d2.3   NAME1 
d3.1   d3.2   d3.3   NAME2 
d4.1   d4.2   d4.3   NAME3
d5.1   d5.2   d5.3   NAME2`

我想对具有相同名称的行执行摘要统计fun1,以获得如下所示的最终矩阵:

fun1(d1.1, d2.1)   fun1(d1.2, d2.2)   fun1(d1.3, d2.3)   NAME1
fun1(d3.1, d5.1)   fun1(d3.2, d5.2)   fun1(d3.3, d5.3)   NAME2
d4.1               d4.2               d4.3               NAME3.

如果fun1也在单身'上进行,也可以。行,即

fun1(d1.1, d2.1)   fun1(d1.2, d2.2)   fun1(d1.3, d2.3)   NAME1
fun1(d3.1, d5.1)   fun1(d3.2, d5.2)   fun1(d3.3, d5.3)   NAME2
fun1(d4.1)         fun1(d4.2)         fun1(d4.3)         NAME3.

我试过

sapply(subset(matrix[,1:3], as.character(matrix[,4])==as.character(listofnames)), fun1)

但当然不起作用。目前的问题在于子集as.character(matrix[,4])==as.character(listofnames),因为这两个对象具有不同的维度,但我确信这不是唯一的。

我试图寻找类似的问题,但我只是通过指定(数字)条件(> 3)或模式(每组7个有序条目)找到子集。没有运气因素或角色。

我想在plyr包中可能会有一些帮助,但我无法使其正常工作。非常感谢任何建议!

更新

就我而言,fun1=min。问题同时发生了变化:在保持数据按NAME分组的同时,我希望得到每组中第1列的最小值,并保存找到min的整行,如下所示:假设d1.1 < d2.1d5.1 < d3.1,然后是矩阵

d1.1   d1.2   d1.3   NAME1 
d2.1   d2.2   d2.3   NAME1 
d3.1   d3.2   d3.3   NAME2 
d4.1   d4.2   d4.3   NAME3
d5.1   d5.2   d5.3   NAME2

应该成为

d1.1   d1.2   d1.3   NAME1 
d4.1   d4.2   d4.3   NAME3
d5.1   d5.2   d5.3   NAME2

不丢失其他列。 我按照建议尝试使用mutatesummarise参数,但不断收到警告和错误(实际上我发现help()根本没有帮助。)

2 个答案:

答案 0 :(得分:2)

你可以尝试:

library(dplyr)
dfSelectSummary <- df %>% 
              group_by(name) %>% 
             summarise_each(funs(mean=mean(., na.rm=TRUE), sd=sd(., na.rm=TRUE),
             median=stats::median(., na.rm=TRUE)), starts_with("X"))

dfSelectSummary[,1:4]
#Source: local data frame [3 x 4]

#   name X1_mean  X2_mean  X3_mean
#1 NAME1   4.250 3.333333 4.888889
#2 NAME2   5.375 4.555556 6.000000
#3 NAME3   6.000 8.000000 9.000000

或者您可以使用data.table

library(data.table)
DT <- data.table(df, key='name')
nm1 <- colnames(DT[, as.list(summary(X1[!is.na(X1)])), by=name])[-1]
DTSummary <- DT[,  c(Var=list(nm1),
    lapply(.SD, function(x) summary(x[!is.na(x)]))), by=name]

head(DTSummary,8)
#    name     Var    X1    X2     X3    X4    X5
#1: NAME1    Min.  1.00 0.000  0.000 3.000  0.00
#2: NAME1 1st Qu.  2.00 2.000  1.000 3.750  3.25
#3: NAME1  Median  3.50 3.000  6.000 7.500  5.00
#4: NAME1    Mean  4.25 3.333  4.889 6.375  5.00
#5: NAME1 3rd Qu.  6.00 5.000  8.000 8.250  7.25
#6: NAME1    Max. 10.00 7.000 10.000 9.000 10.00
#7: NAME2    Min.  0.00 0.000  0.000 1.000  1.00
#8: NAME2 1st Qu.  3.75 4.000  4.000 3.000  4.25

另一种选择是尝试summaryBy

中的doBy
library(doBy)
 summaryBy(.~name, data=df,
    FUN=function(x) c(mean=mean(x, na.rm=TRUE), var= var(x, na.rm=TRUE),
                    median=median(x, na.rm=TRUE)))

如果您有numeric名称列,则可能不需要转换matrix

 m1 <- as.matrix(cbind(name=as.numeric(df$name), df[,-1]))
 by(m1[,-1], m1[,1], FUN=summary)

数据

set.seed(45)
df <- data.frame(name=sample(paste0("NAME", 1:3),20, replace=TRUE),
        matrix(sample(c(NA, 0:10), 20*5, replace=TRUE), ncol=5))

更新

如果您需要long表单中的结果并希望保留comments列,则可以使用mutate_each

 df1 <- df %>% 
           group_by(name) %>% 
           mutate_each(funs(min=min(., na.rm=TRUE)), starts_with("X"))

 colnames(df1)[2:6] <- paste0("Min", colnames(df1)[2:6])
 head(df1,3)
 #Source: local data frame [3 x 7]
 #Groups: name

 #   name MinX1 MinX2 MinX3 MinX4 MinX5 Comments
 #1 NAME2     0     0     0     1     1     Fair
 #2 NAME1     1     0     0     3     0      Bad
 #3 NAME1     1     0     0     3     0     Good

newdata

  set.seed(45)
  df <- data.frame(name=sample(paste0("NAME", 1:3),20, replace=TRUE),
          matrix(sample(c(NA, 0:10), 20*5, replace=TRUE), ncol=5), 
             Comments=sample(c("Good", "Fair", "Bad", "ugly"), 20, replace=TRUE))

答案 1 :(得分:0)

我想我成功了!

library(dplyr)

df1 <- df %>%
       group_by(NAMES) %>%
       filter(df, X1 == min(X1))

返回最小值,未删除任何数据。 我在另一个帖子上找到了类似的答案。如果存在多个最小值,它将返回所有行的问题,但这不是我的情况。