Добавление строки в фрейм данных

#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