我有一个数据帧--say x - 它提供一个函数,该函数根据列x $ id的值返回一个子集。
此子集y包含y $ room列,其中包含不同的值组合,具体取决于x $ id值。
然后用tidyr传播子集,y $ room的值成为列 然后,生成的扩展df --say ext_y--必须按列y_ext $ visit进行分组,并且应通过特殊函数计算剩余列的汇总统计信息。
显而易见的问题是这些列事先是未知的,因此无法通过函数中的名称来定义。
当涉及group_by时,使用列的索引而不是名称的替代方法似乎不适用于dplyr。
您是否有任何想法可以解决这个问题?
数据框有几千行,所以我只给你一瞥:
> tail(y)
id visit room value
11940 14 2 living room 19
11941 14 2 living room 16
11942 14 2 living room 15
11943 14 2 living room 22
11944 14 2 living room 25
11945 14 2 living room 20
> unique(x$id)
[1] 14 20 41 44 46 54 64 74 104 106
> unique(x$visit)
[1] 0 1 2
> unique(x$room)
[1] "bedroom" "living room" "family room" "study room" "den"
[6] "tv room" "office" "hall" "kitchen" "dining room"
> summary(x$value)
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.000 2.750 7.875 17.410 16.000 1775.000
对于给定的id,tidyr的spread()仅返回x中房间值的子集。例如。对于id = 54:
> y<- out
> y$row <- 1 : nrow(y)
> y_ext <- spread(y, room, value)
> head(y_ext)
id visit row bedroom family room living room
1 14 0 1 6.00 NA NA
2 14 0 2 6.00 NA NA
3 14 0 3 2.75 NA NA
4 14 0 4 2.75 NA NA
5 14 0 5 2.75 NA NA
6 14 0 6 2.75 NA NA
现在,我必须编写一个函数,按访问对结果进行分组,并按以下格式汇总为每个组返回的列:
visit bedroom family room living room
1 0 NA 2.79 3.25
2 1 NA NA 4.53
3 2 4.19 3.77 NA
正如我上面提到的,我事先并不知道将为给定的id返回哪些列,这使问题复杂化。当然是捷径 检查并找出每个id返回哪些列,然后创建一个 如果结构将每个id引导到适当的代码,但这不是很优雅,我担心。
希望这有助于您更好地了解情况。
答案 0 :(得分:1)
好吧,这对我来说很有趣,我自己制作了一些样本数据:
nSamples <- 50
allRooms <-
c("Living", "Dining", "Bedroom", "Master", "Family", "Garage", "Office")
set.seed(8675309)
df <-
data_frame(
id = sample(1:5, nSamples, TRUE)
, visit = sample(1:3, nSamples, TRUE)
, room = sample(allRooms, nSamples, TRUE)
, value = round(rnorm(nSamples, 20, 5))
)
我看待它的方式,有三种方法,按合理性的升序排列。第一个选择是遵循您的基本布局。在这里,我按df
分割id
,按指示进行传播,然后使用summarise_all
进行求和,无需明确识别房间名称。
df %>%
split(.$id) %>%
lapply(function(x){
x %>%
select(-id) %>%
mutate(row = 1:n()) %>%
spread(room, value) %>%
select(-row) %>%
group_by(visit) %>%
summarise_all(sum, na.rm = TRUE)
})
返回以下内容(注释唯一列):
$`1`
# A tibble: 3 × 6
visit Bedroom Dining Garage Master Office
<int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0 27 27 0 0
2 2 22 19 0 20 23
3 3 0 0 0 27 0
$`2`
# A tibble: 3 × 6
visit Bedroom Dining Family Living Office
<int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 15 0 0 0 17
2 2 0 14 42 30 0
3 3 15 13 18 0 20
$`3`
# A tibble: 3 × 6
visit Bedroom Dining Living Master Office
<int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 24 0 36 0 28
2 2 0 0 15 30 0
3 3 0 25 21 0 15
$`4`
# A tibble: 3 × 7
visit Bedroom Dining Garage Living Master Office
<int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0 0 23 20 0 24
2 2 0 28 22 0 0 0
3 3 24 0 36 0 16 0
$`5`
# A tibble: 3 × 8
visit Bedroom Dining Family Garage Living Master Office
<int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 23 0 0 21 0 16 0
2 2 44 14 41 0 26 0 18
3 3 21 19 0 0 25 19 0
但是,因为您必须添加行以使spread
正常工作(没有它,所以没有唯一条目),spread
实际上没有帮助。如果你先进行总结,你可以更容易地得到同样的东西,如下:
df %>%
split(.$id) %>%
lapply(function(x){
x %>%
select(-id) %>%
group_by(visit, room) %>%
summarise(Sum = sum(value)) %>%
spread(room, Sum, 0)
})
请注意,由于0
参数的最后0
,它为没有访问的会议室提供了fill
。如果您希望返回NA
,则可以保留默认值。
最后,目前还不清楚为什么要首先单独进行此操作。在一个大的group_by
中完成所有这一切可能更有意义,并在事后处理所需的缺失。也就是说,获得相同摘要的代码要少得多。
df %>%
group_by(id, visit, room) %>%
summarise(sum = sum(value)) %>%
spread(room, sum)
给出
id visit Bedroom Dining Family Garage Living Master Office
* <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 NA 27 NA 27 NA NA NA
2 1 2 22 19 NA NA NA 20 23
3 1 3 NA NA NA NA NA 27 NA
4 2 1 15 NA NA NA NA NA 17
5 2 2 NA 14 42 NA 30 NA NA
6 2 3 15 13 18 NA NA NA 20
7 3 1 24 NA NA NA 36 NA 28
8 3 2 NA NA NA NA 15 30 NA
9 3 3 NA 25 NA NA 21 NA 15
10 4 1 NA NA NA 23 20 NA 24
11 4 2 NA 28 NA 22 NA NA NA
12 4 3 24 NA NA 36 NA 16 NA
13 5 1 23 NA NA 21 NA 16 NA
14 5 2 44 14 41 NA 26 NA 18
15 5 3 21 19 NA NA 25 19 NA
如果您想要过滤到只有一个id
,请在事后使用filter
,然后删除包含所有NA
条目的列。 (注意,你可能会保存一次输出,然后为每个感兴趣的id传递一次最后两行,例如打印时)
df %>%
group_by(id, visit, room) %>%
summarise(sum = sum(value)) %>%
spread(room, sum) %>%
filter(id == 1) %>%
select_if(function(col) mean(is.na(col)) != 1)
给出
id visit Bedroom Dining Garage Master Office
<int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 NA 27 27 NA NA
2 1 2 22 19 NA 20 23
3 1 3 NA NA NA 27 NA