I have a dataset like this:
risk earthquake
platarea
magnitude
area
0.4
no
5
30
0.5
no
6
20
5.5
yes
6
20
I would like to create a new column
i gave that code
df$newrisk <- 0.5*df$magnitude + 0.6*df$aarea + 3*df$platarea
I got an error message for df$platarea?
BUt the platarea will only increase when it is "yes".
How can I code that???? the code is right if I omit df$platarea, but i would also include df$platarea but don't know how??
We can create a logical vector
i1 <- df$platarea == "yes"
df$newrisk[i1] <- with(df, 0.5 * magnitude[i1] + 0.6 * area[i] + 3)
If it is only to change the + 3 *, multiply by the logical vector so that FALSE (or 0 will return 0 and TRUE for 'yes' will return 3 as -3 *1 = 3)
df$newrisk <- with(df, 0.5 * magnitude + 0.6 * area + 3 *i1)
There are three common ways to add a new column to a data frame in R:
Use the $ Operator
df$new <- c(3, 3, 6, 7, 8, 12)
Use Brackets
df['new'] <- c(3, 3, 6, 7, 8, 12)
Use Cbind
df_new <- cbind(df, new)
I leave some examples for further explanation:
#create data frame
df <- data.frame(a = c('A', 'B', 'C', 'D', 'E'),
b = c(45, 56, 54, 57, 59))
#view data frame
df
a b
1 A 45
2 B 56
3 C 54
4 D 57
5 E 59
Example 1: Use the $ Operator
#define new column to add
new <- c(3, 3, 6, 7, 8)
#add column called 'new'
df$new <- new
#view new data frame
df
a b new
1 A 45 3
2 B 56 3
3 C 54 6
4 D 57 7
5 E 59 8
Example 2: Use Brackets
#define new column to add
new <- c(3, 3, 6, 7, 8)
#add column called 'new'
df['new'] <- new
#view new data frame
df
a b new
1 A 45 3
2 B 56 3
3 C 54 6
4 D 57 7
5 E 59 8
Example 3: Use Cbind
#define new column to add
new <- c(3, 3, 6, 7, 8)
#add column called 'new'
df_new <- cbind(df, new)
#view new data frame
df_new
a b new
1 A 45 3
2 B 56 3
3 C 54 6
4 D 57 7
5 E 59 8
Related
For example : I have frame with 4 columns and I want divide columns A and B by C, but I want unchanged column ID
A B C ID
4 8 23 1
5 12 325 2
6 23 56 3
73 234 21 4
23 23 213 5
The result which i expect is
A B C ID
0,173913043 0,347826087 1 1
0,015384615 0,036923077 1 2
0,107142857 0,410714286 1 3
3,476190476 11,14285714 1 4
0,107981221 0,107981221 1 5
or without the column C, doesn't matter
So, I have the code which give me only columns A and B without the column 'ID'
columns_to_divide <- c(1,2)
results <- results[,columns_to_divide ]/results[,3]
We can use mutate, which creates or alters the values in a column. across says to alter columns A and B, and then we can define a function to divide both of these columns by C.
library(dplyr)
dat %>% mutate(across(c(A, B), function(x) x/C))
A B C ID
1: 0.17391304 0.34782609 23 1
2: 0.01538462 0.03692308 325 2
3: 0.10714286 0.41071429 56 3
4: 3.47619048 11.14285714 21 4
5: 0.10798122 0.10798122 213 5
div = c("A", "B")
div_by = "C"
DF[div] <- DF[div] / DF[[div_by]]
# A B C
# 1 0.17391304 0.34782609 23
# 2 0.01538462 0.03692308 325
# 3 0.10714286 0.41071429 56
# 4 3.47619048 11.14285714 21
# 5 0.10798122 0.10798122 213
Data
DF data.frame(
A = c(4, 5, 6, 73, 23), B = c(8, 12, 23, 234, 23), C = c(23, 325, 56, 21, 213)
)
Create Columns
A <- c(4, 5, 6, 73, 23)
B <- c(8, 12, 23, 234, 23)
C <- c(23, 325, 56, 21, 213)
ID <- c(1, 2, 3, 4, 5)
Add to data frame
df = data.frame(A, B, C, ID)
divide by and print
df$A <- df$A / df$C
df$B <- df$B / df$C
df$C <- df$C / df$C
print(df)
I have a dataframe and i want to calculate the sum of variables present in a vector in every row and make the sum in other variable after i want the name of new variable created to be from the name of the variable in vector
for example
data
Name A_12 B_12 C_12 D_12 E_12
r1 1 5 12 21 15
r2 2 4 7 10 9
r3 5 15 16 9 6
r4 7 8 0 7 18
let's say i have two vectors
vector_1 <- c("A_12","B_12","C_12")
vector_2 <- c("B_12","C_12","D_12","E_12")
The result i want is :
New_data >
Name A_12 B_12 C_12 ABC_12 D_12 E_12 BCDE_12
r1 1 5 12 18 21 15 54
r2 2 4 7 13 10 9 32
r3 5 15 16 36 9 6 45
r4 7 8 0 15 7 18 40
I created for loop to get the sum of the rows in a vector but i didn't get the correct result
Please tell me ig you need any more informations or clarifications
Thank you
You can use rowSums and simple column-subsetting:
dat$ABC_12 <- rowSums(dat[,vector_1])
dat$BCDE_12 <- rowSums(dat[,vector_2])
dat
# Name A_12 B_12 C_12 D_12 E_12 ABC_12 BCDE_12
# 1 r1 1 5 12 21 15 18 53
# 2 r2 2 4 7 10 9 13 30
# 3 r3 5 15 16 9 6 36 46
# 4 r4 7 8 0 7 18 15 33
Note that if your frames inherit from data.table, then you'll need to use either subset(dat, select=vector_1) or dat[,..vector_1] instead of simply dat[,vector_1]; if you aren't already using data.table, then you can safely ignore this paragraph.
Like this (using dplyr/tidyverse)
df %>%
rowwise() %>%
mutate(
ABC_12 = sum(c_across(vector_1)),
BCDE_12 = sum(c_across(vector_2))
)
Though I'm not sure the sums are correct in your example
-=-=-=EDIT-=-=-=-
Here's a function to help with the naming.
ex_fun <- function(vec, n_len){
paste0(paste(substr(vec,1,n_len), collapse = ""), substr(vec[1],n_len+1,nchar(vec[1])))
}
Which can then be implemented like so.
df %>%
rowwise() %>%
mutate(
!!ex_fun(vector_1, 1) := sum(c_across(vector_1)),
!!ex_fun(vector_2, 1) := sum(c_across(vector_2)),
)
-=-= Extra note -=--=
If you list your vectors up you could then combine this with r2evans answer and stick into a loop if you prefer.
vectors = list(vector_1, vector_2)
for (v in vectors){
df[ex_fun(v, 1)] <- rowSums(df[,v])
}
I believe this might work, so long as only the starting digits are different:
library("tidyverse")
#Input dataframe.
data <- data.frame(Name =c("r1", "r2", "r3", "r4"), A_12 = c(1, 2, 5, 7), B_12 = c(5, 4, 15, 8),
C_12 = c(12, 7, 16, 0), D_12 = c(21, 10, 9, 7), E_12 = c(15, 9, 6, 18))
#add all vectors to the "vectors" list. I have added vector_1 and vector_2, but
#there can be as many vectors as needed, they just need to be put in the list.
vector_1 <- c("A_12","B_12","C_12")
vector_2 <- c("B_12","C_12","D_12","E_12")
vector_list<-list(vector_1, vector_2)
vector_sum <- function(data, vector_list){
output <- data |>
dplyr::select(1, all_of(vector_list[[1]]))
for (i in vector_list) {
name1 <- substring(as.character(i), 1,1) |> paste(collapse = '')
name2 <- substring(as.character(i[1]), 2)
input_temp <- dplyr::select(data, all_of(i))
input_temp <- mutate(input_temp, temp=rowSums(input_temp))
names(input_temp)[names(input_temp) == "temp"] <- paste(name1, name2)
output = cbind(output, input_temp)
}
output[, !duplicated(colnames(output))]
}
vector_sum(data, vector_list)
I have a dataframe like this:
V1 = paste0("AB", seq(1:48))
V2 = seq(1:48)
test = data.frame(name = V1, value = V2)
I want to calculate the means of the value-column and specific rows.
The pattern of the rows is pretty complicated:
Rows of MeanA1: 1, 5, 9
Rows of MeanA2: 2, 6, 10
Rows of MeanA3: 3, 7, 11
Rows of MeanA4: 4, 8, 12
Rows of MeanB1: 13, 17, 21
Rows of MeanB2: 14, 18, 22
Rows of MeanB3: 15, 19, 23
Rows of MeanB4: 16, 20, 24
Rows of MeanC1: 25, 29, 33
Rows of MeanC2: 26, 30, 34
Rows of MeanC3: 27, 31, 35
Rows of MeanC4: 28, 32, 36
Rows of MeanD1: 37, 41, 45
Rows of MeanD2: 38, 42, 46
Rows of MeanD3: 39, 43, 47
Rows of MeanD4: 40, 44, 48
As you see its starting at 4 different points (1, 13, 25, 37) then always +4 and for the following 4 means its just stepping 1 more row down.
I would like to have an output of all these means in one list.
Any ideas? NOTE: In this example the mean is of course always the middle number, but my real df is different.
Not quite sure about the output format you require, but the following codes can calculate what you want anyhow.
calc_mean1 <- function(x) mean(test$value[seq(x, by = 4, length.out = 3)])
calc_mean2 <- function(x){sapply(x:(x+3), calc_mean1)}
output <- lapply(seq(1, 37, 12), calc_mean2)
names(output) <- paste0('Mean', LETTERS[seq_along(output)]) # remove this line if more than 26 groups.
output
## $MeanA
## [1] 5 6 7 8
## $MeanB
## [1] 17 18 19 20
## $MeanC
## [1] 29 30 31 32
## $MeanD
## [1] 41 42 43 44
An idea via base R is to create a grouping variable for every 4 rows, split the data every 12 rows (nrow(test) / 4) and aggregate to find the mean, i.e.
test$new = rep(1:4, nrow(test)%/%4)
lapply(split(test, rep(1:4, each = nrow(test) %/% 4)), function(i)
aggregate(value ~ new, i, mean))
# $`1`
# new value
# 1 1 5
# 2 2 6
# 3 3 7
# 4 4 8
# $`2`
# new value
# 1 1 17
# 2 2 18
# 3 3 19
# 4 4 20
# $`3`
# new value
# 1 1 29
# 2 2 30
# 3 3 31
# 4 4 32
# $`4`
# new value
# 1 1 41
# 2 2 42
# 3 3 43
# 4 4 44
And yet another way.
fun <- function(DF, col, step = 4){
run <- nrow(DF)/step^2
res <- lapply(seq_len(step), function(inc){
inx <- seq_len(run*step) + (inc - 1)*run*step
dftmp <- DF[inx, ]
tapply(dftmp[[col]], rep(seq_len(step), run), mean, na.rm = TRUE)
})
names(res) <- sprintf("Mean%s", LETTERS[seq_len(step)])
res
}
fun(test, 2, 4)
#$MeanA
#1 2 3 4
#5 6 7 8
#
#$MeanB
# 1 2 3 4
#17 18 19 20
#
#$MeanC
# 1 2 3 4
#29 30 31 32
#
#$MeanD
# 1 2 3 4
#41 42 43 44
Since you said you wanted a long list of the means, I assumed it could also be a vector where you just have all these values. You would get that like this:
V1 = paste0("AB", seq(1:48))
V2 = seq(1:48)
test = data.frame(name = V1, value = V2)
meanVector <- NULL
for (i in 1:(nrow(test)-8)) {
x <- c(test$value[i], test$value[i+4], test$value[i+8])
m <- mean(x)
meanVector <- c(meanVector, m)
}
I have a data frame df with four columns; three integer columns and a special column containing a list:
df <- data.frame(w= 1:3, x=3:5, y=6:8, z = I(list(1:2, 1:3, 1:4)))
> df
w x y z
1 1 3 6 1, 2
2 2 4 7 1, 2, 3
3 3 5 8 1, 2, 3, 4
>class(df$z)
[1] "AsIs"
I want to transform each element of the column df["z"] by separately multiplying it with the corresponding element (same row number) of each of the other columns (df["w"], df["x"], df["y"]) of the same data frame df.
I have found the possibility of using Map("*", df$z, df$x), but it can only perform the required multiplication with one other column at a time. My data set is too large to let me perform the multiplication in such small steps.
> Map("*", df$z, df$x)
[[1]]
[1] 3 6
[[2]]
[1] 4 8 12
[[3]]
[1] 5 10 15 20
Can anyone please provide a hint on how to multiply df["z"] with each of the other columns at once while preserving the data frame structure?
I expect the output to be a data frame df1 with column names w,x,y.
>df1
w x y
1 2 3 6 6 12
2 4 6 4 8 12 7 14 21
3 6 9 12 5 10 15 20 8 16 24 32
Thank you.
We can use transmute_at
library(tidyverse)
df %>%
transmute_at(vars(w, x, y), funs(map2(z, ., `*`)))
# w x y
#1 1, 2 3, 6 6, 12
#2 2, 4, 6 4, 8, 12 7, 14, 21
#3 3, 6, 9, 12 5, 10, 15, 20 8, 16, 24, 32
Or as #Ryan mentioned if there are more columns and the multiplier list column is single, we can use one_of within transmute_at to select other columns except the 'z'
df %>%
transmute_at(vars(-one_of('z')), funs(map2(z, .,`*`)))
Let's say I want to create a column in a data.table, in which the value in each row is equal to the standard deviation of the values in three other cells in the same row. E.g., if I make
DT <- data.table(a = 1:4, b = c(5, 7, 9, 11), c = c(13, 16, 19, 22), d = c(25, 29, 33, 37))
DT
a b c d
1: 1 5 13 25
2: 2 7 16 29
3: 3 9 19 33
4: 4 11 22 37
and I'd like to add a column that contains the standard deviation of a, b, and d for each row, like this:
a b c d abdSD
1: 1 5 13 23 12.86
2: 2 7 16 27 14.36
3: 3 9 19 31 15.87
4: 4 11 22 35 17.39
I could of course write a for-loop or use an apply function to calculate this. Unfortunately, what I actually want to do needs to be applied to millions of rows, isn't as simple a function as calculating a standard deviation, and needs to finish within a fraction of a second, so I really need a vectorized solution. I want to write something like
DT[, abdSD := sd(c(a, b, d))]
but unfortunately that doesn't give the right answer. Is there any data.table syntax that can create a vector out of different values within the same row, and make that vector accessible to a function populating a new cell within that row? Any help would be greatly appreciated. #Arun
Depending on the size of your data, you might want to convert the data into a long format, then calculate the result as follows:
complexFunc <- function(x) sd(x)
cols <- c("a", "b", "d")
rowres <- melt(DT[, rn:=.I], id.vars="rn", variable.factor=FALSE)[,
list(abdRes=complexFunc(value[variable %chin% cols])), by=.(rn)]
DT[rowres, on=.(rn)]
or if your complex function has 3 arguments, you can do something like
DT[, abdSD := mapply(complexFunc, a, b, d)]
As #Frank mentioned, I could avoid adding a column by doing by=1:nrow(DT)
DT[, abdSD:=sd(c(a,b,d)),by=1:nrow(DT)]
output:
a b c d abdSD
1: 1 5 13 25 12.85820
2: 2 7 16 29 14.36431
3: 3 9 19 33 15.87451
4: 4 11 22 37 17.38774
if you add a row_name column, it would be ultra easy
DT$row_id<-row.names(DT)
Simply by=row_id, would get you the result you want
DT[, abdSD:=sd(c(a,b,d)),by=row_id]
Result would have:
a b c d row_id abdSD
1: 1 5 13 25 1 12.85820
2: 2 7 16 29 2 14.36431
3: 3 9 19 33 3 15.87451
4: 4 11 22 37 4 17.38774
If you want row_id removed, simply adding [,row_id:=NULL]
DT[, abdSD:=sd(c(a,b,d)),by=row_id][,row_id:=NULL]
This line would get everything you want
a b c d abdSD
1: 1 5 13 25 12.85820
2: 2 7 16 29 14.36431
3: 3 9 19 33 15.87451
4: 4 11 22 37 17.38774
You just gotta do it by row.
data.frame does it by row on default, data.table does it by column on default I think. It's a bit tricky
Hope this helps
I think you should try matrixStats package
library(matrixStats)
#sample data
dt <- data.table(a = 1:4, b = c(5, 7, 9, 11), c = c(13, 16, 19, 22), d = c(25, 29, 33, 37))
dt[, `:=`(abdSD = rowSds(as.matrix(.SD), na.rm=T)), .SDcols=c('a','b','d')]
dt
Output is:
a b c d abdSD
1: 1 5 13 25 12.85820
2: 2 7 16 29 14.36431
3: 3 9 19 33 15.87451
4: 4 11 22 37 17.38774
Not an answer, but just trying to show the difference between using apply and the solution provided by Prem above :
I have blown up the sample data to 40,000 rows to show solid time differences :
library(matrixStats)
#sample data
dt <- data.table(a = 1:40000, b = rep(c(5, 7, 9, 11),10000), c = rep(c(13, 16, 19, 22),10000), d = rep(c(25, 29, 33, 37),10000))
df <- data.frame(a = 1:40000, b = rep(c(5, 7, 9, 11),10000), c = rep(c(13, 16, 19, 22),10000), d = rep(c(25, 29, 33, 37),10000))
t0 = Sys.time()
dt[, `:=`(abdSD = rowSds(as.matrix(.SD), na.rm=T)), .SDcols=c('a','b','d')]
print(paste("Time taken for data table operation = ",Sys.time() - t0))
# [1] "Time taken for data table operation = 0.117115020751953"
t0 = Sys.time()
df$abdSD <- apply(df[,c("a","b","d")],1, function(x){sd(x)})
print(paste("Time taken for apply opertaion = ",Sys.time() - t0))
# [1] "Time taken for apply opertaion = 2.93488311767578"
Using DT and matrixStats clearly wins the race
It's not hard to vectorize the sd for this situation:
vecSD = function(x) {
n = ncol(x)
sqrt((n/(n-1)) * (Reduce(`+`, x*x)/n - (Reduce(`+`, x)/n)^2))
}
DT[, vecSD(.SD), .SDcols = c('a', 'b', 'd')]
#[1] 12.85820 14.36431 15.87451 17.38774