Есть ли функция R, чтобы сделать x строк равными указанной c строке и повторить операцию? - PullRequest
0 голосов
/ 02 апреля 2020

все!

Будучи новичком с программным обеспечением R (я думаю, что мой запрос выполним на этом программном обеспечении), я хотел бы задать вам вопрос.

В большом файле типа Excel у меня есть столбец, значения которого меня интересуют только каждые 193 строки. Поэтому я бы хотел, чтобы предыдущие 192 строки были равны значению 193-й позиции ... и так далее для всех 193 строк до конца столбца.

Конкретно, вот что я хотел бы получить для этого небольшого примера:

Month    Fund_number    Cluster_ref_INPUT      Expected_output
1        1              1                      1
2        1              1                      1
3        1              3                      1
4        1              1                      1
1        3              2                      NA
2        3              NA                     NA
3        3              NA                     NA
4        3              NA                     NA
1        8              4                      5
2        8              5                      5
3        8              5                      5
4        8              5                      5

Столбец «Cluster_ref_INPUT» разделен в соответствии со столбцом «Fund_number» (одно наблюдение для каждого фонда каждый месяц в течение 4 месяцев). Значения, которые меня интересуют в столбце INPUT, появляются каждые 4 наблюдения (значение в 4-м месяце).

Таким образом, мы видим, что для каждого номера фонда мы находим в столбце «Expected_output» значения, соответствующие значению, найденному в последней строке столбца «Cluster_ref_INPUT». (каждые 4 строки). Я думаю, что мы должны разделить "Fund_number" и указать, что все строки равны последней ... что-то в этом роде?

У вас есть идеи, какой код я должен использовать, чтобы эта работа работала?

Надеюсь, это достаточно ясно. Не стесняйтесь, если мне нужно уточнить.

Большое спасибо заранее,

Ван ie

Ответы [ 2 ]

2 голосов
/ 02 апреля 2020

Вот решение с одной строкой, использующее data.table:

library(data.table)

