Data frame to wide with data compression [duplicate] - r

This question already has answers here:
How to reshape data from long to wide format
(14 answers)
Closed 6 years ago.
A data set similar to this...
ID <- c(rep(10,4),rep(20,4),rep(30,4),rep(40,4),rep(50,4))
Activity <- rep(c("In","Start","Finish","Out"),5)
Rsn <- c(rep("Rsn1",4),rep("Rsn11",4),rep("Rsn111",4),rep("Rsn11",4),rep("Rsn111",4))
Inst <- seq(1,20,1)
Loc <- c(rep("Here",4),rep("There",4),rep("Anywhere",4),rep("Somewhere",4),rep("SomewhereElse",4))
dc <- data.frame(ID,Activity,Rsn,Inst,Loc)
ID Activity Rsn Inst Loc
10 In Rsn1 1 Here
10 Start Rsn1 2 Here
10 Finish Rsn1 3 Here
10 Out Rsn1 4 Here
20 In Rsn11 5 There
20 Start Rsn11 6 There
20 Finish Rsn11 7 There
20 Out Rsn11 8 There
30 In Rsn111 9 Anywhere
30 Start Rsn111 10 Anywhere
30 Finish Rsn111 11 Anywhere
30 Out Rsn111 12 Anywhere
40 In Rsn11 13 Somewhere
40 Start Rsn11 14 Somewhere
40 Finish Rsn11 15 Somewhere
40 Out Rsn11 16 Somewhere
50 In Rsn111 17 SomewhereElse
50 Start Rsn111 18 SomewhereElse
50 Finish Rsn111 19 SomewhereElse
50 Out Rsn111 20 SomewhereElse
the end result that I would like to end up with is this...
ID2 <- c(10,20,30,40,50)
In2 <- seq(1,20,4)
Start2 <- seq(2,20,4)
Finish2 <- seq(3,20,4)
Out2 <- seq(4,20,4)
Rsn2 <- c("Rsn1","Rsn11","Rsn111","Rsn11","Rsn111")
Loc2 <- c("Here","There","Anywhere","Somewhere","SomewhereElse")
dw <- data.frame(ID2, In2, Start2, Finish2, Out2, Rsn2,Loc2)
ID In2 Start2 Finish2 Out2 Rsn2 Loc2
10 1 2 3 4 Rsn1 Here
20 5 6 7 8 Rsn11 There
30 9 10 11 12 Rsn111 Anywhere
40 13 14 15 16 Rsn11 Somewhere
50 17 18 19 20 Rsn111 SomewhereElse
I have used tidyr, reshape and can't seem to get it right.
The data set has 816K lines and takes forever with loops and conditionals.
I have broken the dataset down by the locations, but it is still slow.
Thanks in advance.

we can use dcast
library(data.table)
dcast(setDT(dc), ID+Rsn+Loc~Activity, value.var = "Inst")

Related

Using a date to find out the number of data entry in time series vector

I am currently working with time series data. Having converted the data using the time series function and indicating the correct starting point and frequency, I wondered if it is possible to do operations using a date as indicator for referring to a specific data entry. More specifically, if I have a quarterly series from 1994Q1 to 2007Q2 I wondered if I can access a range of data entries using something like
I hope the following code helps to understand my problem:
# Assuming that full.data is the data sample
full.data <- ts(seq(1:56),start=c(1994,1),frequency = 4)
# I would like to extract specific data entries using dates. Of course,
# the example below does not work but I wondered if something similar like this would be possible:
data.short <- data.full["1995Q1" : "2005Q2"]
I would really appreciate any help or idea, thanks so much!
You can use the window() function which is apparently made for this scenario:
data.short <- window(full.data, start = c(1995, 1), end = c(2005, 2))
See ?window for further information.
Convert to xts and then use the syntax shown. You can omit the conversion back if an xts object is ok:
library(xts)
xx <- as.xts(full.data)
as.ts(xx["1995-1/2005-2"])
giving:
Qtr1 Qtr2 Qtr3 Qtr4
1 5 6 7 8
2 9 10 11 12
3 13 14 15 16
4 17 18 19 20
5 21 22 23 24
6 25 26 27 28
7 29 30 31 32
8 33 34 35 36
9 37 38 39 40
10 41 42 43 44
11 45

