I have written a function to store the diagonal elements of a matrix into a vector. but the output is not as I expected. The code is:
diagonal <- function(x) {
for (i in nrow(x)) {
for (j in ncol(x)) {
if (i == j) {
a <- x[i, j]
}
}
}
print(a)
}
I am passing a matrix to the function.
What is wrong with the code?
We can use the diag function
diag(m1)
#[1] 1 5 9
Or
m1[col(m1)==row(m1)]
#[1] 1 5 9
If we are using the for loop, we are looping by the sequence of rows and columns i.e 1:nrow(x)/1:ncol(x) and not by nrow(x)/ncol(x).
diagonal <- function(x) {
a <- numeric(0)
for( i in 1:nrow(x)){
for(j in 1:ncol(x)){
if(i == j) {
a <- c(a, x[i,j])
}
}
}
a
}
diagonal(m1)
#[1] 1 5 9
data
m1 <- matrix(1:9, ncol=3)
Related
Find the number of entries in each row which are greater than 4.
set.seed(75)
aMat <- matrix( sample(10, size=60, replace=T), nr=6)
rowmax=function(a)
{
x=nrow(a)
y=ncol(a)
i=1
j=1
z=0
while (i<=x) {
for(j in 1:y) {
if(!is.na(a[i][j])){
if(a[i][j]>4){
z=z+1
}
}
j=j+1
}
print(z)
i=i+1
}
}
rowmax(aMat)
It is showing the error. I don't want to apply in built function
You could do this easier counting the x that are greater than 4 using length.
rowmax2 <- function(x) apply(x, 1, function(x) {x <- na.omit(x);length(x[x > 4])})
rowmax2(aMat)
# [1] 8 7 8 7 4 3
If you wanted to do this absolutely without any shortcut you could use two for loops. 1 for each row and another for each value in the row.
rowmax = function(a) {
y=nrow(a)
result <- numeric(y)
for(j in seq_len(y)) {
count = 0
for(val in a[j, ]) {
if(!is.na(val) && val > 4)
count = count + 1
}
result[j] <- count
}
return(result)
}
rowmax(aMat)
#[1] 8 7 8 7 4 3
If you wanted to do this using in-built functions in base R you could use rowSums.
rowSums(aMat > 4, na.rm = TRUE)
#[1] 8 7 8 7 4 3
There are several errors in you code:
You should put z <- 0 inside while loop
You should use a[i,j] for the matrix indexing, rather than a[i][j]
Below is a version after fixing the problems
rowmax <- function(a) {
x <- nrow(a)
y <- ncol(a)
i <- 1
j <- 1
while (i <= x) {
z <- 0
for (j in 1:y) {
if (!is.na(a[i, j])) {
if (a[i, j] > 4) {
z <- z + 1
}
}
j <- j + 1
}
print(z)
i <- i + 1
}
}
and then we get
> rowmax(aMat)
[1] 8
[1] 7
[1] 8
[1] 7
[1] 4
[1] 3
A concise approach to make it is using rowSums, e.g.,
rowSums(aMat, na.rm = TRUE)
i have an assignment for studies and i need to create a function that takes a vector as input and creates another vector, which, at every position has a cumulative sum of the previous ones and itself, it might be unclear but i have some code, and have no idea whats wrong. I cant use cumsum()
SumaKumul <- function(x)
{
result <- c()
for(i in x)
{
result[i] <- sum(x[1:i])
}
return(result)
}
SumaKumul(c(2,3,4,5))
and thats what i get
> SumaKumul(c(2,3,4,5))
[1] NA 5 9 14 NA
>
You should use seq_along(x), rather than x in your for loop
SumaKumul <- function(x)
{
result <- c()
for(i in seq_along(x))
{
result[i] <- sum(x[1:i])
}
return(result)
}
such that
> SumaKumul(c(2,3,4,5))
[1] 2 5 9 14
You can add 1:length(x) in your for loop of a function to iterate over a vector:
SumaKumul <- function(x)
{
result <- c()
for(i in 1:length(x))
{
result[i] <- sum(x[1:i])
}
return(result)
}
SumaKumul(c(2,3,4,5))
# [1] 2 5 9 14
*> csort <- function(c){
i<-1
for (i in 1:length(c)-1) {
j <- i+1
for (j in 2:length(c)) {
if(c[i] >= c[j])c[c(i,j)] <- c[c(j,i)]
j = j + 1
}
i = i + 1
}
}
> csort(a)
Error in if (c[i] >= c[j]) c[c(i, j)] <- c[c(j, i)] :
argument is of length zero*
This is what RStudio do when I run it. I do not know what cause the zero here.
csort <- function(c){
p <- 1
povit <- c[1]
c <- c[-1]
left <- c()
right <- c()
left <- c[which(c <= povit)]
right <- c[which(c > povit)]
if(length(left) > 1){
left <- csort(left)
}
if(length(right) > 1){
right <- csort(right)
}
return(c(left ,povit,right))
}
I viewed more about sorting online and this is a pivot sort way.
your mistake is in this line
for (i in 1:length(c)-1)
and should be
for (i in 1:(length(c)-1))
since $:$ operator precedes $-$.
an example is
1:(5-1)
#[1] 1 2 3 4
1:5-1
#[1] 0 1 2 3 4
so error happen in index with Zero value.
csort <- function(d){
for (i in 1:(length(d)-1)) {
for (j in (i+1):length(d)) {
if(d[i] >= d[j])d[c(i,j)] <- d[c(j,i)]
}
}
return(d)
}
d<-c(5:1,-1:3,-9,-3,10,9,-20,1,20,-6,5)
any((csort(d)==sort(d))==F)
#[1] FALSE
you can improve this function.
Write a function which takes a matrix that can be coerces into a matrix; the function should return a matrix which is the same as the function argument, but every even number is not changed and odd number is doubled.
I'm very new to R. Can someone help me complete my codes:
mx = matrix(c(1,1,3,5,2,6,-2,-1,-3), nrow = 3, byrow = TRUE)
fun = function(mx){
for(i in mx){
if(i %% 2 == 0){
return(i)
}
else if(i %% 2 > 0){
return(2*i)
}
}
}
Don't need a function, just use the built-in function ifelse:
mx <- ifelse(mx %% 2 == 0, mx, 2*mx)
Or, if you prefer to encapsulate it into a function:
fun = function(mx) {
ifelse(mx %% 2 == 0, mx, 2*mx)
}
res <- fun(mx)
## [,1] [,2] [,3]
##[1,] 2 2 6
##[2,] 10 2 6
##[3,] -2 -2 -6
Explanation:
ifelse performs a vectorized comparison over all elements of the matrix mx to see if each element is even (i.e., mx %% 2 == 0). For each element if this comparison condition is TRUE, the next argument is returned, which in this case is just the value from that element in mx. Otherwise, the last argument is returned, which is 2 times the value from that element in mx as you wish.
That's easy using indices :)
double_odd <- function(mx){
odds_idx <- (mx %% 2 != 0)
mx[odds_idx] <- 2 * mx[odds_idx]
mx # If it is the last statement, you don't need return
}
Cheers
Using your try:
fun = function(mx){
res <- matrix(data = NA, ncol = ncol(mx), nrow = nrow(mx))
for(i in 1:ncol(mx)){
for(j in 1:nrow(mx))
if(mx[j, i] %% 2 == 0){
res[j, i] <- mx[j, i]
}else{
res[j, i] <- 2 * mx[j, i]
}
}
return(res)
}
of course not the most elegant solution :)
I would like to ask how I can overwrite the variables v and ind in the following function:
repcomb <- function(v,n,ind)
{
k <- length(v)
if(ind == 0)
{
for (i in 1:k) v[i] <- 1
ind <- 1
return
}
for (i in k:1)
{
if(v[i] != n)
{
for (j in k:i) v[j] <- v[i] + 1
return
}
}
ind = 0
}
What is the easiest way for updating v and ind?
This is the easiest way:
repcomb <- function(v,n,ind)
{
k <- length(v)
if(ind == 0)
{
for (i in 1:k) v[i] <- 1
ind <- 1
return(list(v=v, ind=ind))
}
for (i in k:1)
{
if(v[i] != n)
{
for (j in i+1:k) v[j] <- v[i] + 1
v[i] <- v[i] + 1
return(list(v=v, ind=ind))
}
}
ind = 0
return(list(v=v, ind=ind))
}
res <- repcomb(1:5, 4, 2)
v <- res$v
ind <- res$ind
If you want to get back the value of a parameter set inside a function, you can use eval.parent(substitute(val<-new_val)), for example:
f_sqr <- function(val){
new_val <- val^2
eval.parent(substitute(val<-new_val))
}
If you call it:
val <- 5
f_sqr(val)
val
#[1] 25
Please bear in mind that you should not change the value of the parameter inside the function, instead, you copy it to a new variable, do what you want to do in your code and finally set the value of new variable into your parameter variable as it is the case inside the function.
For your own function, this is what you have to do for your first if:
repcomb <- function(v, n, ind)
{
k <- length(v)
if (ind == 0)
{
new_v <- v
for (i in 1:k) new_v[i] <- 1
# ind <- 1
new_ind <- 1
eval.parent(substitute(ind<-new_ind))
eval.parent(substitute(v<-new_v))
}
}
Then if you call it, you will get the changes back:
v <- 1:5
n <- 3
ind <- 0
repcomb(v, n, ind)
v
#[1] 1 1 1 1 1
ind
#[1] 1
Correspondingly, the other part can be changed to meet what you want.