【问题标题】:How to apply a custom function over each column of a matrix?如何在矩阵的每一列上应用自定义函数?
【发布时间】:2018-05-01 22:02:28
【问题描述】:

我一直在尝试使用我在此处找到的custom function 重新计算人口普查区汇总到社区的家庭收入中位数。我的数据是这样的

> inc_df[, 1:5]
          San Francisco Bayview Hunters Point Bernal Heights Castro/Upper Market Chinatown
2500-9999             22457                  1057            287                 329      1059
10000-14999           20708                   920            288                 463      1327
1500-19999            12701                   626            145                 148       867
20000-24999           12106                   491            285                 160       689
25000-29999           10129                   554            238                 328       167
30000-34999           10310                   338            257                 179       289
35000-39999            9028                   383            184                 163       326
40000-44999            9532                   472            334                 173       264
45000-49999            8406                   394            345                 241       193
50000-59999           17317                   727            367                 353       251
60000-74999           25947                  1037            674                 794       236
75000-99999           36378                  1185            980                 954       289
100000-124999         33890                   990            640                1208       199
125000-149999         24935                   522            666                 957       234
150000-199999         37190                   814           1310                1535       150
200000-250001         65763                   796           2122                3175       302

函数如下:

GroupedMedian <- function(frequencies, intervals, sep = NULL, trim = NULL) {
  # If "sep" is specified, the function will try to create the 
  #   required "intervals" matrix. "trim" removes any unwanted 
  #   characters before attempting to convert the ranges to numeric.
  if (!is.null(sep)) {
    if (is.null(trim)) pattern <- ""
    else if (trim == "cut") pattern <- "\\[|\\]|\\(|\\)"
    else pattern <- trim
    intervals <- sapply(strsplit(gsub(pattern, "", intervals), sep), as.numeric)
  }

  Midpoints <- rowMeans(intervals)
  cf <- cumsum(frequencies)
  Midrow <- findInterval(max(cf)/2, cf) + 1
  L <- intervals[1, Midrow]      # lower class boundary of median class
  h <- diff(intervals[, Midrow]) # size of median class
  f <- frequencies[Midrow]       # frequency of median class
  cf2 <- cf[Midrow - 1]          # cumulative frequency class before median class
  n_2 <- max(cf)/2               # total observations divided by 2

  unname(L + (n_2 - cf2)/f * h)
}

应用该函数的代码如下所示:

GroupedMedian(inc_df[, "Bernal Heights"], rownames(inc_df), sep="-", trim="cut")

这一切都很好,但我不知道如何将它应用于矩阵的每一列,而不是输入每一列名称并一次又一次地运行它。我试过这个:

> minc_hood <- data.frame(apply(inc_df, 2, function(x) GroupedMedian(inc_df[, x], 
rownames(inc_df), sep="-", trim="cut")))

但我收到此错误消息

Error in inc_df[, x] : subscript out of bounds

【问题讨论】:

  • inc_df[, x] 更改为 x。另外,也许您应该将其应用于inc_df[,-1],因为我认为它不适用于第一列。
  • 将其更改为 x 就像一个魅力 - 谢谢!

标签: r apply


【解决方案1】:

这里有几件事在起作用:

  • 建议:切勿将applydata.frame 一起使用(除非您绝对确定您不介意转换为matrix^1 的开销并且可以接受潜在的数据丢失^2)。

  • 即使你打算使用apply,你也有点“偏离”:当你说apply(df, 2, func)时,它会使用df的第一列并将其作为参数呈现,所以比如

    apply(mtcars, 2, mean)
    

    会打电话

    mean(c(21, 21, 22.8, 21.4, 18.7, ...)) # mpg
    mean(c(6, 6, 4, 6, 8, ...))            # cyl
    mean(c(160, 160, 108, 258, 360, ...))  # disp
    # ... etc
    

    在这种情况下,您对apply(inc_df, 2, function(x) GroupedMedian(inc_df[, x], ...)) 的使用是错误的,因为xinc_df 的第一列的所有值替换(然后是第二列的所有值,等等)。

由于您的函数看起来像是接受值向量(加上一些其他参数),我建议您尝试类似

inc_df[] <- lapply(inc_df, GroupedMedian, rownames(inc_df), sep="-", trim="cut")

如果您想将此函数应用于这些列的 子集,那么这样的方法效果很好:

ind <- c(1,3,7)
inc_df[ind] <- lapply(inc_df[ind], GroupedMedian, rownames(inc_df), sep="-", trim="cut")

使用inc_df[] &lt;- ...(当不做列子集时)确保我们替换列的值而不会丢失它是data.frame 的属性。它实际上与 inc_df &lt;- as.data.frame(...) 相同,但有一些其他细微差别。

注意事项:

^1:apply 将始终将 data.frame 转换为 matrix。这可能没问题,但是对于更大的数据将花费非零的时间。它也可能会产生后果,请参阅下一个...

^2: 与data.frame 不同,matrix 只能有一个类。这意味着所有列都将按logical &lt; integer &lt; numeric &lt; POSIXct &lt; character 的顺序向上转换为最高通用类型。这意味着,如果您拥有所有 numeric 列和一个 character,那么您正在使用的函数 apply 将看到所有 character 数据。这可以通过仅选择具有您期望的类型的那些列来缓解,也许是:

isnum <- sapply(inc_df, is.numeric)
inc_df[isnum] <- apply(inc_df[isnum], 2, GroupedMedian, ...)

在这种情况下,您将获得的最差转换将是integer-to-numeric,这可能是一个可接受(且可逆)的转换。

【讨论】:

  • mshwall,这能回答你的问题吗?如果有,请accept it
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-05
  • 1970-01-01
  • 2018-10-09
  • 2011-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多