Как преобразовать выбранные строки в один столбец в R

У меня есть фрейм данных, который мне нужно преобразовать. Мне нужно изменить уникальные строки на отдельные столбцы на основе значения столбца.

Мои данные ниже:

df1 <- data.frame(V1 = c("a", "a", "b", "b","b"), 
                  V2 = c("product1", "transport", "product1", "product2","transport"),
                  V3 = c("100", "10", "100", "100","10"))

> df1
  V1        V2  V3
1  a  product1 100
2  a transport  10
3  b  product1 100
4  b  product2 100
5  b transport  10

Мне нужно следующее преобразование и деление стоимости V3 на количество продуктов, входящих в V1.

> df2
  V1       V2 transport  V3
1  a product1        10 100
2  b product1         5 100
3  b product2         5 100
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
78
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

Вот один из способов с data.table — преобразовать в data.table (setDT), убедиться, что «V3» — это numeric (для деления — он был создан как символ), сгруппировать по «V1», создать «транспорт», извлекая «V3 ' значение, где "V2" означает "транспорт" и разделить на количество элементов в "V2", которые не являются "транспортом", затем подмножить данные, удалив элементы "транспорт" из "V2"

library(data.table)
df1$V3 <- as.numeric(df1$V3)
setDT(df1)[, transport := V3[V2 == "transport"]/
       sum(V2 != "transport"), by = V1]
df1[V2 != "transport"]
       V1       V2    V3 transport
   <char>   <char> <num>     <num>
1:      a product1   100        10
2:      b product1   100         5
3:      b product2   100         5

Или другой вариант с dplyr/tidyr

library(dplyr)
library(tidyr)
df1 %>%
   type.convert(as.is = TRUE) %>% 
   mutate(transport = case_when(V2 == 'transport' ~ V3)) %>% 
   group_by(V1) %>%
   fill(transport, .direction = "downup") %>%
   mutate(transport = transport/sum(V2 != "transport")) %>% 
   ungroup %>% 
   filter(V2 != "transport")
# A tibble: 3 × 4
  V1    V2          V3 transport
  <chr> <chr>    <int>     <dbl>
1 a     product1   100        10
2 b     product1   100         5
3 b     product2   100         5

Вот решение на основе tidyverse с использованием tidyr и dplyr:

  1. преобразовать V3 в числовой
  2. поверните шире, чтобы создать отдельный столбец для transport, затем поверните длиннее, чтобы свернуть "product1" и "product2" обратно в один столбец
  3. разделите transport на количество случаев в V1.
library(dplyr)
library(tidyr)

df1 %>% 
  mutate(V3 = as.numeric(V3)) %>% 
  pivot_wider(names_from = V2, values_from = V3) %>% 
  pivot_longer(
    cols = c(product1, product2), 
    names_to = "V2", 
    values_to = "V3", 
    values_drop_na = TRUE
  ) %>% 
  group_by(V1) %>% 
  mutate(transport = transport / n()) %>% 
  ungroup()

#> # A tibble: 3 x 4
#>   V1    transport V2          V3
#>   <chr>     <dbl> <chr>    <dbl>
#> 1 a            10 product1   100
#> 2 b             5 product1   100
#> 3 b             5 product2   100

Created on 2022-03-17 by the reprex package (v2.0.1)

Вот еще один подход к получению желаемого результата, если я правильно понял вашу точку зрения:

library(dplyr)
library(tidyr)

df1 %>%
  group_by(V1) %>%
  mutate(V3 = ifelse(V2 == "transport", as.numeric(V3) / (n() - 1), as.numeric(V3))) %>%
  ungroup() %>%
  pivot_wider(names_from = V2, values_from = V3) %>%
  pivot_longer(c(product1, product2), names_to = "V2", values_to = "V3") %>%
  drop_na()

# A tibble: 3 x 4
  V1    transport V2          V3
  <chr>     <dbl> <chr>    <dbl>
1 a            10 product1   100
2 b             5 product1   100
3 b             5 product2   100

Другое возможное решение:

library(tidyverse)

df1 %>%
  mutate(V3 = as.numeric(V3)) %>% 
  group_by(V1) %>% 
  mutate(transport = if_else(V2 == "transport", V3 / (n()-1), NA_real_)) %>% 
  fill(transport, .direction = "up") %>% ungroup %>% 
  filter(V2 != "transport")

#> # A tibble: 3 × 4
#>   V1    V2          V3 transport
#>   <chr> <chr>    <dbl>     <dbl>
#> 1 a     product1   100        10
#> 2 b     product1   100         5
#> 3 b     product2   100         5

Вот еще один с pivoting:

library(dplyr)
library(tidyr)

df1 %>% 
  pivot_wider(
    names_from = V2,
    values_from = V3
  ) %>% 
  pivot_longer(
    -c(V1, transport),
    names_to = "V2",
    values_to = "V3"
  )%>% 
  type.convert(as.is = TRUE) %>% 
  na.omit() %>% 
  group_by(V1) %>% 
  mutate(transport = transport/max(row_number()))
  V1    transport V2          V3
  <chr>     <dbl> <chr>    <int>
1 a            10 product1   100
2 b             5 product1   100
3 b             5 product2   100

Мужик, так рад тебя здесь видеть :)

Anoushiravan R 17.03.2022 20:19

Рад тебя видеть, дорогой @Anoushiravan!!!

TarJae 17.03.2022 20:21

Вот подход data.table:

f <- function(p,v) {  
  ps=grepl("^p",p)
  list(V2 = p[ps], transport=rep(v[!ps]/sum(ps), sum(ps)), V3 = v[ps])
}
setDT(df1)[,f(V2,as.numeric(V3)), V1 ]

       V1       V2 transport    V3
   <char>   <char>     <num> <num>
1:      a product1        10   100
2:      b product1         5   100
3:      b product2         5   100

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