#r #rows
#r #строки
Вопрос:
У меня есть df, подобный этому:
x <- data.frame("Year" = c(1945,1945,1946,1946,1947,1947), "Age" = c(1,2,1,2,1,2), "Value" = c(4,5,4,5,4,6))
Я хотел бы добавить новые строки на основе некоторых условий:
Например, я хочу добавить вторую строку, которая имеет тот же «ГОД» и «ВОЗРАСТ», что и первая строка, но значение является значением первой строки minis 1.
Я хочу, чтобы мой результат выглядел так:
x <- data.frame("Year" = c(1945, 1945,1945,1945,1946,1946,1946,1946,1947,1947,1947,1947), "Age" = c(1,1,2,2,1,1,2,2,1,1,2,2), "Value" = c(4,3,5,4,4,3,5,4,4,3,5,4))
Спасибо за помощь новичку.
Комментарии:
1. Я не совсем понимаю ваши условия — вы можете уточнить? Например, почему
5
в строке 3 в вашем желаемом выводе?2. Вы можете попробовать это:
value <- data.frame(x$Year, x$Value-1, x$Age)
тогдаcolnames(value) <- c("Year", "Value", "Age")
и, наконецp <- full_join(x, value, by = c("Year", "Value", "Age"))
.value
создает фрейм данных с нужными значениями.colnames
изменяет имена столбцов в соответствии с оригиналом. иfull_join
объединяет два фрейма данных по именам их столбцов.
Ответ №1:
Вы могли бы сделать это так:
#original df
x <- data.frame("Year" = c(1945,1945,1946,1946,1947,1947), "Age" = c(1,2,1,2,1,2),"Value" = c(4,5,4,5,4,6))
#replicate df with value minus 1
y <- data.frame(x[,c("Year", "Age")], Value = x[,"Value"] -1)
#combine
z <- rbind(x,y)
z[order(z$Year, z$Age),]
Year Age Value
1 1945 1 4
7 1945 1 3
2 1945 2 5
8 1945 2 4
3 1946 1 4
9 1946 1 3
4 1946 2 5
10 1946 2 4
5 1947 1 4
11 1947 1 3
6 1947 2 6
12 1947 2 5
Конечно, приведенный выше код можно было бы сократить, например, до этого при непосредственном обновлении вашего фрейма данных x.
x <- rbind(x, data.frame(x[,c("Year", "Age")], Value = x[,"Value"] -1))
Как указано в комментарии ниже, код можно было бы еще больше сократить (и сделать более читабельным), используя transform()
или within()
.
x <- rbind(x, transform(x, Value = Value - 1))
x <- rbind(x, within(x, Value <- Value - 1))
Ответ №2:
В base
, вы можете повторить каждую строку дважды и добавить переработанный 0:-1
в Value
.
within(x[rep(1:nrow(x), each = 2), ], Value <- Value 0:-1)
Его tidyverse
версия
library(tidyverse)
x %>%
uncount(2) %>%
mutate(Value = Value 0:-1)
Оба они дают следующее. Выходные данные упорядочены правильно, поэтому вам не нужно использовать order()
или arrange()
.
Year Age Value
1 1945 1 4
2 1945 1 3
3 1945 2 5
4 1945 2 4
5 1946 1 4
6 1946 1 3
7 1946 2 5
8 1946 2 4
9 1947 1 4
10 1947 1 3
11 1947 2 6
12 1947 2 5
Ответ №3:
Работает ли это:
library(dplyr)
x %>% inner_join(x %>% select(1)) %>% group_by(Year, Age) %>%
mutate(Value = case_when(row_number() == 2 ~ Value - 1, TRUE ~ Value))
Joining, by = "Year"
# A tibble: 12 x 3
# Groups: Year, Age [6]
Year Age Value
<dbl> <dbl> <dbl>
1 1945 1 4
2 1945 1 3
3 1945 2 5
4 1945 2 4
5 1946 1 4
6 1946 1 3
7 1946 2 5
8 1946 2 4
9 1947 1 4
10 1947 1 3
11 1947 2 6
12 1947 2 5
Используемые данные:
x
Year Age Value
1 1945 1 4
2 1945 2 5
3 1946 1 4
4 1946 2 5
5 1947 1 4
6 1947 2 6