exdata <- fread(text = "
  Month    Fund_number    Cluster_ref_INPUT      Expected_output
  1        1              1                      1
  2        1              1                      1
  3        1              3                      1
  4        1              1                      1
  1        2              2                      NA
  2        2              NA                     NA
  3        2              NA                     NA
  4        2              NA                     NA
  1        3              4                      5
  2        3              5                      5
  3        3              5                      5
  4        3              5                      5")
# You can read you data directly as data.table using fread or convert using setDT(exdata)

exdata[, newvar := Cluster_ref_INPUT[.N], by = Fund_number]

> exdata
    Month Fund_number Cluster_ref_INPUT Expected_output newvar
 1:     1           1                 1               1      1
 2:     2           1                 1               1      1
 3:     3           1                 3               1      1
 4:     4           1                 1               1      1
 5:     1           2                 2              NA     NA
 6:     2           2                NA              NA     NA
 7:     3           2                NA              NA     NA
 8:     4           2                NA              NA     NA
 9:     1           3                 4               5      5
10:     2           3                 5               5      5
11:     3           3                 5               5      5
12:     4           3                 5               5      5
0 голосов
/ 02 апреля 2020

Возможно, есть решения, использующие tidyverse, которые будут намного быстрее, но вот решение в base R.

#Your data
df <- data.frame(Month = rep_len(c(1:4), 12), 
                 Fund_number = rep(c(1:3), each = 4), 
                 Cluster_ref_INPUT = c(1, 1, 3, 1, 2, NA, NA, NA, 4, 5, 5, 5), 
                 stringsAsFactors = FALSE)

#Create an empty data frame in which the results will be stored
outdat <- data.frame(Month = c(), Fund_number = c(), Cluster_ref_INPUT = c(), expected_input = c(), stringsAsFactors = FALSE)

#Using a for loop
#Iterate through the list of unique Fund_number values
for(i in 1:length(unique(df$Fund_number))){

  #Subset data pertaining to each unique Fund_number
  curdat <- subset(df, df$Fund_number == unique(df$Fund_number)[i])

  #Take the value of Cluster_ref_Input from the last row
  #And set it as the value for expected_input column for all rows
  curdat$expected_input <- curdat$Cluster_ref_INPUT[nrow(curdat)]

  #Append this modified subset to the output container data frame
  outdat <- rbind(outdat, curdat)

  #Go to next iteration
}

#Remove non-essential looping variables
rm(curdat, i)

outdat
#    Month Fund_number Cluster_ref_INPUT expected_input
# 1      1           1                 1              1
# 2      2           1                 1              1
# 3      3           1                 3              1
# 4      4           1                 1              1
# 5      1           2                 2             NA
# 6      2           2                NA             NA
# 7      3           2                NA             NA
# 8      4           2                NA             NA
# 9      1           3                 4              5
# 10     2           3                 5              5
# 11     3           3                 5              5
# 12     4           3                 5              5

РЕДАКТИРОВАТЬ: дополнительные решения + сравнительный анализ

В комментарии OP к этому ответу я представил несколько более быстрых решений (dplyr и решение data.table из ответа other ), а также провел их сравнение с моделируемой строкой 950,004 набор данных похож на тот, что в примере OP. Код и результаты ниже; весь кодовый блок может быть скопирован и запущен напрямую, если установлены необходимые библиотеки (microbenchmark, dplyr, data.table) и их зависимости. (Если кто-то знает решение, основанное на apply(), он может добавить его здесь.)

rm(list = ls())

#Library for benchmarking
library(microbenchmark)

#Dplyr
library(dplyr)

#Data.table
library(data.table)

#Your data
df <- data.frame(Month = rep_len(c(1:12), 79167), 
                 Fund_number = rep(c(1, 2, 5, 6, 8, 22), each = 158334), 
                 Cluster_ref_INPUT = sample(letters, size = 950004, replace = TRUE), 
                 stringsAsFactors = FALSE)

#Data in format for data.table
df_t <- data.table(Month = rep_len(c(1:12), 79167), 
                   Fund_number = rep(c(1, 2, 5, 6, 8, 22), each = 158334), 
                   Cluster_ref_INPUT = sample(letters, size = 950004, replace = TRUE), 
                   stringsAsFactors = FALSE)

#----------------

#Base R solution


#Using a for loop
#Iterate through the list of unique Fund_number values
base_r_func <- function(df) {
  #Create an empty data frame in which the results will be stored
  outdat <- data.frame(Month = c(), 
                       Fund_number = c(), 
                       Cluster_ref_INPUT = c(), 
                       expected_input = c(), 
                       stringsAsFactors = FALSE)

  for(i in 1:length(unique(df$Fund_number))){

  #Subset data pertaining to each unique Fund_number
  curdat <- subset(df, df$Fund_number == unique(df$Fund_number)[i])

  #Take the value of Cluster_ref_Input from the last row
  #And set it as the value for expected_input column for all rows
  curdat$expected_input <- curdat$Cluster_ref_INPUT[nrow(curdat)]

  #Append this modified subset to the output container data frame
  outdat <- rbind(outdat, curdat)

  #Go to next iteration
  }
  #Remove non-essential looping variables
  rm(curdat, i)

  #This return is needed for the base_r_func function wrapper
  #this code is enclosed in (not necessary otherwise)
  return(outdat)
}



#----------------

#Tidyverse solution

dplyr_func <- function(df){
  df %>% #For actual use, replace this %>% with %<>%
         #and it will write the output back to the input object
    #Group the data by Fund_number
    group_by(Fund_number) %>%
    #Create a new column populated w/ last value from Cluster_ref_INPUT
    mutate(expected_input = last(Cluster_ref_INPUT))
}

#----------------

#Data table solution

dt_func <- function(df_t){

  #For this function, we are using
  #dt_t (created above)

  #Logic similar to dplyr solution
  df_t <- df_t[ , expected_output := Cluster_ref_INPUT[.N], by = Fund_number]

}

dt_func_conv <- function(df){

  #Converting data.frame to data.table format
  df_t <- data.table(df)

  #Logic similar to dplyr solution
  df_t <- df_t[ , expected_output := Cluster_ref_INPUT[.N], by = Fund_number]
}

#----------------

#Benchmarks

bm_vals <- microbenchmark(base_r_func(df), 
                          dplyr_func(df),
                          dt_func(df_t),
                          dt_func_conv(df), times = 8)

bm_vals
# Unit: milliseconds
#              expr       min        lq      mean    median        uq       max neval
#   base_r_func(df) 618.58202 702.30019 721.90643 743.02018 754.87397 756.28077     8
#    dplyr_func(df) 119.18264 123.26038 128.04438 125.64418 133.37712 140.60905     8
#     dt_func(df_t)  38.06384  38.27545  40.94850  38.88269  43.58225  48.04335     8
#  dt_func_conv(df)  48.87009  51.13212  69.62772  54.36058  57.68829 181.78970     8

#----------------

Как видно, использование data.table будет способом к go, если скорость равна необходимость. data.table быстрее, чем dplyr и base R, даже если учитывать издержки преобразования обычного data.frame в data.table (см. Результаты dt_func_conv()).

Редактировать : , следуя комментариям Карлоса Эдуардо Лагосты, используя setDT() для приведения df от data.frame к data.table, накладные расходы на указанное принуждение приближаются к нулю. Ниже приведены значения кода и эталонного кода.

#This version includes the time taken
#to coerce a data.frame to a data.table
dt_func_conv <- function(df){

  #Logic similar to dplyr solution
  #setDT() coerces data.frames to the data.table format
  setDT(df)[ , expected_output := Cluster_ref_INPUT[.N], by = Fund_number]

}

bm_vals
# Unit: milliseconds
#              expr       min        lq      mean    median        uq       max neval
#   base_r_func(df) 271.60196 344.47280 353.76204 348.53663 368.65696 435.16163     8
#    dplyr_func(df) 121.31239 122.67096 138.54481 128.78134 138.72509 206.69133     8
#     dt_func(df_t)  38.21601  38.57787  40.79427  39.53428  43.14732  45.61921     8
#  dt_func_conv(df)  41.11210  43.28519  46.72589  46.74063  50.16052  52.32235     8

Специально для OP: какое бы решение вы ни использовали sh, код, который вы ищете, находится внутри тела соответствующая функция. Так, например, если вы хотите использовать решение dplyr, вам нужно взять этот код и адаптировать его к вашим объектам данных:

df %>% #For actual use, replace this %>% with %<>%
         #and it will write the output back to the input object
    #Group the data by Fund_number
    group_by(Fund_number) %>%
    #Create a new column populated w/ last value from Cluster_ref_INPUT
    mutate(expected_input = last(Cluster_ref_INPUT))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...