Почему мутация не работает так, как я ожидаю в этом коде?

У меня есть путаница относительно того, как работает мутация в tidyverse/dplyr. Я включил воспроизводимый пример здесь. Один использует мутацию, а другой использует цикл. Я ожидал бы, что оба дадут тот же результат, но это не так. Понятия не имею почему. Любая помощь будет оценена по достоинству.

library(tidyverse)
d <- data.frame(x = c('a,a,b,b,b','a,a','a,b,b,b,c,c,c'))
# Approach 1 (mutate)
d %>% 
  mutate(y = paste(unique(str_split(x, ',')[[1]]), collapse = ','))
d
# Approach 2 (loop)
for (i in 1:nrow(d))
{
  d$y[i] <- paste(unique(str_split(d$x[i], ',')[[1]]), collapse = ',')
}
d

Я ожидаю, что результат будет одинаковым для обоих подходов, но это не так.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
42
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что мы подмножаем только первый элемент list с [[1]], а затем unique находится только в этом элементе. Вместо этого нам нужно перебрать list (из вывода str_split)

library(tidyverse) 
d %>%
     mutate(y = str_split(x, ',') %>%  # output is a list
                   map_chr(~ unique(.x) %>% # loop with map, get the unique elements 
                    toString)) # paste the strings together
#             x       y
#1     a,a,b,b,b    a, b
#2           a,a       a
#3 a,b,b,b,c,c,c a, b, c

В цикле for этого не было, потому что разбиение производилось по одному элементу за раз str_split(d$x[i]


Чтобы лучше понять, str_split (strsplit базовый R) is vectorized. They can take multiple strings and split into alistofвектор равен длине исходного вектора

str_split(d$x, ',') # list of length 3
#[[1]]
#[1] "a" "a" "b" "b" "b"

#[[2]]
#[1] "a" "a"

#[[3]]
#[1] "a" "b" "b" "b" "c" "c" "c"

Извлечение первого [[1]]

str_split(d$x, ',')[[1]]
#[1] "a" "a" "b" "b" "b"

В цикле for мы разделяем элементы по отдельности и извлекаем элемент списка (длина 1).

str_split(d$x[1], ',')[[1]]
#[1] "a" "a" "b" "b" "b"
str_split(d$x[2], ',')[[1]]
#[1] "a" "a"

По этой причине нам нужно перебрать list, а затем получить unique из каждого элемента.

Означает ли это, что «мутация» не выполняет вычисление по одному элементу за раз? Итак, «x» в mutate — это весь столбец, а не одна ячейка за раз?

PraGalaxy 27.05.2019 23:32

@PraGalaxy Это не имеет ничего общего с mutate. Вы можете проверить, что str_split(d$x, ",") возвращает list из vectors. Когда вы делаете [[1]], вы извлекаете только первый элемент list

akrun 27.05.2019 23:33

Спасибо, кажется, теперь я понял. Кроме того, я провел некоторое исследование и выяснил, что «мутация» применяется к столбцу сразу. Он отлично работает с функциями, которые векторизованы. Но здесь str_split не векторизован и выводит список, отсюда и проблема. Это правильно?

PraGalaxy 27.05.2019 23:42

@PraGalaxy str_split векторизован, и именно поэтому он разбивает более 1 элемента за раз на list из vectors. В цикле for вы разделяете один элемент/строку (d$x[i]) за раз, и в этом разница. Но в обоих случаях strsplit возвращает список. Разница в длине list. Здесь это будет list длины 3. Итак, если есть list длины 1, извлеките его с помощью [[1]], он вернет элемент. Для списка длины 3 выполнение того же действия возвращает только первый

akrun 27.05.2019 23:44

Другие вопросы по теме