簡體   English   中英

不明白R的應用功能

[英]Don't understand R's apply function

我有一個數據框,其中一列代表一個數值,我想在數據框中添加一列,這是該列的離散化版本。 這是一個可重復的例子:

# create example data
smallData <- data.frame(name = as.character(c("IC","IC","IC","IC","IC","BC","BC","BC","BC","BC")), 
                        value = as.integer(c(29,29,29,29,29,29,29,29,43,26)))

這在這里創建了一個小例子:

 smallData
   name value
1    IC    29
2    IC    29
3    IC    29
4    IC    29
5    IC    29
6    BC    29
7    BC    29
8    BC    29
9    BC    43
10   BC    26

現在,我想在數據框中添加一列,根據“值”列對行進行離散化:

# add new column to data frame
smallData$category <- ""
# define function to categorize data frame objects
categorize <- function(r)
{
  target <- r[c("value")]

  if(target < 27)
  {
    r[c("category")] <- "A"
  } else if(target < 30) {
    r[c("category")] <- "B"
  } else {
    r[c("category")] <- "C"
  }
  return(r)
}
# call to apply
smallData <- apply(smallData,1,categorize)
smallData

此代碼的輸出是:

> smallData
         [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
name     "IC" "IC" "IC" "IC" "IC" "BC" "BC" "BC" "BC" "BC" 
value    "29" "29" "29" "29" "29" "29" "29" "29" "43" "26" 
category "B"  "B"  "B"  "B"  "B"  "B"  "B"  "B"  "C"  "A"  

這是smallData的str()函數的輸出:

> str(smallData)
 chr [1:3, 1:10] "IC" "29" "B" "IC" "29" "B" "IC" "29" "B" "IC" "29" "B" ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:3] "name" "value" "category"
  ..$ : NULL

我不熟悉這種數據類型。 smallData現在是列表,向量還是其他什么? 我認為,因為apply()返回一個向量或數組,當我從smallData數據框中連續輸入它時,它將以相同的數據格式返回結果。 為什么不是這樣? 我也看了sapply()和lapply(),但它們似乎明確地返回一個列表,這似乎不是我想要的。

我似乎對apply()函數有誤解。 我認為它本質上是'for'循環的矢量化替換,但轉換一個簡單的for循環使用apply()並不像它應該的那樣簡單。

smallData[ ,"category"] <- c("A","B","C")[ 
                   findInterval(smallData[, "value"], c(-Inf,27,30, Inf)

使用cut的建議也是有道理的。 我的偏好是使用來自pkg Hmisc的cut2。 你還使用了一些ifelse任務。 你得到一個矩陣(以及一個字符矩陣)的原因是apply總是返回一個矩陣。 它很容易使用,但通常會對您的數據結構造成極大的破壞。

進一步說明。 當你使用cut你得到一個因子對象,而我上面概述的方法給你一個字符向量。 在某些情況下,您需要一個因子,例如立即為回歸函數准備數據,但我發現最好推遲構造因素。 他們可能會有點痛苦。

正如@Adrian所說,你可以使用cut()

smallData$category <- cut(smallData$value,breaks=c(0,27,30,Inf),
                          labels=c("A","B","C"))

(對結果使用as.character() ,如果@DWin建議,你想要一個character而不是一個factor結果......)

有兩個原因apply於你的想法:

  • 它將結果強制轉換為矩陣,這意味着所有元素都是類型character (包含矩陣中所有數據的最常見類型):from ?apply

    如果'X'不是數組而是具有非空'dim'值的類的對象(例如數據幀),'apply'會嘗試通過'as.matrix'將其強制轉換為數組,如果它是二維(例如,數據幀)或通過'as.array'。

  • apply()在這種情況下有效地轉換你的數組:

    如果每次調用'FUN'都返回一個長度為'n'的向量,那么'apply'將返回一個維度為'c(n,dim(X)[MARGIN])'的數組,如果'n> 1'。

這里的另外兩個答案很棒,它們是解決您問題的更優雅的解決方案。 我在這里添加自己的帖子,以便您可以看到apply語句將如何完成您嘗試執行的操作:

smallData <- data.frame(name = as.character(c("IC","IC","IC","IC","IC","BC","BC","BC","BC","BC")), 
                        value = as.integer(c(29,29,29,29,29,29,29,29,43,26)))

# Create custom categorize function
categorize <- function(r)
{
  if(r < 27) {
    return("A")
  } else if(r < 30) {
    return("B")
  } else {
    return("C")
  }
}

# call to apply
smallData$category <- apply(smallData[match("value", names(smallData))],1,categorize)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM