tapply возвращает NA для каждого уровня индекса фактора или настаивает на том, что объект и индекс имеют разную длину - PullRequest
1 голос
/ 05 июля 2019

Я пытаюсь использовать tapply, чтобы получить средний вес пойманных черепах в день.tapply возвращает NA для каждого значения даты (класс: POSIXct) для каждого подхода, который я пробовал

, который я пробовал: вызов tapply для столбца веса и столбца даты -> аргументы имеют разную длину ошибка

удаление записей со значениями NA в столбце веса моего фрейма данных с последующим вызовом tapply для столбца веса и столбца даты.-> аргументы имеют разную длину ошибки

вызывает tapply при вызове na.omit столбца веса и столбца даты, проиндексированного вызовом na.omit столбца веса -> аргументы имеют ошибку различной длины

вызов tapply для вызова na.omit столбца веса и столбца даты с факторами, проиндексированных вызовом na.omit столбца веса -> возвращает NA для каждого уровня столбца даты с факторами

заголовок исходного фрейма данных

> head(stinkpotData)
       Date     DateCt  Species Turtle.ID ID.Code             Location Recapture Weight.g C.Length.mm
1  6/1/2001 2001-06-01 Stinkpot         1       1   keck lab dock site         0      190          95
2  6/1/2001 2001-06-01 Stinkpot         2      10        Right of dock         0      200         100
3  8/9/2001 2001-08-09 Stinkpot         2      10 #4 Deep Right of lab         1      175         104
4 8/27/2001 2001-08-27 Stinkpot         2      10 #4 Deep Right of lab         1      175         105
5  6/1/2001 2001-06-01 Stinkpot         3      11        Right of dock         0      200         109
6 10/3/2001 2001-10-03 Stinkpot         3      11 #4 Deep Right of lab         1      205         109
  C.Width.mm Female.1.Male.2 Rotation                                  Marks
1         70            <NA>     <NA>                                   <NA>
2         72            <NA>     <NA>                                   <NA>
3         72               2     <NA>                                   Male
4         71               2     <NA>    male, 1 small leech Right front leg
5         74            <NA>     <NA>                          algae covered
6         76               2     <NA> male, 1 lg & 1 sm leech right rear leg

заголовок исходного фрейма данных с записями с пропущенными весами NA (проверено, что NA на самом деле опущены)

> head(noNAWeightsDf)
       Date     DateCt  Species Turtle.ID ID.Code             Location Recapture Weight.g C.Length.mm
1  6/1/2001 2001-06-01 Stinkpot         1       1   keck lab dock site         0      190          95
2  6/1/2001 2001-06-01 Stinkpot         2      10        Right of dock         0      200         100
3  8/9/2001 2001-08-09 Stinkpot         2      10 #4 Deep Right of lab         1      175         104
4 8/27/2001 2001-08-27 Stinkpot         2      10 #4 Deep Right of lab         1      175         105
5  6/1/2001 2001-06-01 Stinkpot         3      11        Right of dock         0      200         109
6 10/3/2001 2001-10-03 Stinkpot         3      11 #4 Deep Right of lab         1      205         109
  C.Width.mm Female.1.Male.2 Rotation                                  Marks
1         70            <NA>     <NA>                                   <NA>
2         72            <NA>     <NA>                                   <NA>
3         72               2     <NA>                                   Male
4         71               2     <NA>    male, 1 small leech Right front leg
5         74            <NA>     <NA>                          algae covered
6         76               2     <NA> male, 1 lg & 1 sm leech right rear leg

, вызывая tapply для столбцов висходный фрейм данных

> tapply(stinkpotData$Weight.g, stinkpotData$DateCt, FUN = mean)
Error in tapply(stinkpotData$Weight.g, stinkpotData$DateCt, FUN = mean) : 
  arguments must have same length

, вызывающий tapply по столбцам в фрейме данных noNA

>tapply(noNAWeightsDf$Weight.g, noNAWeightsDf$DateCt, FUN = mean)
Error in tapply(noNAWeightsDf$Weight.g, noNAWeightsDf$DateCt, FUN = mean) : 
  arguments must have same length

, вызывающий tapply при вызове na.omit столбца веса и столбца даты

