Hello dear stack overflow community,
Here is the context of my problem : I have a dataframe with each column corresponding to one bat species and and each row corresponds to the acoustic activity measured for one night (for each night of recording not all the species as been sampled).
eg :
> Dataset
Bba Ese Hsa Mda Mda.Mca Mema Mpu
1 3 NA NA NA 33 NA NA
2 NA NA NA NA 1 NA NA
3 2 4 1 NA 19 1 NA
4 NA NA NA NA 25 NA NA
5 NA NA NA NA 3 NA NA
6 1 1 NA NA 53 NA NA
7 1 NA 9 NA NA 1 NA
8 NA NA 10 NA NA NA NA
9 NA NA NA NA NA NA NA
10 1 1 NA NA NA NA NA
11 6 NA NA NA NA NA NA
12 12 NA 1 NA NA 1 NA
13 3 NA 2 NA NA 1 NA
14 1 NA NA NA NA NA NA
15 NA NA NA NA NA NA NA
16 1 NA NA NA NA NA NA
17 2 NA NA NA NA 2 NA
18 1 1 NA NA NA NA 1
19 NA NA NA NA NA NA NA
20 1 1 NA NA NA NA NA
21 2 NA 1 NA NA NA NA
22 1 NA NA NA NA 4 NA
23 1 NA 1 NA NA 1 NA
24 NA NA NA NA NA 2 NA
25 1 NA NA NA NA NA NA
26 1 NA NA NA NA 1 NA
27 1 NA NA NA NA NA NA
28 5 NA NA NA NA NA NA
29 NA NA NA NA NA NA NA
.....
To study vocal activity I am checking the quantile of bat vocal activity per species
apply(Dataset[,9:15],2,quantile, na.rm=TRUE, type=7, c(0.02,0.25,0.5,0.75,0.98))
Bba Ese Hsa Mda Mda.Mca Mema Mpu
2% 1.00 1.00 1.00 1.00 1.00 1.00 1
25% 1.00 1.00 2.00 2.00 2.00 1.00 1
50% 3.00 4.00 6.00 4.00 3.00 2.00 2
75% 9.75 12.00 18.00 12.00 20.00 4.00 6
98% 53.86 69.88 166.12 313.32 159.04 27.28 44
To test the impact of sampling (number of night) on my quantile estimate, I want to do a boostrap. More specifically, I want to calculate the mean of the bat activity if I take only 3 night per species using 1000 random sample with replacement. And i want to do it If I take from 3 to 70 nights.
This is what I have so far (for one species):
Bbana<-as.data.frame(Bbana)
L= length(Bbana[,1])
B= 1000
m<-list()
for (j in 3:70) {
for (i in 1 : B) {
idx<-sample(1:L, j, replace=TRUE)
data_idx<-Bbana[idx, ]
m[i]<-mean(data_idx)
}}
Somehow it didn't give my what I am expected : 67 list with 1000 means of bat activity.
Could anyone help me ?
(I don't know if it's clear enough...)
Thanks in advance
if you want to stick to loops and lists:
for (j in 3:70) {
mat = matrix(NA, nrow = B, ncol = ncol(idx))
for (i in 1 : B) {
idx<-sample(1:L, j, replace=TRUE)
data_idx<-Bbana[idx, ]
mat[i,] = colMeans(data_idx, na.rm = TRUE)
}
m[[j]] = mat
}
Otherwise, this option should work (and should be more efficient / convenient to use):
sample.fun = function(nb.nights, dataset){
# select randomly nb.nights rows to sample
selected.rows = sample(1:nrow(dataset), nb.nights, replace = FALSE)
# return a vector with their means
return(colMeans(dataset[select.rows,], na.rm = TRUE))
}
sapply(3:67, function(nights) replicate(1000, sample.fun(nights, dataset), simplify = 'array'), simplify = FALSE)
This will return you a list of 67 elements that each contains a dataframe of 1000 rows (1000 means per species)
Related
I have three single-line dataframes with different numbers and names of columns...
df1:
0 3 6 7 10 14 17
2 18 9 1 14 2 1 1
df2:
0 3 7 9 10 13 14 17 21 35
2 10 4 8 1 5 2 11 2 1 1
df3:
0 3 7 10 12
2 7 3 11 3 1
...and I have a master dataframe.
CREATION CODE
masterdf <- data.frame(matrix(ncol = 50, nrow = 0))
colnames(masterdf) <- c('0',2:50)
0 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 29 30 31 32
1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
I want to take each of the smaller dataframes and put one per row into the master dataframe with the values in the matching columns. When finished, the updated master dataframe will look like this:
0 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 29 30 31 32
1 18 NA 9 NA NA 1 14 NA NA 2 NA NA NA 1 NA NA 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
2 10 NA 4 NA NA NA 8 NA 1 5 NA NA 2 11 NA NA 2 NA NA NA 1 NA NA NA NA NA NA NA NA NA NA NA
3 7 NA 3 NA NA NA 11 NA NA 3 NA 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
2 NA NA 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
Yes, the column names do need to remain as numbers. As you can see, the number of columns varies with each of the numbered dataframes.
Other notes:
The first column name is 0 and the second column name is 2.
The 0 column will ALWAYS have a value in it in every dataframe.
The row number (2) in each numbered dataframe is superfluous for my purposes.
I've tried nested loops without success.
My use case will end up with thousands of rows in the master dataframe.
Thoughts?
You can simply use the function rbindlist from data.table with fill = T
data.table::rbindlist(list(masterdf, df1, df2, df3), fill = T)
Results
0 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
1: 18 NA 9 NA NA 1 14 NA NA 2 NA NA NA 1 NA NA 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
2: 10 NA 4 NA NA NA 8 NA 1 5 NA NA 2 11 NA NA 2 NA NA NA 1 NA NA NA NA NA NA NA NA NA NA NA NA NA 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
3: 7 NA 3 NA NA NA 11 NA NA 3 NA 1 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
data
masterdf <- data.frame(matrix(ncol = 50, nrow = 0))
colnames(masterdf) <- c('0',2:50)
df1 <- data.frame(t(data.frame("2" = c(18,9,1,14,2,1,1))))
colnames(df1) <- c(0,3,6,7,10,14,17)
df2 <- data.frame(t(data.frame("2" = c(10,4,8,1,5,2,11,2,1,1))))
colnames(df2) <- c(0,3,7,9,10,13,14,17,21,35)
df3 <- data.frame(t(data.frame("2" = c(7,3,11,3,1))))
colnames(df3) <- c(0,3,7,10,12)
Two attempts:
basic for loop, which might be a bit slow with many rows:
df_list <- list(df1,df2,df3)
for(i in seq_along(df_list)) {
masterdf[i, names(df_list[[i]])] <- df_list[[i]]
}
vectorised approach using matrix indexing and a single assignment to all matching rows and columns
df_list <- list(df1,df2,df3)
masterdf[seq_along(df_list),] <- NA
masterdf[cbind(
rep(seq_along(df_list), lengths(df_list)),
match(unlist(lapply(df_list, names)), names(masterdf))
)] <- unlist(df_list)
I think you can try the match function. It is a base R function. See the quick example below:
?match
match("2", c("1","2","3"))
I am working on building a time series in R programming language.
I m having a zoo object which is follows:
I 'd like to convert this into a weekly time series data for analysis and typed in the following code
tt2<-as.ts(zz,freq=365.25/7,start=decimal_date(ymd("2018-01-01")))
tt2[is.na(tt2)]<-0
However, I get the following output:
Time Series:
Start = 17538
End = 18532
Frequency = 0.142857142857143
While I'd like to see the output in line with something like this:
Time Series:
Start = c(2018,2)
End = c(2020,40)
Frequency = 52
or since we can have both 53 and 52 weeks, something like:
Time Series:
Start = 1991.0848733744
End = 2005.34360027378
Frequency = 52.1785714285714
I also tried to do the following ,
library(zoo)
zz <- read.zoo(data, split = 1, index = 2,FUN=as.week")
and converted the following into the format:
However, if i try to convert this into a time series, I receive the following output:
Time Series:
Start = 2505
End = 2647
Frequency = 1
[1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[40] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[79] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
[118] NA NA NA NA NA NA NA NA NA 64 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
I'd be keen to receive your thoughts on this
I suppose using tsibble would more easier to convert your series from daily frequency to weekly frequency. At the end you can change to zoo object again.
Here is a short code on what I done
data
# A tibble: 14 x 2
Date Y
<date> <dbl>
1 2020-01-01 0.176
2 2020-01-02 0.521
3 2020-01-03 0.348
4 2020-01-04 0.801
5 2020-01-05 0.963
6 2020-01-06 0.0723
7 2020-01-07 0.638
8 2020-01-08 0.842
9 2020-01-09 0.298
10 2020-01-10 0.902
11 2020-01-11 0.943
12 2020-01-12 0.884
13 2020-01-13 0.266
14 2020-01-14 0.789
library(tsibble)
library(tidyverse)
library(zoo)
data$Date<-as.Date(data$Date)
data.w<-data%>%as_tsibble(index=Date)%>% index_by(year_week = ~ yearweek(.)) %>% summarise(weekly = sum(Y, na.rm = TRUE))
data.z<-zoo(data.w)
> data.z
year_week weekly
1 2020 W01 2.809756
2 2020 W02 4.579329
3 2020 W03 1.055690
I have a data set in which I'm tracking the dates a patient has specific symptoms
The data set looks like the following :
ID Date symp wt ht sympTY sympDays
1 1/05/2012 NA NA NA NA NA
1 1/06/2012 NA NA NA NA NA
1 1/07/2012 NA NA NA NA NA
1 1/08/2012 NA NA NA NA NA
1 1/09/2012 NA NA NA NA NA
1 1/10/2012 NA NA NA NA NA
1 1/11/2012 1 23 15 1 3
1 1/23/2015 NA 27 19 NA NA
2 2/17/2014 NA NA NA NA NA
2 2/18/2014 NA NA NA NA NA
2 2/19/2014 NA NA NA NA NA
2 2/20/2014 NA NA NA NA NA
2 2/21/2014 NA NA NA NA NA
2 2/22/2014 NA NA NA NA NA
2 2/23/2014 1 17 22 0 2
2 2/22/2016 NA NA NA NA NA
2 2/23/2016 NA NA NA NA NA
2 2/24/2016 NA NA NA NA NA
2 2/25/2016 NA NA NA NA NA
2 2/26/2016 NA NA NA NA NA
2 2/27/2016 NA NA NA NA NA
2 2/28/2016 1 20 30 1 5
2 3/17/2017 NA 25 32 NA NA
I want to create a new variable sympfl that tracks each day an individual has symptoms
additional info that may be pertinent :
symp - whether a patient has symptoms within the last week
sympTY - whether a patient had these symptoms today or yesterday
sympDays - the number of days the patient had these symptoms within the
past week
Conditions for new sympfl variable:
if symp == 1 and sympTY == 1, then sympfl == 1 starting on the present date going back the number sympDays column holds
if symp == 1 and sympTY == 0, then sympfl == 1 starting 2 days prior to the present date and going back the number the sympDays column holds
The new data set would ideally look like the following:
ID Date symp wt ht sympTY sympDays sympfl
1 1/05/2012 NA NA NA NA NA NA
1 1/06/2012 NA NA NA NA NA NA
1 1/07/2012 NA NA NA NA NA NA
1 1/08/2012 NA NA NA NA NA NA
1 1/09/2012 NA NA NA NA NA 1
1 1/10/2012 NA NA NA NA NA 1
1 1/11/2012 1 23 15 1 3 1
1 1/23/2015 NA 27 19 NA NA NA
2 2/17/2014 NA NA NA NA NA NA
2 2/18/2014 NA NA NA NA NA NA
2 2/19/2014 NA NA NA NA NA NA
2 2/20/2014 NA NA NA NA NA 1
2 2/21/2014 NA NA NA NA NA 1
2 2/22/2014 NA NA NA NA NA NA
2 2/23/2014 1 17 22 0 2 NA
2 2/22/2016 NA NA NA NA NA NA
2 2/23/2016 NA NA NA NA NA NA
2 2/24/2016 NA NA NA NA NA 1
2 2/25/2016 NA NA NA NA NA 1
2 2/26/2016 NA NA NA NA NA 1
2 2/27/2016 NA NA NA NA NA 1
2 2/28/2016 1 20 30 1 5 1
2 3/17/2017 NA 25 32 NA NA NA
I know in order to do this, I can use an if statement, but I'm uncertain how to do this over a number of rows by dates. Any help or direction is greatly appreciated.
Here is a data.table solution which reproduces the expected result for the given sample dataset:
library(data.table)
setDT(DT)[, Date := lubridate::mdy(Date)][
order(ID, -Date), sympfl := {
if (!is.na(first(symp))) {
tmp <- rep(NA_integer_, .N);
replace(tmp, 1 + seq((1 - first(sympTY)) * 3, length.out = first(sympDays)), 1)
}}, by = cumsum(!is.na(symp))][]
ID Date symp wt ht sympTY sympDays sympfl
1: 1 2012-01-05 NA NA NA NA NA NA
2: 1 2012-01-06 NA NA NA NA NA NA
3: 1 2012-01-07 NA NA NA NA NA NA
4: 1 2012-01-08 NA NA NA NA NA NA
5: 1 2012-01-09 NA NA NA NA NA 1
6: 1 2012-01-10 NA NA NA NA NA 1
7: 1 2012-01-11 1 23 15 1 3 1
8: 1 2015-01-23 NA 27 19 NA NA NA
9: 2 2014-02-17 NA NA NA NA NA NA
10: 2 2014-02-18 NA NA NA NA NA NA
11: 2 2014-02-19 NA NA NA NA NA 1
12: 2 2014-02-20 NA NA NA NA NA 1
13: 2 2014-02-21 NA NA NA NA NA NA
14: 2 2014-02-22 NA NA NA NA NA NA
15: 2 2014-02-23 1 17 22 0 2 NA
16: 2 2016-02-22 NA NA NA NA NA NA
17: 2 2016-02-23 NA NA NA NA NA NA
18: 2 2016-02-24 NA NA NA NA NA 1
19: 2 2016-02-25 NA NA NA NA NA 1
20: 2 2016-02-26 NA NA NA NA NA 1
21: 2 2016-02-27 NA NA NA NA NA 1
22: 2 2016-02-28 1 20 30 1 5 1
23: 2 2017-03-17 NA 25 32 NA NA NA
ID Date symp wt ht sympTY sympDays sympfl
Data
library(data.table)
DT <- fread("
ID Date symp wt ht sympTY sympDays
1 1/05/2012 NA NA NA NA NA
1 1/06/2012 NA NA NA NA NA
1 1/07/2012 NA NA NA NA NA
1 1/08/2012 NA NA NA NA NA
1 1/09/2012 NA NA NA NA NA
1 1/10/2012 NA NA NA NA NA
1 1/11/2012 1 23 15 1 3
1 1/23/2015 NA 27 19 NA NA
2 2/17/2014 NA NA NA NA NA
2 2/18/2014 NA NA NA NA NA
2 2/19/2014 NA NA NA NA NA
2 2/20/2014 NA NA NA NA NA
2 2/21/2014 NA NA NA NA NA
2 2/22/2014 NA NA NA NA NA
2 2/23/2014 1 17 22 0 2
2 2/22/2016 NA NA NA NA NA
2 2/23/2016 NA NA NA NA NA
2 2/24/2016 NA NA NA NA NA
2 2/25/2016 NA NA NA NA NA
2 2/26/2016 NA NA NA NA NA
2 2/27/2016 NA NA NA NA NA
2 2/28/2016 1 20 30 1 5
2 3/17/2017 NA 25 32 NA NA ")
Say I have a data frame as follows (in reality this is multiple data frames bound):
data.frame(
position = c(3,4,7,12,NA,NA,NA,NA,NA,NA,NA,NA),
colb = c(1,3,8,2,NA,NA,NA,NA,NA,NA,NA,NA),
colc = c(4,6,9,5,NA,NA,NA,NA,NA,NA,NA,NA),
position = c(2,7,8,10,11,12,15,16,19,21,24,26),
colb = c(1,3,8),
colc = c(4,6,9)
)
(Sorry, gets flagged if I post the data format myself.)
How can I transform this so I have a unified system of indicating a 'position'? ie one of the two formats below.
A single column scale:
position colb colc colb.1 colc.1
1 NA NA NA NA
2 NA NA 1 4
3 1 4 NA NA
4 3 6 NA NA
5 NA NA NA NA
6 NA NA NA NA
7 8 9 3 6
8 NA NA 8 9
9 NA NA NA NA
10 NA NA 1 4
11 NA NA 3 6
12 2 5 8 9
13 NA NA NA NA
14 NA NA NA NA
15 NA NA 1 4
16 NA NA 3 6
17 NA NA NA NA
18 NA NA NA NA
19 NA NA 8 9
20 NA NA NA NA
21 NA NA 1 4
22 NA NA NA NA
23 NA NA NA NA
24 NA NA 3 6
25 NA NA NA NA
26 NA NA 8 9
Or with separate columns, but 'matching':
position colb colc position.1 colb.1 colc.1
NA NA NA NA NA NA
NA NA NA 2 3 6
3 1 4 NA NA NA
4 3 6 NA NA NA
NA NA NA NA NA NA
NA NA NA NA NA NA
7 8 9 7 1 4
NA NA NA 8 3 6
NA NA NA NA NA NA
NA NA NA 10 1 4
NA NA NA 11 3 6
12 2 5 12 8 9
NA NA NA NA NA NA
NA NA NA NA NA NA
NA NA NA 15 8 9
NA NA NA 16 1 4
NA NA NA NA NA NA
NA NA NA NA NA NA
NA NA NA 19 1 4
NA NA NA NA NA NA
NA NA NA 21 8 9
NA NA NA NA NA NA
NA NA NA NA NA NA
NA NA NA 24 8 9
NA NA NA NA NA NA
NA NA NA 26 8 9
Any help is appreciated. Thanks.
If df contains the dataframe
df <- data.frame(
position = c(3,4,7,12,NA,NA,NA,NA,NA,NA,NA,NA),
colb = c(1,3,8,2,NA,NA,NA,NA,NA,NA,NA,NA),
colc = c(4,6,9,5,NA,NA,NA,NA,NA,NA,NA,NA),
position = c(2,7,8,10,11,12,15,16,19,21,24,26),
colb = c(1,3,8),
colc = c(4,6,9)
)
df1 <- df[,1:3]
df2 <- df[,4:6]
names(df2) <- c("position", "colb", "colc")
df_out <- rbind(df1, df2)
df_out <- df_out[!is.na(df_out$position),]
df_out <- df_out[order(df_out$position),]
df_out
I have the following data :
as.integer(datIn$Measurement.location)
myfunctionSD <- function(mydata) { return(sd(mydata,na.rm=TRUE))}
Alltubes <- tapply(datIn$Material.loss.interval,list(as.factor(datIn$Measurement.location),as.factor(datIn$Tube.number)),myfunctionSD)
From this I get the following output table:
1 2 3 4 5 6
1 0.8710740 0.7269928 0.8151022 0.6397234 0.8670634 0.7042107
10 NA 0.8075675 NA NA NA NA
11 0.6977951 NA 1.0984465 1.1148588 1.2156506 0.9620030
12 NA 0.5986758 NA NA NA NA
13 0.8386249 NA 0.8398164 0.8833184 1.2469221 1.0070322
14 NA 0.5109903 NA NA NA NA
15 NA NA NA 0.9391486 1.3571094 0.8375686
16 NA 0.5761583 NA NA NA NA
17 NA NA NA NA 1.0100850 0.7171070
19 NA NA NA NA 0.5913518 NA
3 0.5580579 0.6106961 0.8971073 0.7046614 0.8456784 0.8001571
4 NA 0.7228325 NA NA NA NA
5 0.9318795 NA 0.8961706 0.7753733 0.5915633 1.0471933
6 NA 0.5968613 NA NA NA NA
7 0.7674944 NA 0.7196781 0.8543926 0.7778685 0.8697442
8 NA 0.6283008 NA NA NA NA
9 1.3687895 NA 0.8815196 1.1723445 1.1589998 0.8194962
How do I rearrange the row numbers in the correct numeric order, so from 1 to 19 so I can plot it correctly?
Hope someone can help me.
Something like this...
> Alltubes[sort(as.numeric(rownames(Alltubes))), ]
df2 is your data frame
df2[order(as.numeric(rownames(df2))),]
X1 X2 X3 X4 X5 X6
1 0.8710740 0.7269928 0.8151022 0.6397234 0.8670634 0.7042107
3 0.5580579 0.6106961 0.8971073 0.7046614 0.8456784 0.8001571
4 NA 0.7228325 NA NA NA NA
5 0.9318795 NA 0.8961706 0.7753733 0.5915633 1.0471933
6 NA 0.5968613 NA NA NA NA
7 0.7674944 NA 0.7196781 0.8543926 0.7778685 0.8697442
8 NA 0.6283008 NA NA NA NA
9 1.3687895 NA 0.8815196 1.1723445 1.1589998 0.8194962
10 NA 0.8075675 NA NA NA NA
11 0.6977951 NA 1.0984465 1.1148588 1.2156506 0.9620030
12 NA 0.5986758 NA NA NA NA
13 0.8386249 NA 0.8398164 0.8833184 1.2469221 1.0070322
14 NA 0.5109903 NA NA NA NA
15 NA NA NA 0.9391486 1.3571094 0.8375686
16 NA 0.5761583 NA NA NA NA
17 NA NA NA NA 1.0100850 0.7171070
19 NA NA NA NA 0.5913518 NA