Transpose column and group dataframe [duplicate]

This question already has answers here:
How to reshape data from long to wide format
(14 answers)
Closed 5 years ago.
I'm trying to change a dataframe in R to group multiple rows by a measurement. The table has a location (km), a size (mm) a count of things in that size bin, a site and year. I want to take the sizes, make a column from each one (2, 4 and 6 in this example), and place the corresponding count into each the row for that location, site and year.
It seems like a combination of transposing and grouping, but I can't figure out a way to accomplish this in R. I've looked at t(), dcast() and aggregate(), but those aren't really close at all.
So I would go from something like this:
df <- data.frame(km=c(rep(32,3),rep(50,3)), mm=rep(c(2,4,6),2), count=sample(1:25,6), site=rep("A", 6), year=rep(2013, 6))
km mm count site year
1 32 2 18 A 2013
2 32 4 2 A 2013
3 32 6 12 A 2013
4 50 2 3 A 2013
5 50 4 17 A 2013
6 50 6 21 A 2013
To this:
km site year mm_2 mm_4 mm_6
1 32 A 2013 18 2 12
2 50 A 2013 3 17 21
Edit: I tried the solution in a suggested duplicate, but I did not work for me, not really sure why. The answer below worked better.
As suggested in the comment above, we can use the sep argument in spread:
library(tidyr)
spread(df, mm, count, sep = "_")
km site year mm_2 mm_4 mm_6
1 32 A 2013 4 20 1
2 50 A 2013 15 14 22
As you mentioned dcast(), here is a method using it.
set.seed(1)
df <- data.frame(km=c(rep(32,3),rep(50,3)),
mm=rep(c(2,4,6),2),
count=sample(1:25,6),
site=rep("A", 6),
year=rep(2013, 6))
library(reshape2)
dcast(df, ... ~ mm, value.var="count")
# km site year 2 4 6
# 1 32 A 2013 13 10 20
# 2 50 A 2013 3 17 1
And if you want a bit of a challenge you can try the base function reshape().
df2 <- reshape(df, v.names="count", idvar="km", timevar="mm", ids="mm", direction="wide")
colnames(df2) <- sub("count.", "mm_", colnames(df2))
df2
# km site year mm_2 mm_4 mm_6
# 1 32 A 2013 13 10 20
# 4 50 A 2013 3 17 1

Extract intervals from time data in R

My problem is simple. I have table where each row is event (month, day, hour, minute is given). However, the machine was set to record 24/7. So I have more events (rows) than I need. How to remove surplus rows from daytime and to keep only rows from night (from sunset to sunrise)?
Dreadful thing is, that the timing of sunrise/sunset is slightly different each day.
In this example I provide two tables. First is table with all events, second contain timings of sunset/sunrise for each day.
If it is possible to extract, please notice that EACH night consists from two dates could be a additional column inserted in table containing ID of night? (see scheme below)
# table with all events
my.table <- data.frame(event = 1:34,
day = rep(c(30,31,1,2,3), times = c(8,9,7,8,2)),
month = rep(c(3,4), each = 17),
hour = c(13,13,13,13,22,
22,23,23,2,2,2,
14,14,14,19,22,22,
2,2,2,14,15,22,22,
3,3,3,14,14,14,
23,23,2,14),
minute = c(11,13,44,55,27,
32,54,57,10,14,
26,12,16,46,30,
12,13,14,16,45,
12,15,12,15,24,
26,28,12,16,23,12,13,11,11))
# timings of sunset/sunrise for each day
sun.table <- data.frame(day = c(30,31,31,1,1,2,2,3),
month = rep(c(3,4), times = c(3,5)),
hour = rep(c(19,6), times = 4),
minute = c(30,30,31,29,32,
28,33,27),
type = rep(c("sunset","sunrise"), times = 4))
# rigth solution reduced table would contain only rows:
# 5,6,7,8,9,10,11,16,17,18,19,20,23,24,25,26,27,31,32,33.
# nrow("reduced table") == 20
Here's one possible strategy
#convert sun-up, sun-down times to proper dates
ss <- with(sun.table, ISOdate(2000,month,day,hour,minute))
up <- ss[seq(1,length(ss),by=2)]
down <- ss[seq(2,length(ss),by=2)]
Here I assume the table is ordered and starts with a sunrise and alternates back and forth and ends with a sunset. Date values also need a year, here I just hard coded 2000. As long as your data doesn't span years (or leap days) that should be fine, but you'll probably want to pop in the actual year of your observations.
Now do the same for events
tt <- with(my.table, ISOdate(2000,month,day,hour,minute))
Find rows during the day
daytime <- sapply(tt, function(x) any(up<x & x<down))
and extract those rows
my.table[daytime, ]
# event day month hour minute
# 5 5 30 3 22 27
# 6 6 30 3 22 32
# 7 7 30 3 23 54
# 8 8 30 3 23 57
# 9 9 31 3 2 10
# 10 10 31 3 2 14
# 11 11 31 3 2 26
# 16 16 31 3 22 12
# 17 17 31 3 22 13
# 18 18 1 4 2 14
# 19 19 1 4 2 16
# 20 20 1 4 2 45
# 23 23 1 4 22 12
# 24 24 1 4 22 15
# 25 25 2 4 3 24
# 26 26 2 4 3 26
# 27 27 2 4 3 28
# 31 31 2 4 23 12
# 32 32 2 4 23 13
# 33 33 3 4 2 11
Here we only grab values that are after sunrise and before sunset. Since there isn't enough information in the sun.table to make sure that row 34 actually happens before subset, it is not returned.