> tapply(na.omit(stinkpotData$Weight.g), stinkpotData$DateCt[!is.na(stinkpotData$Weight.g)], FUN = mean)
Error in tapply(na.omit(stinkpotData$Weight.g), stinkpotData$DateCt[!is.na(stinkpotData$Weight.g)],  : 
  arguments must have same length

, вызывающий tapply при вызове na.omit столбца веса, а фактор-

coerced date column indexed by the na.omit call of the weight column 
tapply(na.omit(stinkpotData$Weight.g), as.factor(stinkpotData$DateCt[!is.na(stinkpotData$Weight.g)]), FUN = mean)
2001-01-07 2001-06-01 2001-06-04 2001-06-06 2001-06-07 2001-06-11 2001-06-12 2001-06-15 2001-06-19 
        NA         NA         NA         NA         NA         NA         NA         NA         NA 
2001-06-20 2001-06-25 2001-06-27 2001-06-29 2001-07-03 2001-07-09 2001-07-11 2001-07-13 2001-07-16 
        NA         NA         NA         NA         NA         NA         NA         NA         NA ................etc

There were 50 or more warnings (use warnings() to see the first 50)

, вызывающий warnings () после вышеуказанной ошибки, дает:

> warnings()
Warning messages:
1: In mean.default(X[[i]], ...) :
  argument is not numeric or logical: returning NA
2: In mean.default(X[[i]], ...) :
  argument is not numeric or logical: returning NA
3: In mean.default(X[[i]], ...) :
  argument is not numeric or logical: returning NA
.......................etc

РЕДАКТИРОВАТЬ:

split(na.omit(stinkpotData$Weight.g), as.factor(stinkpotData$DateCt[!is.na(stinkpotData$Weight.g)])) Дали список индивидуальных весов черепах на каждую дату.Проверено, что это был список режимов.Его элементы имели числовой режим, классовый фактор.lapply в разделенном списке с FUN = означает, что по-прежнему возвращается NA для каждого уровня даты.Можно получить средствами отдельных элементов разделенного списка по принуждению к векторам, но не совсем то, что мне нужно.

РЕДАКТИРОВАТЬ 2: Наконец-то я получил желаемый результат, но шаги к нему кажутся слишком сложными, и я до сих пор не понимаю, почему использование tapply не сработает.Мне пришлось вызвать split, как при первом редактировании, затем привести каждый элемент результирующего списка к числовому классу (первоначально возвращенному как фактор класса) с помощью lapply, а затем вызвать среднее значение для каждого элемента с помощью lapply:

weightsDateList = split(na.omit(stinkpotData$Weight.g), as.factor(stinkpotData$DateCt[!is.na(stinkpotData$Weight.g)]))
weightsDateList = lapply(weightsDateList, FUN = as.numeric)
weightsDateList = lapply(weightsDateList, FUN = mean)

РЕДАКТИРОВАТЬ 3: Теперь я понимаю, что результат, который я получаю от решения в EDIT 2 и вызова tapply (сильно недооценивает средства, так что все еще потеряно.

EDIT 4: понял, что преобразование веса в числовой класс вернул числоуровень веса с того момента, когда он был фактором, который объясняет серьезную недооценку средств.

Я хочу, чтобы колокольный звонок возвращался каждую дату с весом (ями) черепах и их соответствующим средним весом пойманных черепахэти даты. Спасибо, и я прошу прощения, если я что-то упустил.

1 Ответ

0 голосов
/ 06 июля 2019

Как правило, для использования tapply вы должны соблюдать следующие правила относительно его аргументов:

  • Первый аргумент должен быть или приведен к логическому, целому или числовому. Факторы, символы или другие типы не могут быть использованы здесь.

  • Второй аргумент должен быть или приведен к фактору, который может быть любым базовым типом данных с исключениями для более сложных типов. Это включает в себя несколько группировок, если использовать list(), где tapply затем возвращает матрицу.

    • Поскольку этот аргумент принимает только факторы, его избыточно использовать с as.factor(), что, вероятно, tapply уже делает под капотом.
  • Третий аргумент должен быть функцией, которая возвращает атомное числовое значение для каждого ввода (т. Е. Первый аргумент), разбитого по группам (т. Е. Второму аргументу).
  • Длина: Первый и второй аргументы должны иметь одинаковую длину, которая указывается, если оба они получены из фрейма данных, поскольку фреймы данных по определению являются объектом class типа list, который содержит равные длина атомных векторов.
    • Из-за этого правила избегайте выполнения различных операций с первым или вторым аргументом, так как это может привести к разной длины. Вместо этого либо выполните одну и ту же операцию для обоих векторов, либо еще лучше выполните операцию для всего фрейма данных перед вызовом tapply:
    • Поскольку каждый NA поддерживает длину один (в отличие от NULL), его присутствие не имеет значения в tapply. Однако у дочерней функции могут быть проблемы с NA, которые tapply поднимает вверх по течению.

В частности, ваша проблема касается оригинальных типов: тип фактора Weight.g и POSIXlt тип DateCt . Рассмотрите возможность преобразования этих типов в tapply.

Но не приводите эти исходные типы напрямую к factor, так как лежащие в его основе числовые значения или номер уровня фактора приведут к нежелательным результатам. Для преобразования чисел приведите сначала к character. Для POSIXlt приведите к Date или character. Ниже показано, как OP dput первых десяти строк с другими методами группировки.

Данные (только два соответствующих столбца)

stinkpotDataDeparsed <- structure(list(Weight.g = structure(c(15L, 13L, 20L, 16L, 15L, 
12L, NA, 12L, 15L, 20L, 26L), .Label = c("100", "105", "106", 
"107", "110", "115", "1150", "120", "125", "126", "128", "130", 
"135", "138", "140", "145", "150", "155", "159", "160", "165", 
"168", "170", "175", "180", "185", "187", "190", "195", "20", 
"200", "205", "210", "215", "220", "225", "230", "235", "245", 
"250", "40", "45", "50", "55", "60", "65", "70", "75", "80", 
"85", "90", "95", "oops!"), class = "factor"), DateCt = structure(list(
    sec = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), min = c(0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), hour = c(0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), mday = c(20L, 30L, 8L, 29L, 
    23L, 26L, 12L, 17L, 29L, 13L, 4L), mon = c(8L, 8L, 10L, 10L, 
    5L, 5L, 6L, 6L, 6L, 5L, 5L), year = c(101L, 101L, 101L, 101L, 
    102L, 102L, 102L, 102L, 102L, 103L, 101L), wday = c(4L, 0L, 
    4L, 4L, 0L, 3L, 5L, 3L, 1L, 5L, 1L), yday = c(262L, 272L, 
    311L, 332L, 173L, 176L, 192L, 197L, 209L, 163L, 154L), isdst = c(0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), zone = c("EST", 
    "EST", "EST", "EST", "EST", "EST", "EST", "EST", "EST", "EST", 
    "EST"), gmtoff = c(NA_integer_, NA_integer_, NA_integer_, 
    NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, 
    NA_integer_, NA_integer_, NA_integer_)), .Names = c("sec", 
"min", "hour", "mday", "mon", "year", "wday", "yday", "isdst", 
"zone", "gmtoff"), class = c("POSIXlt", "POSIXt"), tzone = c("EST", 
"EST", "   "))), .Names = c("Weight.g", "DateCt"), row.names = 60:70, class = "data.frame")

Очистка

# REMOVE NAs FROM DATA FRAME TO RUN ON ALL COLUMNS BUT DOES NOT MATTER W/ tapply
stinkpotDataDeparsed <- stinkpotDataDeparsed[!is.na(stinkpotDataDeparsed$Weight.g),]

# CAST FACTOR TYPE TO NUMERIC    
stinkpotDataDeparsed$Weight.g <- as.numeric(as.character(stinkpotDataDeparsed$Weight.g))

# CAST POISXlt TO DATE OR CHARACTER FOR FACTOR-ABILITY
stinkpotDataDeparsed$DateCt <- as.Date(stinkpotDataDeparsed$DateCt)
# stinkpotDataDeparsed$DateCt <- as.character(stinkpotDataDeparsed$DateCt)

Tapply (возвращает вектор)

with(stinkpotDataDeparsed, tapply(Weight.g, DateCt, mean))     

# 2001-06-04 2001-09-20 2001-09-30 2001-11-08 2001-11-29 2002-06-23 2002-06-26 2002-07-17 2002-07-29 2003-06-13 
#        185        140        135        160        145        140        130        130        140        160 

Агрегат (возвращает фрейм данных)

aggregate(Weight.g ~ DateCt, data = stinkpotDataDeparsed, mean)

#        DateCt Weight.g
# 1  2001-06-04      185
# 2  2001-09-20      140
# 3  2001-09-30      135
# 4  2001-11-08      160
# 5  2001-11-29      145
# 6  2002-06-23      140
# 7  2002-06-26      130
# 8  2002-07-17      130
# 9  2002-07-29      140
# 10 2003-06-13      160

Ave (возвращает вектор такой же длины, что и входной, поэтому может быть назначен столбец фрейма данных)

stinkpotDataDeparsed$Wgt.Mean <- with(stinkpotDataDeparsed, ave(Weight.g, DateCt, FUN=mean))
stinkpotDataDeparsed

#    Weight.g     DateCt Wgt.Mean
# 60      140 2001-09-20      140
# 61      135 2001-09-30      135
# 62      160 2001-11-08      160
# 63      145 2001-11-29      145
# 64      140 2002-06-23      140
# 65      130 2002-06-26      130
# 67      130 2002-07-17      130
# 68      140 2002-07-29      140
# 69      160 2003-06-13      160
# 70      185 2001-06-04      185

By (объектно-ориентированная оболочка для tapply, возвращает список)

by(stinkpotDataDeparsed, stinkpotDataDeparsed$DateCt, FUN=function(sub) mean(sub$Weight.g))

# stinkpotDataDeparsed$DateCt: 2001-06-04
# [1] 185
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2001-09-20
# [1] 140
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2001-09-30
# [1] 135
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2001-11-08
# [1] 160
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2001-11-29
# [1] 145
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2002-06-23
# [1] 140
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2002-06-26
# [1] 130
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2002-07-17
# [1] 130
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2002-07-29
# [1] 140
# ------------------------------------------------------------ 
# stinkpotDataDeparsed$DateCt: 2003-06-13
# [1] 160

Rextester Demo

...