roughly equal spaced integers on a log scale - r

For the integers between 10 and 100, I want to keep the numbers that are roughly equally spaced in a log-scale.
General speaking if the space between two integers is much less than .5 (scaled by (log(10)-log(9) as shown in the code below), then one integer should be dropped. But the remaining integers should be also be rounded to a multiple of 2, 5 and 10 if possible.
So this would end up 10, 11, ..., 19, 20, 22, ..., 30, 32, 35, 40, ..., 85, 90, 100.
R> data.frame(diff((log(9:100)-lodata.frame(delta=diff((log(9:100)-log(10))/(log(10)-log(9))), n=10:100)
delta n
1 1.00000000 10
2 0.90461004 11
3 0.82584426 12
4 0.75970307 13
5 0.70337518 14
6 0.65482663 15
7 0.61254940 16
8 0.57540172 17
9 0.54250317 18
10 0.51316398 19
11 0.48683602 20
12 0.46307826 21
13 0.44153178 22
14 0.42190153 23
15 0.40394273 24
16 0.38745060 25
17 0.37225248 26
18 0.35820182 27
19 0.34517337 28
20 0.33305949 29
21 0.32176714 30
22 0.31121547 31
23 0.30133393 32
24 0.29206063 33
25 0.28334109 34
26 0.27512714 35
27 0.26737604 36
28 0.26004974 37
29 0.25311424 38
30 0.24653910 39
31 0.24029693 40
32 0.23436306 41
33 0.22871520 42
34 0.22333316 43
35 0.21819861 44
36 0.21329485 45
37 0.20860667 46
38 0.20412016 47
39 0.19982257 48
40 0.19570222 49
41 0.19174837 50
42 0.18795112 51
43 0.18430136 52
44 0.18079064 53
45 0.17741118 54
46 0.17415574 55
47 0.17101763 56
48 0.16799061 57
49 0.16506888 58
50 0.16224705 59
51 0.15952008 60
52 0.15688327 61
53 0.15433221 62
54 0.15186279 63
55 0.14947115 64
56 0.14715367 65
57 0.14490696 66
58 0.14272783 67
59 0.14061326 68
60 0.13856044 69
61 0.13656670 70
62 0.13462951 71
63 0.13274652 72
64 0.13091548 73
65 0.12913426 74
66 0.12740086 75
67 0.12571338 76
68 0.12407002 77
69 0.12246907 78
70 0.12090892 79
71 0.11938801 80
72 0.11790489 81
73 0.11645817 82
74 0.11504652 83
75 0.11366868 84
76 0.11232346 85
77 0.11100971 86
78 0.10972633 87
79 0.10847228 88
80 0.10724658 89
81 0.10604827 90
82 0.10487644 91
83 0.10373023 92
84 0.10260880 93
85 0.10151136 94
86 0.10043714 95
87 0.09938543 96
88 0.09835551 97
89 0.09734672 98
90 0.09635841 99
91 0.09538996 100
When I plot these manually select integers, it is roughly on a straight line. Is there a more intelegent algorithm that can help this job automatically (so that it can easily extend to larger ranges, note in that case the round should be to 20, 25, 50, ...something that can divide powers of 10) without having to manually select data?
R> plot(log(c(10:20, seq(from=22, to=32, by=2), seq(from=35, to=90, by=5), 100)), log='y')

Something like this may be helpful:
int_log <- function(min, max, by = 1, round_to = 1) {
round_to * round(exp(seq(log(min), log(max), log(min + by) - log(min)))/round_to)
}
int_log(10, 100)
#> [1] 10 11 12 13 15 16 18 19 21 24 26 29 31 35 38 42 46 51 56 61 67 74 81 90 98
plot(int_log(10, 100), log = 'y')
plot(int_log(10, 1000, by = 10, round_to = 10), log = 'y')
Created on 2022-04-01 by the reprex package (v2.0.1)

Related

how to delete every nth range of rows in R

Suppose I have a dataframe df, which contains 450 rows. I want to delete rows from 10 through 18 (that is 10, 11, 12, 13, 14, 15, 16, 17, 18). Then similarly rows from 28 through 36, then 46:54. And so on, up to deleting rows from 442 through 450.
Any suggestions, guys?
Create a sequence and remove those rows. The first argument, nvec, is the length of each sequence (8, repeated for each sequence); the second, from, is the starting point for each sequence (10, 28, ...).
n = 450
len = n %/% 18
s <- sequence(nvec = rep(9, len), from = seq(10, n, 18))
# [1] 10 11 12 13 14 15 16 17 18 28 29 30 31 32 33 34
# [17] 35 36 46 47 48 49 50 51 52 53 54 64 65 66 67 68
# [33] 69 70 71 72 82 83 84 85 86 87 88 89 90 100 101 102
# ...
your_df[-s, ]
You can also create the sequence like this:
rep(10:18, len) + rep(18*(0:(len - 1)), each = 9)
# [1] 10 11 12 13 14 15 16 17 18 28 29 30 31 32 33 34
# [17] 35 36 46 47 48 49 50 51 52 53 54 64 65 66 67 68
# [33] 69 70 71 72 82 83 84 85 86 87 88 89 90 100 101 102
# ...

What ways exist to create an array with given dimensions from a given sequence in Julia?

I'm new to Julia and I could not find any useful information on the following: I would like to create an array of given dimensions and fill it with a given sequence.
m,n = 10,10 # dimensions
i = 1:100 # sequence
I've tried to use collect, but this gives me a single column array. I have also tried it the Julia way
[? for i in 1:m, j in 1:n]
but I don't know what I could insert for ?.
The easiest way is reshape(i, m,n) (potentially together with a collect if you really need an Array{Int64,2}):
julia> reshape(i,m,n)
10×10 reshape(::UnitRange{Int64}, 10, 10) with eltype Int64:
1 11 21 31 41 51 61 71 81 91
2 12 22 32 42 52 62 72 82 92
3 13 23 33 43 53 63 73 83 93
4 14 24 34 44 54 64 74 84 94
5 15 25 35 45 55 65 75 85 95
6 16 26 36 46 56 66 76 86 96
7 17 27 37 47 57 67 77 87 97
8 18 28 38 48 58 68 78 88 98
9 19 29 39 49 59 69 79 89 99
10 20 30 40 50 60 70 80 90 100
julia> collect(ans)
10×10 Array{Int64,2}:
1 11 21 31 41 51 61 71 81 91
2 12 22 32 42 52 62 72 82 92
3 13 23 33 43 53 63 73 83 93
4 14 24 34 44 54 64 74 84 94
5 15 25 35 45 55 65 75 85 95
6 16 26 36 46 56 66 76 86 96
7 17 27 37 47 57 67 77 87 97
8 18 28 38 48 58 68 78 88 98
9 19 29 39 49 59 69 79 89 99
10 20 30 40 50 60 70 80 90 100
To answer your question what to put as ? in the array comprehension approach, you must convert the cartesian index to a linear index, for example like so:
julia> [i[LinearIndices((m,n))[p,q]] for p in 1:m, q in 1:n]
10×10 Array{Int64,2}:
1 11 21 31 41 51 61 71 81 91
2 12 22 32 42 52 62 72 82 92
3 13 23 33 43 53 63 73 83 93
4 14 24 34 44 54 64 74 84 94
5 15 25 35 45 55 65 75 85 95
6 16 26 36 46 56 66 76 86 96
7 17 27 37 47 57 67 77 87 97
8 18 28 38 48 58 68 78 88 98
9 19 29 39 49 59 69 79 89 99
10 20 30 40 50 60 70 80 90 100
Of course, you can also calculate the linear index yourself, [i[(q-1)*m + p] for p in 1:m, q in 1:n].
Alternatively, you can preallocate the array and fill it in a linear fashion:
julia> result = Matrix{Int64}(undef, m,n);
julia> result[:] .= i;
julia> result
10×10 Array{Int64,2}:
1 11 21 31 41 51 61 71 81 91
2 12 22 32 42 52 62 72 82 92
3 13 23 33 43 53 63 73 83 93
4 14 24 34 44 54 64 74 84 94
5 15 25 35 45 55 65 75 85 95
6 16 26 36 46 56 66 76 86 96
7 17 27 37 47 57 67 77 87 97
8 18 28 38 48 58 68 78 88 98
9 19 29 39 49 59 69 79 89 99
10 20 30 40 50 60 70 80 90 100
which is basically equivalent to the naive, explicit solution
julia> result = Matrix{Int64}(undef, m,n);
julia> for k in eachindex(i) result[k] = i[k] end
julia> result
10×10 Array{Int64,2}:
1 11 21 31 41 51 61 71 81 91
2 12 22 32 42 52 62 72 82 92
3 13 23 33 43 53 63 73 83 93
4 14 24 34 44 54 64 74 84 94
5 15 25 35 45 55 65 75 85 95
6 16 26 36 46 56 66 76 86 96
7 17 27 37 47 57 67 77 87 97
8 18 28 38 48 58 68 78 88 98
9 19 29 39 49 59 69 79 89 99
10 20 30 40 50 60 70 80 90 100

How to cut the values in a regular interval and define them into the separate group? [duplicate]

This question already has answers here:
Split a vector into chunks
(22 answers)
Closed 3 years ago.
How to cut the values (1 to 100) in a regular interval (25) and place them into 4 groups as below:
sdr <- c(1:100)
Group1: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Group2: 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
Group3: 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
Group4: 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
Any suggestion, please.
You could use split
sdr <- 1:100
split(sdr, rep(1:4, each = 25))
#$`1`
# [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#
#$`2`
# [1] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#
#$`3`
# [1] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#
#$`4`
# [1] 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
#[20] 95 96 97 98 99 100
This returns a list with 4 vector elements.
Also note that the c() around 1:100 is not necessary.
Or we can define the number of groups
ngroup <- 4
split(sdr, rep(1:ngroup, each = length(sdr) %/% ngroup))
giving the same result.
You can make a dataframe for your groups and then transpose using t:
df <- t(data.frame(Group1 = c(1:25), Group2 = c(26:50), Group3 = c(51:75), Group4 = c(76:100)))

loop over a sequence and rounding problem in R

I want to assign some value to a vecter like:
a = rep(0, 101)
for(i in seq(0, 1, 0.01)){
u <- 100 * i + 1
a[u] <- u
}
a
plot(a)
The output is
> a
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 0 31 32 33 34
[35] 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 59 0 60 61 62 63 64 65 66 67 68
[69] 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
There are problems on the 29th and the 59th elements. They should be 29 and 59, but it turns out to be 0, the default value. And the previous values, the 28th and 58th, are also incorrect. Why is this happening? Thank you!
There is a problem with your indexing. I don't know how to explain why it doesn't work as written, but here is a modification to your code that works:
a = rep(0, 101)
s<-seq(0, 1, 0.01)
for(i in 1:101){
a[i] <- 100 * s[i] + 1
}
a
plot(a)
In general it is best to avoid multiple indexes in the same loop as it can be confusing and difficult to diagnose problems.

Generate sequence with alternating increments in R? [duplicate]

This question already has answers here:
Get a seq() in R with alternating steps
(6 answers)
Closed 6 years ago.
I want to use R to create the sequence of numbers 1:8, 11:18, 21:28, etc. through 1000 (or the closest it can get, i.e. 998). Obviously typing that all out would be tedious, but since the sequence increases by one 7 times and then jumps by 3 I'm not sure what function I could use to achieve this.
I tried seq(1, 998, c(1,1,1,1,1,1,1,3)) but it does not give me the results I am looking for so I must be doing something wrong.
This is a perfect case of vectorisation( recycling too) in R. read about them
(1:100)[rep(c(TRUE,FALSE), c(8,2))]
# [1] 1 2 3 4 5 6 7 8 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27 28 31 32
#[27] 33 34 35 36 37 38 41 42 43 44 45 46 47 48 51 52 53 54 55 56 57 58 61 62 63 64
#[53] 65 66 67 68 71 72 73 74 75 76 77 78 81 82 83 84 85 86 87 88 91 92 93 94 95 96
#[79] 97 98
rep(seq(0,990,by=10), each=8) + seq(1,8)
You want to exclude numbers that are 0 or 9 (mod 10). So you can try this too:
n <- 1000 # upper bound
x <- 1:n
x <- x[! (x %% 10) %in% c(0,9)] # filter out (0, 9) mod (10)
head(x,80)
# [1] 1 2 3 4 5 6 7 8 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27
# 28 31 32 33 34 35 36 37 38 41 42 43 44 45 46 47 48 51 52 53 54 55 56 57
# 58 61 62 63 64 65 66 67 68 71 72 73 74 75 76 77 78 81 82 83 84 85
# 86 87 88 91 92 93 94 95 96 97 98
Or in a single line using Filter:
Filter(function(x) !((x %% 10) %in% c(0,9)), 1:100)
# [1] 1 2 3 4 5 6 7 8 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27 28 31 32 33 34 35 36 37 38 41 42 43 44 45 46 47 48 51 52 53 54 55 56 57
# [48] 58 61 62 63 64 65 66 67 68 71 72 73 74 75 76 77 78 81 82 83 84 85 86 87 88 91 92 93 94 95 96 97 98
With a cycle: for(value in c(seq(1,991,10))){vector <- c(vector,seq(value,value+7))}

Resources