【问题标题】:Uniting multiple rows in R data frame into one row将R数据框中的多行合并为一行
【发布时间】:2021-09-10 17:43:30
【问题描述】:

我有一个 R 数据框,里面有很多零。基本上是这样的:

Year Gender BMW VW Mercedes
2018 Male Max 0 0
2019 Male Peter 0 0
2019 Male 0 Peter 0
2019 Male 0 0 Peter

此表中的一行代表每年一位客户。每个客户可以拥有 0、1 或多辆汽车(来自不同制造商)...

现在,我想让桌子更紧凑。事实上,我想将最后三行合并为一行。由于 Peter 拥有所有三辆汽车并且他的所有汽车都是在同一年注册的,因此 Peter 看起来像这样的一个条目就足够了:

Year Gender BMW VW Mercedes
2019 Male Peter Peter Peter

最后,输出应该是这样的:

Year Gender BMW VW Mercedes
2018 Male Max 0 0
2019 Male Peter Peter Peter

我怎样才能做到这一点? 我希望每人每年一排!

【问题讨论】:

  • 请注意标签,这与rstudio IDE无关。
  • @RonakShah 不,我想保留所有用户。我只想要每个用户和每年一行。如果他们根本没有车,那也没关系。然后他们会得到一个只有零的行。我只是不希望同一个人在同一年有多行,因为这会使表格变得不必要地大。
  • @RonakShah 我明确写了我想要“一个彼得看起来像......的条目”,所以我不想删除或更改任何其他条目/人。但是,您的回答已经对我有很大帮助。我会尝试一下并回复你...
  • @RonakShah,我认为关键评论是“一个彼得看起来像这样的条目”,对我来说这意味着三个彼得行合并为一个。对我来说,这并不意味着删除Max,只是Max 行没有明确包含在该输出中。我同意在这个例子中,除了彼得之外只包括那一行会更加清晰,但我认为我按照 OP 的意图解释了它。
  • @r2evans 没错,你做对了。我确实有点懒,我现在将它添加到输出中以使其更清晰

标签: r dataframe datatable row redundancy


【解决方案1】:

(部分回答)

一旦您将 0 设为 NA(编辑:进行更改:data[data == 0] <- NA),您可以:

data %>% 
  group_by(Year, Gender) %>% 
  summarise_all(na.omit)

但这只有在您每年只有一个消费者时才有效,这里就是这种情况,但可能不是所有数据。在按年份合并行之前,您应该考虑使用 Id 列或其他内容。

【讨论】:

  • 您好,非常感谢您的努力。不幸的是,我每年有多个用户。我想保留所有用户,无论他们是否到处都是零,只有一辆车或三辆车。但是如果他们有两三辆汽车,我只想要这个用户的一排......
  • 好的,我会尝试寻找更好的解决方案。
【解决方案2】:

由于您希望将数据按性别和年份“分组”,因此我建议对这些变量进行重新整形,过滤掉您不想要的内容,然后重新整形。

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   

如果存在重复的年份/性别/姓名,则会出现问题。例如,

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   

虽然确实“失去”了彼得两次列出大众汽车的事实......这可能是两个不同的大众汽车。如果您想要/需要保留此信息,请使用 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))

【讨论】:

    【解决方案3】:

    对于YearGender 的每个值,您可以选择每列中的第一个非 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))
    

    【讨论】:

      猜你喜欢
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      • 2019-01-09
      • 2016-04-27
      相关资源
      最近更新 更多