I am sorry if it seems like a foolish question but I want to ask how to select cases that have the same id and index
This is an example of my dataframe:
df1<-structure(list(id = c(10, 10, 10, 11, 11, 11), pnum = c(1,
2, 3, 1, 2, 3), index = c(1, 2, 2, 1, 1, 1)), class = "data.frame", row.names = c(NA,
-6L))
Also if in and index has the values across all pnums:
df2<-structure(list(id = c(10, 10, 10, 11, 11, 11), pnum = c(1,
2, 3, 1, 2, 3), index = c(1, 1, 2, 2, 2, 2)), class = "data.frame", row.names = c(NA,
-6L))
I need to select cases that have the same id and index
End table should be this:
for df1
id pnum index
11 1 1
11 2 1
11 3 1
Also when id and index belong to the same group:
df2 outcome
id pnum index
10 1 2
10 2 2
10 3 2
We can use subset from base R
subset(df1, id == index)
# id pnum index
#4 1 1 1
#5 1 2 1
#6 1 3 1
Or with filter
library(dplyr)
df1 %>%
filter(id == index)
For the second case, may be we can use
df2 %>%
group_by(id) %>%
filter(n_distinct(index) > 1) %>%
mutate(index = 2)
We can select id's where there are only 1 unique index value.
library(data.table)
setDT(df1)[, .SD[uniqueN(index) == 1], id]
# id pnum index
#1: 11 1 1
#2: 11 2 1
#3: 11 3 1
For df2 this returns as :
setDT(df2)[, .SD[uniqueN(index) == 1], id]
# id pnum index
#1: 11 1 2
#2: 11 2 2
#3: 11 3 2
We can translate this to dplyr as :
df1 %>% group_by(id) %>% filter(n_distinct(index) == 1)
and in base R :
subset(df1, ave(index, id, FUN = function(x) length(unique(x))) == 1)
Related
I would like to reshape the data sample below, so that to get the output like in the table. How can I reach to that? the idea is to split the column e into two columns according to the disease. Those with disease 0 in one column and those with disease 1 in the other column. thanks in advance.
structure(list(id = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), fid = c(1,
1, 2, 2, 3, 3, 4, 4, 5, 5), disease = c(0, 1, 0, 1, 1, 0, 1, 0, 0,
1), e = c(3, 2, 6, 1, 2, 5, 2, 3, 1, 1)), class = c("tbl_df",
"tbl", "data.frame"), row.names = c(NA, -10L))
library(tidyverse)
df %>%
pivot_wider(fid, names_from = disease, values_from = e, names_prefix = 'e') %>%
select(-fid)
e0 e1
<dbl> <dbl>
1 3 2
2 6 1
3 5 2
4 3 2
5 1 1
if you want the e1,e2 you could do:
df %>%
pivot_wider(fid, names_from = disease, values_from = e,
names_glue = 'e{disease + 1}') %>%
select(-fid)
# A tibble: 5 x 2
e1 e2
<dbl> <dbl>
1 3 2
2 6 1
3 5 2
4 3 2
5 1 1
We could use lead() combined with ìfelse statements for this:
library(dplyr)
df %>%
mutate(e2 = lead(e)) %>%
filter(row_number() %% 2 == 1) %>%
mutate(e1 = ifelse(disease==1, e2,e),
e2 = ifelse(disease==0, e2,e)) %>%
select(e1, e2)
e1 e2
<dbl> <dbl>
1 3 2
2 6 1
3 5 2
4 3 2
5 1 1
I have a data frame that looks likes this:
structure(list(value1 = c(1, 2, 3, 4, 5), value2 = c(1, 2, 2,
2, 2), value3 = c(1, 1, 2, 3, 4)), class = "data.frame", row.names = c("apple1",
"apple2", "orange1", "orange2", "plum"))
value1
value2
value3
apple1
1
1
1
apple2
2
2
1
orange1
3
2
2
orange2
4
2
3
plum
5
2
4
now I want to run the mean function on every column based on the first part of the row names
(for example I want to calculate the mean of value1 of the apple group independently from their apple number.)
I figured out that something like this works:
y<-x[grep("apple",row.names(x)),]
mean(y$value1)
mean(y$value2)
mean(y$vvalue3)
y<-x[grep("orange",row.names(x)),]
mean(y$value1)
mean(y$value2)
mean(y$value2)
y<-x[grep("plum",row.names(x)),]
mean(y$value1)
mean(y$value2)
mean(y$value2)
but for a bigger dataset, this is going to take ages, so I was wondering if there is a more efficient way to subset the data based on the first part of the row name and calculating the mean afterward.
Using tidyverse:
library(tidyverse)
df %>%
tibble::rownames_to_column("row") %>%
dplyr::mutate(row = str_remove(row, "\\d+")) %>%
dplyr::group_by(row) %>%
dplyr::summarize(across(where(is.numeric), ~ mean(.), .groups = "drop"))
In base R you could do:
df$row <- gsub("\\d+", "", rownames(df))
data.frame(do.call(cbind, lapply(df[,1:3], function(x) by(x, df$row, mean))))
Output
row value1 value2 value3
* <chr> <dbl> <dbl> <dbl>
1 apple 1.5 1.5 1
2 orange 3.5 2 2.5
3 plum 5 2 4
Data
df <- structure(list(value1 = 1:5, value2 = c(1, 2, 2, 2, 2), value3 = c(1,
1, 2, 3, 4)), class = "data.frame", row.names = c("apple1", "apple2",
"orange1", "orange2", "plum"))
I have a dataframe with Markets, Retailers and Sales. I need to bin the Retailers within each Market into 5 quantiles.
Example:
dataframe <- structure(list(Market = c(1, 1, 1, 2, 2, 2), Retailer = c(1,
2, 3, 4, 5, 6), Sales = c(5, 10, 25, 5, 10, 25), Quantile = c(1,
2, 3, 1, 2, 3)), class = "data.frame", row.names = c(NA, -6L))
One approach is using group_by and ntile from dplyr:
library(dplyr)
dataframe %>%
group_by(Market) %>%
mutate(Quantile = ntile(Sales, 4))
# A tibble: 150 x 4
# Groups: Market [3]
Market Retailer Sales Quantile
<int> <int> <dbl> <int>
1 1 1 16804 1
2 1 2 80752 4
3 1 3 38494 2
4 1 4 32773 2
5 1 5 60210 3
# … with 145 more rows
Data
set.seed(3)
dataframe <- data.frame(Market = rep(1:3, each = 50),
Retailer = rep(1:50, times = 3),
Sales = round(runif(150,0,100000),0))
How might I calculate the delta between multiple variables grouped by user ids in a "long" data frame?
Data format:
d1 <- data.frame(
id = rep(c(1, 2, 3, 4, 5), each = 2),
purchased = c(rep(c(T, F), 3), F, T, T, F),
product = rep(c("A", "B"), 5),
grade = c(1, 2, 1, 2, 2, 3, 7, 5, 1, 2),
rate = c(10, 12, 10, 12, 12, 14, 22, 18, 10, 12),
fee = rep(c(1, 2), 5))
This is my roundabout solution:
dA <- d1 %>%
filter(product == "A")
dB <- d1 %>%
filter(product == "B")
d2 <- inner_join(dA, dB, by = "id", suffix = c(".A", ".B"))
d3 <- d2 %>%
mutate(
purchased = if_else(purchased.A == T, "A", "B"),
dGrade = grade.B - grade.A,
dRate = rate.B - rate.A,
dFee = fee.B - fee.A) %>%
select(id, purchased:dFee)
All of this just seems terribly inefficient and complex. Is tidyr::spread or another dplyr/tidyr function appropriate here? (I couldn't get anything else to work)...
We can do this with gather/spread. Reshape the data from 'wide' to 'long' using gather, grouped by 'id', 'Var', we get the 'product' based on the logical column 'purchased', get the difference of 'Val' for 'product' that are 'B' and 'A', and spread it from 'long' to 'wide' format.
library(dplyr)
library(tidyr)
gather(d1, Var, Val, grade:fee) %>%
group_by(id, Var) %>%
summarise(purchased = product[purchased],
Val = Val[product == 'B'] - Val[product == 'A'])%>%
spread(Var, Val)
# id purchased fee grade rate
# <dbl> <fctr> <dbl> <dbl> <dbl>
#1 1 A 1 1 2
#2 2 A 1 1 2
#3 3 A 1 1 2
#4 4 B 1 -2 -4
#5 5 A 1 1 2
The OP's output ('d3') is
d3
# id purchased dGrade dRate dFee
#1 1 A 1 2 1
#2 2 A 1 2 1
#3 3 A 1 2 1
#4 4 B -2 -4 1
#5 5 A 1 2 1
I have a data.frame where I'd like to remove entire groups if any of their members meets a condition.
In this first example, if the values are numbers and the condition is NA the code below works.
df <- structure(list(world = c(1, 2, 3, 3, 2, NA, 1, 2, 3, 2), place = c(1,
1, 2, 2, 3, 3, 1, 2, 3, 1), group = c(1, 1, 1, 2, 2, 2, 3,
3, 3, 3)), .Names = c("world", "place", "group"), row.names = c(NA,
-10L), class = "data.frame")
ans <- ddply(df, . (group), summarize, code=mean(world))
ans$code[is.na(ans$code)] <- 0
ans2 <- merge(df,ans)
final.ans <- ans2[ans2$code !=0,]
However, this ddply maneuver with the NA values will not work if the condition is something other than "NA", or if the value are non-numeric.
For example, if I wanted to remove groups which have one or more rows with a world value of AF (as in the data frame below) this ddply trick would not work.
df2 <-structure(list(world = structure(c(1L, 2L, 3L, 3L, 3L, 5L, 1L,
4L, 2L, 4L), .Label = c("AB", "AC", "AD", "AE", "AF"), class = "factor"),
place = c(1, 1, 2, 2, 3, 3, 1, 2, 3, 1), group = c(1,
1, 1, 2, 2, 2, 3, 3, 3, 3)), .Names = c("world", "place",
"group"), row.names = c(NA, -10L), class = "data.frame")
I can envision a for-loop where for each group the value of each member is checked, and if the condition is met a code column could be populated, and then a subset could me made based on that code.
But, perhaps there is a vectorized, r way to do this?
Using dplyr:
library(dplyr)
df2 %>%
group_by(group) %>%
filter(!any(world == "AF"))
Or as per motioned by #akrun using data.table:
library(data.table)
setDT(df2)[, if(!any(world == "AF")) .SD, group]
#or
setDT(df2)[, if(all(world != "AF")) .SD, group]
Which gives:
#Source: local data frame [7 x 3]
#Groups: group
#
# world place group
#1 AB 1 1
#2 AC 1 1
#3 AD 2 1
#4 AB 1 3
#5 AE 2 3
#6 AC 3 3
#7 AE 1 3
Alternate data.table solution:
setDT(df2)
df2[!(group %in% df2[world == "AF",group])]
gives:
world place group
1: AB 1 1
2: AC 1 1
3: AD 2 1
4: AB 1 3
5: AE 2 3
6: AC 3 3
7: AE 1 3
Using keys we can be a bit faster:
setkey(df2,group)
df2[!J((df2[world == "AF",group]))]
base package:
df2[ df2$group != df2[ df2$world == 'AF', "group" ], ]
Output:
world place group
1 AB 1 1
2 AC 1 1
3 AD 2 1
7 AB 1 3
8 AE 2 3
9 AC 3 3
10 AE 1 3
Using sqldf:
library(sqldf)
sqldf("SELECT df2.world, df2.place, [group] FROM df2
LEFT JOIN
(SELECT * FROM df2 WHERE world LIKE 'AF') AS t
USING([group])
WHERE t.world IS NULL")
Output:
world place group
1 AB 1 1
2 AC 1 1
3 AD 2 1
4 AB 1 3
5 AE 2 3
6 AC 3 3
7 AE 1 3
Base R option using ave
df2[with(df2, ave(world != "AF", group, FUN = all)),]
# world place group
#1 AB 1 1
#2 AC 1 1
#3 AD 2 1
#7 AB 1 3
#8 AE 2 3
#9 AC 3 3
#10 AE 1 3
Or we can also use subset
subset(df2, ave(world != "AF", group, FUN = all))
The above can also be written as
df2[with(df2, !ave(world == "AF", group, FUN = any)),]
and
subset(df2, !ave(world == "AF", group, FUN = any))