Prepare Time Series for Machine Learning - Long to Wide Format

I have a data frame of time series data in a 'long' format where there is 1 row/observation per day. I would like to transform this data into a 'wide' format. Each row/observation should have the time series value for the current date and the previous 2 days.
To provide a concrete example, I will use the Air Quality data available in R. This is what my input data frame looks like.
> input <- airquality[1:4,c("Month", "Day", "Ozone")]
> input
Month Day Ozone
1 5 1 41
2 5 2 36
3 5 3 12
4 5 4 18
I would like to transform this input so that it looks like the following.
output <- data.frame(Month = 5, Day = 1:4, Ozone=c(41,36,12,18), Ozone.Prev.1=c(NA,41,36,12), Ozone.Prev.2=c(NA,NA,41,36))
> output
Month Day Ozone Ozone.Prev.1 Ozone.Prev.2
1 5 1 41 NA NA
2 5 2 36 41 NA
3 5 3 12 36 41
4 5 4 18 12 36
Any suggestions on a nice, clean way to do this? Many thanks in advance.
You can use the lag function from zoo, but the following small function get's the trick done without using additional packages:
shift_vector = function(vec, n) c(rep(NA, n), head(vec, -n))
output = transform(input, prev_1 = shift_vector(Ozone, 1),
prev_2 = shift_vector(Ozone, 2))
output
Month Day Ozone prev_1 prev_2
1 5 1 41 NA NA
2 5 2 36 41 NA
3 5 3 12 36 41
4 5 4 18 12 36

Pivot table from column to row in excel or R [duplicate]

This question already has answers here:
Reshape data from wide to long? [duplicate]
(3 answers)
Closed 9 years ago.
I have a table with header like this
Id x.1960 x.1970 x.1980 x.1990 x.2000 y.1960 y.1970 y.1980 y.1990 y.2000
I want to pivot this table as
Id time x y
What is the best way to do this in Excel or R?
Something like this using base R reshape:
Get some data first
test <- read.table(text="Id x.1960 x.1970 x.1980 x.1990 x.2000 y.1960 y.1970 y.1980 y.1990 y.2000
a 1 2 3 4 5 6 7 8 9 10
b 10 20 30 40 50 60 70 80 90 100",header=TRUE)
Then reshape:
reshape(
test,
idvar="Id",
varying=list(2:6,7:11),
direction="long",
v.names=c("x","y"),
times=seq(1960,2000,10)
)
Or let reshape guess the names automatically based on the . separator:
reshape(
test,
idvar="Id",
varying=-1,
direction="long",
sep="."
)
Resulting in:
Id time x y
a.1960 a 1960 1 6
b.1960 b 1960 10 60
a.1970 a 1970 2 7
b.1970 b 1970 20 70
a.1980 a 1980 3 8
b.1980 b 1980 30 80
a.1990 a 1990 4 9
b.1990 b 1990 40 90
a.2000 a 2000 5 10
b.2000 b 2000 50 100

Resources