将R数据框中的多行合并为一行
Uniting multiple rows in R data frame into one row
我有一个 R 数据框,里面有很多零。它基本上是这样的:
年
性别
宝马
大众
奔驰
2018
男
最大值
0
0
2019
男
彼得
0
0
2019
男
0
彼得
0
2019
男
0
0
彼得
此 table 中的一行表示每年一位客户。每个客户可以拥有 0、1 或多辆汽车(来自不同制造商)...
现在,我想让 table 更紧凑。事实上,我想将最后三行合并为一行。由于 Peter 拥有所有三辆车,并且他的所有汽车都在同一年注册,所以 Peter 看起来像这样的条目应该足够了:
年
性别
宝马
大众
奔驰
2019
男
彼得
彼得
彼得
最后,输出应该是这样的:
年
性别
宝马
大众
奔驰
2018
男
最大值
0
0
2019
男
彼得
彼得
彼得
我怎样才能做到这一点?
我想要每人一年一行!
(部分回答)
将 0 变为 NA 后(编辑:进行更改:data[data == 0] <- NA
),您可以:
data %>%
group_by(Year, Gender) %>%
summarise_all(na.omit)
但这只适用于每年只有一个消费者的情况,这里就是这种情况,但可能不适用于所有数据。在按年份合并行之前,您应该考虑使用 Id 列或其他内容。
对于 Year
和 Gender
的每个值,您可以 select 每列中的第一个非 0 值。
library(dplyr)
res <- df %>%
group_by(Year, Gender) %>%
summarise(across(.fns = ~.[. != 0][1])) %>%
ungroup()
res
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
#1 2018 Male Max NA NA
#2 2019 Male Peter Peter Peter
如果您想删除包含任何 NA
行的行,您可以将答案扩展为
res %>% filter(if_all(BMW:Mercedes, Negate(is.na)))
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
#1 2019 Male Peter Peter Peter
数据
df <- structure(list(Year = c(2018L, 2019L, 2019L, 2019L), Gender = c("Male",
"Male", "Male", "Male"), BMW = c("Max", "Peter", "0", "0"), VW = c("0",
"0", "Peter", "0"), Mercedes = c("0", "0", "0", "Peter")),
class = "data.frame", row.names = c(NA, -4L))
由于您希望数据按性别和年份“分组”,我建议对这些变量进行整形,过滤掉您不想要的内容,然后再整形回宽。
library(dplyr)
library(tidyr) # pivot_*
dat %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0") %>%
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# # A tibble: 2 x 5
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
# 1 2018 Male Max <NA> <NA>
# 2 2019 Male Peter Peter Peter
如果存在重复 year/gender/names,就会出现问题。例如,
bind_rows(dat, dat[3,])
# Year Gender BMW VW Mercedes
# 1 2018 Male Max 0 0
# 2 2019 Male Peter 0 0
# 3 2019 Male 0 Peter 0
# 4 2019 Male 0 0 Peter
# 5 2019 Male 0 Peter 0
bind_rows(dat, dat[3,]) %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0") %>%
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# Warning: Values are not uniquely identified; output will contain list-cols.
# * Use `values_fn = list` to suppress this warning.
# * Use `values_fn = length` to identify where the duplicates arise
# * Use `values_fn = {summary_fun}` to summarise duplicates
# # A tibble: 2 x 5
# Year Gender BMW VW Mercedes
# <int> <chr> <list> <list> <list>
# 1 2018 Male <chr [1]> <NULL> <NULL>
# 2 2019 Male <chr [1]> <chr [2]> <chr [1]>
在这种情况下,如果您想删除完全重复的内容,那么您可以这样做:
bind_rows(dat, dat[3,]) %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0", !duplicated(.)) %>% # updated
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# # A tibble: 2 x 5
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
# 1 2018 Male Max <NA> <NA>
# 2 2019 Male Peter Peter Peter
尽管确实“丢失”了彼得两次列出大众汽车的事实……这可能是两个不同的大众汽车。如果您 want/need 保留此信息,则一个 hackish 修复是
bind_rows(dat, dat[3,]) %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0") %>%
group_by(Year, Gender, name, value) %>%
mutate(name = paste0(name, replace(seq_along(name), 1, ""))) %>%
ungroup() %>%
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# # A tibble: 2 x 6
# Year Gender BMW VW Mercedes VW2
# <int> <chr> <chr> <chr> <chr> <chr>
# 1 2018 Male Max <NA> <NA> <NA>
# 2 2019 Male Peter Peter Peter Peter
(或在不影响其他汽车的情况下明确传达“第二大众”的类似方式)。
数据
dat <- structure(list(Year = c(2018L, 2019L, 2019L, 2019L), Gender = c("Male", "Male", "Male", "Male"), BMW = c("Max", "Peter", "0", "0"), VW = c("0", "0", "Peter", "0"), Mercedes = c("0", "0", "0", "Peter")), class = "data.frame", row.names = c(NA, -4L))
我有一个 R 数据框,里面有很多零。它基本上是这样的:
年 | 性别 | 宝马 | 大众 | 奔驰 |
---|---|---|---|---|
2018 | 男 | 最大值 | 0 | 0 |
2019 | 男 | 彼得 | 0 | 0 |
2019 | 男 | 0 | 彼得 | 0 |
2019 | 男 | 0 | 0 | 彼得 |
此 table 中的一行表示每年一位客户。每个客户可以拥有 0、1 或多辆汽车(来自不同制造商)...
现在,我想让 table 更紧凑。事实上,我想将最后三行合并为一行。由于 Peter 拥有所有三辆车,并且他的所有汽车都在同一年注册,所以 Peter 看起来像这样的条目应该足够了:
年 | 性别 | 宝马 | 大众 | 奔驰 |
---|---|---|---|---|
2019 | 男 | 彼得 | 彼得 | 彼得 |
最后,输出应该是这样的:
年 | 性别 | 宝马 | 大众 | 奔驰 |
---|---|---|---|---|
2018 | 男 | 最大值 | 0 | 0 |
2019 | 男 | 彼得 | 彼得 | 彼得 |
我怎样才能做到这一点? 我想要每人一年一行!
(部分回答)
将 0 变为 NA 后(编辑:进行更改:data[data == 0] <- NA
),您可以:
data %>%
group_by(Year, Gender) %>%
summarise_all(na.omit)
但这只适用于每年只有一个消费者的情况,这里就是这种情况,但可能不适用于所有数据。在按年份合并行之前,您应该考虑使用 Id 列或其他内容。
对于 Year
和 Gender
的每个值,您可以 select 每列中的第一个非 0 值。
library(dplyr)
res <- df %>%
group_by(Year, Gender) %>%
summarise(across(.fns = ~.[. != 0][1])) %>%
ungroup()
res
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
#1 2018 Male Max NA NA
#2 2019 Male Peter Peter Peter
如果您想删除包含任何 NA
行的行,您可以将答案扩展为
res %>% filter(if_all(BMW:Mercedes, Negate(is.na)))
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
#1 2019 Male Peter Peter Peter
数据
df <- structure(list(Year = c(2018L, 2019L, 2019L, 2019L), Gender = c("Male",
"Male", "Male", "Male"), BMW = c("Max", "Peter", "0", "0"), VW = c("0",
"0", "Peter", "0"), Mercedes = c("0", "0", "0", "Peter")),
class = "data.frame", row.names = c(NA, -4L))
由于您希望数据按性别和年份“分组”,我建议对这些变量进行整形,过滤掉您不想要的内容,然后再整形回宽。
library(dplyr)
library(tidyr) # pivot_*
dat %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0") %>%
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# # A tibble: 2 x 5
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
# 1 2018 Male Max <NA> <NA>
# 2 2019 Male Peter Peter Peter
如果存在重复 year/gender/names,就会出现问题。例如,
bind_rows(dat, dat[3,])
# Year Gender BMW VW Mercedes
# 1 2018 Male Max 0 0
# 2 2019 Male Peter 0 0
# 3 2019 Male 0 Peter 0
# 4 2019 Male 0 0 Peter
# 5 2019 Male 0 Peter 0
bind_rows(dat, dat[3,]) %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0") %>%
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# Warning: Values are not uniquely identified; output will contain list-cols.
# * Use `values_fn = list` to suppress this warning.
# * Use `values_fn = length` to identify where the duplicates arise
# * Use `values_fn = {summary_fun}` to summarise duplicates
# # A tibble: 2 x 5
# Year Gender BMW VW Mercedes
# <int> <chr> <list> <list> <list>
# 1 2018 Male <chr [1]> <NULL> <NULL>
# 2 2019 Male <chr [1]> <chr [2]> <chr [1]>
在这种情况下,如果您想删除完全重复的内容,那么您可以这样做:
bind_rows(dat, dat[3,]) %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0", !duplicated(.)) %>% # updated
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# # A tibble: 2 x 5
# Year Gender BMW VW Mercedes
# <int> <chr> <chr> <chr> <chr>
# 1 2018 Male Max <NA> <NA>
# 2 2019 Male Peter Peter Peter
尽管确实“丢失”了彼得两次列出大众汽车的事实……这可能是两个不同的大众汽车。如果您 want/need 保留此信息,则一个 hackish 修复是
bind_rows(dat, dat[3,]) %>%
pivot_longer(-c(Year, Gender), values_to = "value") %>%
filter(value != "0") %>%
group_by(Year, Gender, name, value) %>%
mutate(name = paste0(name, replace(seq_along(name), 1, ""))) %>%
ungroup() %>%
pivot_wider(c(Year, Gender), names_from = name, values_from = value)
# # A tibble: 2 x 6
# Year Gender BMW VW Mercedes VW2
# <int> <chr> <chr> <chr> <chr> <chr>
# 1 2018 Male Max <NA> <NA> <NA>
# 2 2019 Male Peter Peter Peter Peter
(或在不影响其他汽车的情况下明确传达“第二大众”的类似方式)。
数据
dat <- structure(list(Year = c(2018L, 2019L, 2019L, 2019L), Gender = c("Male", "Male", "Male", "Male"), BMW = c("Max", "Peter", "0", "0"), VW = c("0", "0", "Peter", "0"), Mercedes = c("0", "0", "0", "Peter")), class = "data.frame", row.names = c(NA, -4L))