C или Rcpp: сравнение двух векторов без цикла

#c #r #rcpp

#c #r #rcpp

Вопрос:

Я новичок в C и Rcpp, и мне интересно, как сравнить каждый элемент двух разных векторов без цикла одновременно.

Моя цель — изменить элемент v1 путем ссылки на другой вектор. `

Текущий код

 v1 = {6,7,8,9,10}
v2 = {2,4,6,8,10}
v3 = {a,b,a,b,c}
v4 = {0,0,0,0,0}
v5 = {a,b,c}
v6 = {1,2,3}

for (i in 1:5){
  if (v1[i] > v2[i]){
    for (j in 1:3){
      if (v5[j] == v3[i]){
        v4[i] = v2[i]   v6[j]
          if (v1[i] > v4[i]){
            v1[i] = v4[i]
          }
      }
    }
  }
}  
 

Результат должен быть

 v1 = {3,6,7,9,10}
 

На самом деле, v1, v2, v3, v4 и v5, v6 отличаются dataframe в R. Каждый элемент v1 сравнивается с v2 . Если элемент i in v1 больше, чем i элемент in v2 , элемент of v1 становится суммой i элемента of v1 и элемента of v6 по соответствующему v3 amp; v5 . Затем сравнивается новое оцененное значение v4[i] v1[i] .

У меня есть большое количество случаев в v1~v5 и. v5~v6 В этом случае использование loop занимает много времени. Можно ли сравнивать разные векторы без цикла? или как оценить и ссылаться на элемент другого вектора?

Комментарии:

1. Можете ли вы расширить свои требования? Что вы сравниваете и что вы делаете с результатом? Пример с ожидаемым результатом всегда полезен для других, чтобы увидеть, что вы делаете.

2. Это реальная проблема или домашнее задание? Если это домашнее задание, то каковы параметры? Рекурсию можно использовать, чтобы избежать «циклов», но непонятно, почему вы пытаетесь избежать циклов.

3. Ваш пример кода не выдает выходных данных. Если первые два вектора эквивалентны, кажется, ваша цель — никогда не выполнять сравнение между v1 и v3? Вы хотите вернуть индикатор того, что v2 является первым вектором, эквивалентным v1?

4. Я действительно прошу прощения за путаницу в моем вопросе. Я добавляю больше информации и цели в мою текущую проблему. Я аспирант в области социальных наук, и это проблема моего исследования. Я пытаюсь оценить время прохождения между различными пространственными областями. Однако я понятия не имею, как избежать цикла в Rcpp или C в настоящее время. В R это можно было бы легко упростить, но это занимает много времени, когда я пытался из-за большого количества данных.

Ответ №1:

Я не вижу необходимости использовать Rcpp или C здесь. Насколько я понимаю ваши требования, вы пытаетесь манипулировать двумя наборами векторов одинаковой длины. Для «набора векторов равной длины» обычно используется a data.frame или одно из его расширений. Здесь я использую базу R data.table и dplyr with tibble . Посмотрите сами, какой синтаксис вы предпочитаете. Вообще говоря, data.table скорее всего, будет быстрее для больших наборов данных.

Установочные данные:

 v1 <- c(6,7,8,9,10)
v2 <- c(2,4,6,8,10)
v3 <- c("a","b","a","b","c")
v5 <- c("a","b","c")
v6 <- c(1,2,3)
 

База R:

 df1 <- data.frame(v1, v2, v3)
df2 <- data.frame(v5, v6)

df1 <- merge(df1, df2, by.x = "v3", by = "v5")
df1$v4 <- df1$v2   df1$v6
df1$v1 <- ifelse(df1$v1 > df1$v2 amp; df1$v1 > df1$v4, df1[["v4"]], df1[["v1"]])
df1
#>   v3 v1 v2 v6 v4
#> 1  a  3  2  1  3
#> 2  a  7  6  1  7
#> 3  b  6  4  2  6
#> 4  b  9  8  2 10
#> 5  c 10 10  3 13
 

data.table :

 library(data.table)
dt1 <- data.table(v1, v2, v3, key = "v3")
dt2 <- data.table(v5, v6, key = "v5")

dt1[dt2, v4 := v2   v6]
dt1[v1 > v2 amp; v1 > v4, v1 := v4]
dt1
#>    v1 v2 v3 v4
#> 1:  3  2  a  3
#> 2:  7  6  a  7
#> 3:  6  4  b  6
#> 4:  9  8  b 10
#> 5: 10 10  c 13
 

dplyr :

 suppressPackageStartupMessages(library(dplyr))
t1 <- tibble(v1, v2, v3)
t2 <- tibble(v5, v6)
t1 %>% 
  inner_join(t2, by = c("v3" = "v5")) %>%
  mutate(v4 = v2   v6) %>%
  mutate(v1 = case_when(
    v1 > v2 amp; v1 > v4 ~ v4,
    TRUE ~ v1
  ))
#> # A tibble: 5 x 5
#>      v1    v2 v3       v6    v4
#>   <dbl> <dbl> <chr> <dbl> <dbl>
#> 1     3     2 a         1     3
#> 2     6     4 b         2     6
#> 3     7     6 a         1     7
#> 4     9     8 b         2    10
#> 5    10    10 c         3    13
 

Создано 2019-04-19 пакетом reprex (версия 0.2.1)

Общая идея всегда одна и та же:

  • соедините две таблицы в столбце символов
  • создайте новый столбец v4 как сумму v2 и v6
  • обновите v1 значение v4 где v1 > v2 и v1 > v4

Обратите внимание, что базовые R и data.table не сохраняют порядок, поэтому было бы разумнее поместить выходные данные в дополнительный столбец.

Комментарии:

1. Я действительно ценю ваш ответ. Я понятия не имел о data.table и tibble! Еще раз спасибо за ваш ответ.

2. @Suralira. K Добро пожаловать. Смотрите Обновленный ответ для базового решения R. Кстати, обычный способ сказать «спасибо» на SO — это проголосовать и / или принять ответы.

3. Извините за мое позднее согласие с вашими ответами. Кстати, не могли бы вы сообщить мне еще одну вещь? Хотя я не включил в приведенный выше вопрос, я должен повторить вышеуказанную функцию. Вышеуказанные коды можно использовать в цикле for . Однако у меня около 300 000 случаев, цикл for должен повторяться около 300 000. Когда я пытался, это занимало много времени. Из-за этого повторения я рассмотрел Rcpp. Не могли бы вы сообщить мне, чтобы ускорить его, используя ваш ответ? Я попытался выполнить цикл с помощью data.table, но это все равно занимает больше времени, чем Rcpp.

4. @Suralira. K Это трудно оценить без более подробной информации. Насколько велик один случай? По моему опыту, типичные задачи, такие как объединение и группирование для больших наборов данных, выполняются быстрее всего с data.table. Для многих небольших наборов данных все может быть иначе. В таком случае я бы попытался объединить наборы данных и использовать группировку.