Jak mogę "zastosować" funkcję zdefiniowaną przez użytkownika do każdego wiersza ramki danych, jeśli funkcja zdefiniowana przez użytkownika wymaga funkcji jako argument?

Oto przykład ... Powiedzmy, że mam trzy kolumny w ramce danych, każdy zawierający liczby całkowite. Za każdy wiersz chciałbym wziąć minimalną liczbę całkowitą i przekonwertować go na odpowiedni list za pomocą zestawu danych wyszukiwania. Podobnie wykonaj to samo zadanie z MAX Integer. Wynik byłby to:

Col1 | Col2 | Col3 | MaxVal | MinVal |
-------------------------------------
 1      2      1       B        A
 4      4      1       F        A
 5      6      2       F        B

Kod poniżej Przyczyny: Error in $<-.data.frame(*tmp*, "MaxVal", value = integer(0)) : replacement has 0 rows, data has 3

myData <- data.frame("Col1" = c(1, 4, 5), "Col2" = c(2, 6, 6), "Col3" = c(1, 1, 2))
numberToLetterData <- data.frame("Number" = 1:6, "Letter" = c("A", "B","C","D","E","F"))

GetMinOrMaxForRow <- function(x, refData, functionToUse){
    refData$Letter[refData$Number ==  functionToUse(x)]
}

myData$MinVal <- apply(myData, 1, FUN = function(x) GetMinOrMaxForRow(x = x, refData = numberToLetterData, functionToUse = min))
myData$MaxVal <- apply(myData, 1, FUN = function(x) GetMinOrMaxForRow(x = x, refData = numberToLetterData, functionToUse = max))

... Ale następujący kod (z ostatnimi dwoma liniami) działa dobrze:

myData <- data.frame("Col1" = c(1, 4, 5), "Col2" = c(2, 6, 6), "Col3" = c(1, 1, 2))
numberToLetterData <- data.frame("Number" = 1:6, "Letter" = c("A", "B","C","D","E","F"))

GetMinOrMaxForRow <- function(x, refData, functionToUse){
    refData$Letter[refData$Number ==  functionToUse(x)]
}

myData$MaxVal <- apply(myData, 1, FUN = function(x) GetMinOrMaxForRow(x = x, refData = numberToLetterData, functionToUse = max))
myData$MinVal <- apply(myData, 1, FUN = function(x) GetMinOrMaxForRow(x = x, refData = numberToLetterData, functionToUse = min))

... Czy ktoś wie dlaczego?

1
Thomas Wire 16 luty 2017, 19:25

2 odpowiedzi

Najlepsza odpowiedź

Po wywołaniu pierwszej linii przypisujesz MyData $ Minval. W następnym wierszu zbudujesz max nad pełnym wierszem w dataframe, w tym nowej kolumny Minval.

Więc nie zastosuj funkcji do wszystkich kolumn, I.E. MyData [, 1: 3].

myData <- data.frame("Col1" = c(1, 4, 5), "Col2" = c(2, 6, 6), "Col3" = c(1, 1, 2))
numberToLetterData <- data.frame("Number" = 1:6, "Letter" = c("A", "B","C","D","E","F"))

GetMinOrMaxForRow <- function(x, refData, functionToUse){
    refData$Letter[refData$Number ==  functionToUse(x)]
}

myData$MinVal <- apply(myData[,1:3], 1, FUN = function(x) GetMinOrMaxForRow(x = x, refData = numberToLetterData, functionToUse = min))
myData$MaxVal <- apply(myData[,1:3], 1, FUN = function(x) GetMinOrMaxForRow(x = x, refData = numberToLetterData, functionToUse = max))
0
c0bra 16 luty 2017, 16:43

Za pomocą dplyr możesz:

myData %>% 
  rowwise %>% 
  mutate(minVal = lookup[min(Col1, Col2, Col3)],
         maxVal = lookup[max(Col1, Col2, Col3)])

Lub w 2 krokach, więc najpierw obliczanie funkcji, a następnie wykonanie wyszukiwania:

myData %>% 
  rowwise %>% 
  mutate(minVal = min(Col1, Col2, Col3),
         maxVal = max(Col1, Col2, Col3)) %>% 
  mutate_at(vars(minVal, maxVal), function(x) lookup[x])

Używanie purrr możesz zrobić:

require(purrr)
lookup <- setNames(LETTERS[1:6], 1:6)
myData %>% 
  by_row(~lookup[min(.[1:3])], .collate = "cols", .to = "minVal") %>% 
  by_row(~lookup[max(.[1:3])], .collate = "cols", .to = "maxVal")
0
Rentrop 16 luty 2017, 17:03