R中列值的条件排序/重新排序

时间:2019-05-21 00:02:14

标签: r sorting

我有一个类似于以下的数据集,具有1列60行:

    value 
 1 0.0423 
 2 0.0388 
 3 0.0386 
 4 0.0342 
 5 0.0296 
 6 0.0276 
 7 0.0246 
 8 0.0239 
 9 0.0234 
10 0.0214 
 .
40 0.1424
 .
60 -0.0312

我想对行进行重新排序,以便满足某些条件。例如,一个条件可能是:sum(df$value[4:7]) > 0.1000sum(df$value[4:7]) <0.1100

例如,数据集如下所示。

    value 
 1 0.0423 
 2 0.0388 
 3 0.0386 
 4 0.1312
 5 -0.0312
 6 0.0276 
 7 0.0246 
 8 0.0239 
 9 0.0234 
10 0.0214 
 .
 .
 .
60 0.0342

我尝试使用repeatsample,如下所示:

repeat{ 
       df1 <- as_tibble(sample(sdf$value, replace = TRUE))
    if (sum(df$value[4:7]) > 0.1000 &  sum(df$value[4:7]) <0.1100) break
    }

不幸的是,这种方法需要花费很多时间,我想知道是否存在一种更快的方法,可以基于数学条件(例如sumprod

)对行​​进行重新排序。

2 个答案:

答案 0 :(得分:2)

这是我在评论中概述的爬山方法的快速实现。我必须将所需条件略微改组为“ sum(x[4:7])与0.105的距离”以使其连续,尽管在进行检查是否满足所有要求时仍可以使用精确条件。好处是您可以轻松地向距离功能添加额外条件。

# Using same example data as Jon Spring
set.seed(42)
vs = rnorm(60, 0.05, 0.08)

get_distance = function(x) {
    distance = abs(sum(x[4:7]) - 0.105)
    # Add to the distance with further conditions if needed
    distance
}

max_attempts = 10000
best_distance = Inf

swaps_made = 0
for (step in 1:max_attempts) {
    # Copy the vector and swap two random values
    new_vs = vs
    swap_inds = sample.int(length(vs), 2, replace = FALSE)
    new_vs[swap_inds] = rev(new_vs[swap_inds])

    # Keep the new vector if the distance has improved
    new_distance = get_distance(new_vs)
    if (new_distance < best_distance) {
        vs = new_vs
        best_distance = new_distance
        swaps_made = swaps_made + 1
    }

    complete = (sum(vs[4:7]) < 0.11) & (sum(vs[4:7]) > 0.1)
    if (complete) {
        print(paste0("Solution found in ", step, " steps"))
        break
    }
}

sum(vs[4:7])

不能真正保证此方法能够解决问题,但是当我不确定是否有解决问题的“智能”方法时,我经常尝试这种基本的爬坡方式。

答案 1 :(得分:1)

这是一种使用基数R中的combn,然后使用dplyr进行过滤的方法。 (我确定有一种方法可以解决,但我的基本功还没有。)

60个池中只有4个数字,因此只有“ 488k”不同的组合(忽略顺序; = 60 * 59 * 58 * 57/4/3/2),因此在大约第二。

# Make a vector of 60 numbers like your example
set.seed(42)
my_nums <- rnorm(60, 0.05, 0.08); 

all_combos <- combn(my_nums, 4)  # Get all unique combos of 4 numbers

library(tidyverse)
combos_table <- all_combos %>%
  t() %>%
  as_tibble() %>%
  mutate(sum = V1 + V2 + V3 + V4) %>%
  filter(sum > 0.1, sum < 0.11)


> combos_table
# A tibble: 8,989 x 5
      V1      V2      V3       V4   sum
   <dbl>   <dbl>   <dbl>    <dbl> <dbl>
 1 0.160 0.00482  0.0791 -0.143   0.100
 2 0.160 0.00482  0.101  -0.163   0.103
 3 0.160 0.00482  0.0823 -0.145   0.102
 4 0.160 0.00482  0.0823 -0.143   0.104
 5 0.160 0.00482 -0.0611 -0.00120 0.102
 6 0.160 0.00482 -0.0611  0.00129 0.105
 7 0.160 0.00482  0.0277 -0.0911  0.101
 8 0.160 0.00482  0.0277 -0.0874  0.105
 9 0.160 0.00482  0.101  -0.163   0.103
10 0.160 0.00482  0.0273 -0.0911  0.101
# … with 8,979 more rows

这表示在此示例中,我的序列中约有9000个4个数字的集合符合标准。我们可以选择其中任何一个并将其放置在4-7位,以满足您的要求。