Mutate возвращает данные в неправильном порядке. dplyr это ошибка?

Я столкнулся с проблемой, когда mutate() в dplyr возвращает результаты в неправильном порядке. Мой вызов mutate использует данные из существующего столбца в качестве входных данных, но результаты возвращаются так, как если бы данные были отсортированы до mutate.

В моей конкретной проблеме используется пакет dataRetrieval для получения данных USGS/NWIS из Интернета. В этом примере я получаю имена сайтов на основе идентификатора сайта. В пакете `dataRetreival идентификатор сайта представляет собой числовой код, хранящийся в виде символа.

library(dataRetrieval)
library(dplyr)

Gauges <- tibble( Name = c("Twisp", "Chewuch", "Andrews" ,"Met@Winthrop", "Met@Twisp", "Met@Pateros", "Met@Goat"),
                  ID = c("12448998" , "12448000","12447390", "12448500" ,"12449500","12449950" , "12447383")
)

## This works correctly with each of the station numbers
readNWISsite(Gauges$ID[1])$station_nm
# [1] "TWISP RIVER NEAR TWISP, WA"

## This does not work correctly
## Order is not right! Station does not correspond with ID  !!
Gauges%>%
      mutate(Station = readNWISsite(ID)$station_nm)

# # A tibble: 7 x 3
# Name         ID       Station                                      
# <chr>        <chr>    <chr>                                        
# 1 Twisp        12448998 METHOW RIVER ABOVE GOAT CREEK NEAR MAZAMA, WA
# 2 Chewuch      12448000 ANDREWS CREEK NEAR MAZAMA, WA                
# 3 Andrews      12447390 CHEWUCH RIVER AT WINTHROP, WA                
# 4 Met@Winthrop 12448500 METHOW RIVER AT WINTHROP, WA                 
# 5 Met@Twisp    12449500 TWISP RIVER NEAR TWISP, WA                   
# 6 Met@Pateros  12449950 METHOW RIVER AT TWISP, WA                    
# 7 Met@Goat     12447383 METHOW RIVER NEAR PATEROS, WA    

## This works, returning the correct site associated with the gauge number
Gauges%>%
      arrange(ID) %>%
      mutate(Station = readNWISsite(ID)$station_nm)
# # A tibble: 7 x 3
# Name         ID       Station                                      
# <chr>        <chr>    <chr>                                        
# 1 Met@Goat     12447383 METHOW RIVER ABOVE GOAT CREEK NEAR MAZAMA, WA
# 2 Andrews      12447390 ANDREWS CREEK NEAR MAZAMA, WA                
# 3 Chewuch      12448000 CHEWUCH RIVER AT WINTHROP, WA                
# 4 Met@Winthrop 12448500 METHOW RIVER AT WINTHROP, WA                 
# 5 Twisp        12448998 TWISP RIVER NEAR TWISP, WA                   
# 6 Met@Twisp    12449500 METHOW RIVER AT TWISP, WA                    
# 7 Met@Pateros  12449950 METHOW RIVER NEAR PATEROS, WA  

Почему mutate переупорядочивает данные в середине процесса? Как вариант, что здесь происходит?


person Brian Fisher    schedule 02.01.2020    source источник


Ответы (1)


Чтобы понять, что происходит, вместо того, чтобы извлекать только «station_nm», получите также «site_no».

library(dplyr)
library(dataRetrieval)
readNWISsite(Gauges$ID)[c('site_no', 'station_nm')]
#site_no                                    station_nm
#1 12447383 METHOW RIVER ABOVE GOAT CREEK NEAR MAZAMA, WA
#2 12447390                 ANDREWS CREEK NEAR MAZAMA, WA
#3 12448000                 CHEWUCH RIVER AT WINTHROP, WA
#4 12448500                  METHOW RIVER AT WINTHROP, WA
#5 12448998                    TWISP RIVER NEAR TWISP, WA
#6 12449500                     METHOW RIVER AT TWISP, WA
#7 12449950                 METHOW RIVER NEAR PATEROS, WA

Здесь «site_no» упорядочивается на основе целочисленных значений «ID». Чтобы исправить это, мы можем применить функцию к каждому «ID» по одному с помощью rowwise

Gauges %>% 
    rowwise() %>% 
    mutate(Station = readNWISsite(ID)$station_nm)

или map из purrr

library(purrr)
Gauges %>%
    mutate(Station = map_chr(ID, ~ readNWISsite(.x)$station_nm))
# A tibble: 7 x 3
#  Name         ID       Station                                      
#  <chr>        <chr>    <chr>                                        
#1 Twisp        12448998 TWISP RIVER NEAR TWISP, WA                   
#2 Chewuch      12448000 CHEWUCH RIVER AT WINTHROP, WA                
#3 Andrews      12447390 ANDREWS CREEK NEAR MAZAMA, WA                
#4 Met@Winthrop 12448500 METHOW RIVER AT WINTHROP, WA                 
#5 Met@Twisp    12449500 METHOW RIVER AT TWISP, WA                    
#6 Met@Pateros  12449950 METHOW RIVER NEAR PATEROS, WA                
#7 Met@Goat     12447383 METHOW RIVER ABOVE GOAT CREEK NEAR MAZAMA, WA

Или мы извлекаем оба столбца и делаем match с «ID» и «site_no».

Gauges %>% 
          mutate(Station = {
           tmp <- readNWISsite(ID)[c('site_no', 'station_nm')]
              tmp$station_nm[match(ID, tmp$site_no)]})
# A tibble: 7 x 3
#  Name         ID       Station                                      
#  <chr>        <chr>    <chr>                                        
#1 Twisp        12448998 TWISP RIVER NEAR TWISP, WA                   
#2 Chewuch      12448000 CHEWUCH RIVER AT WINTHROP, WA                
#3 Andrews      12447390 ANDREWS CREEK NEAR MAZAMA, WA                
#4 Met@Winthrop 12448500 METHOW RIVER AT WINTHROP, WA                 
#5 Met@Twisp    12449500 METHOW RIVER AT TWISP, WA                    
#6 Met@Pateros  12449950 METHOW RIVER NEAR PATEROS, WA                
#7 Met@Goat     12447383 METHOW RIVER ABOVE GOAT CREEK NEAR MAZAMA, WA
person akrun    schedule 02.01.2020
comment
Спасибо @akrun, mutate() по умолчанию сортирует вывод или это особый случай, когда входной столбец представляет собой число, хранящееся как символ или что-то в этом роде? - person Brian Fisher; 02.01.2020
comment
@BrianFisher Нет, mutate вернет строки в том же порядке, но здесь вывод из readNWISsite представляет собой data.frame со многими столбцами, и сортировка происходит на этом уровне. - person akrun; 02.01.2020
comment
Спасибо, @akrun, думаю, это та часть, которую я пропустил. - person Brian Fisher; 02.01.2020