将二进制测量结果转换为R数据帧中的字符向量

将二进制测量结果转换为R数据帧中的字符向量,r,dataframe,character,binary-data,tidyverse,R,Dataframe,Character,Binary Data,Tidyverse,假设我将超市水果库存调查的结果存储在数据框中: stock <- data.frame( store = c("Asda", "Booths", "Co-op"), apple = c(1, 0, 0), banana = c(1, 1, 0), coconut = c(0, 0, 0) ) 我的目标: 我想将上述二元调查结果列转换为每个超市的库存汇总字符向量,如下所示: store fruits 1 Asda apple, ban

假设我将超市水果库存调查的结果存储在数据框中:

stock <- data.frame(
    store = c("Asda", "Booths", "Co-op"),
    apple = c(1, 0, 0),
    banana = c(1, 1, 0),
    coconut = c(0, 0, 0)
)
我的目标:

我想将上述二元调查结果列转换为每个超市的库存汇总字符向量,如下所示:

   store        fruits
1   Asda apple, banana
2 Booths        banana
3  Co-op              
我的解决方案:

步骤1:我使用
for
循环将二进制列中的所有1替换为相应的列名:

for(i in names(stock)[2:4]) {
    stock[which(stock[[i]] == 1), i] <- i
}
步骤2:我使用
tidyr::unite()
将各个水果列连接到一个字符向量列中:

library(tidyverse)
stock <- unite(stock, fruits, apple:coconut, sep = ", ")
步骤3:我必须使用stringr::str_replace_all()删除所有不需要的0和逗号分隔符:

library(stringr)
stock$fruits <- str_replace_all(stock$fruits, "0, |, 0|0", "")
库(stringr)

库存$FROUTS假设商店名称唯一,只有1和0,并且没有缺失值:

library(dplyr)
library(tidyr)
result <- stock %>%
  gather(fruit, binary, -store) %>%
  mutate(fruit = if_else(binary == 1, fruit, NA_character_)) %>%
  select(-binary) %>%
  filter(!is.na(fruit)) %>%
  group_by(store) %>%
  summarize(fruits = paste(fruit, collapse = ", ")) %>%
  ungroup() %>%
  right_join(stock %>% select(store)) %>%
  mutate(fruits = if_else(is.na(fruits), "", fruits))
库(dplyr)
图书馆(tidyr)
结果%
采集(水果,二进制,-存储)%>%
变异(果=if_-else(二进制==1,果,NA_字符))%>%
选择(-binary)%>%
过滤器(!is.na(水果))%>%
分组依据(门店)%>%
汇总(水果=浆糊(水果,折叠=“,”)%%
解组()%>%
右键加入(库存%>%选择(商店))%%>%
变异(水果=如果其他(is.na(水果),“”,水果))

假设存储名称唯一,只有1和0,并且没有缺失值:

library(dplyr)
library(tidyr)
result <- stock %>%
  gather(fruit, binary, -store) %>%
  mutate(fruit = if_else(binary == 1, fruit, NA_character_)) %>%
  select(-binary) %>%
  filter(!is.na(fruit)) %>%
  group_by(store) %>%
  summarize(fruits = paste(fruit, collapse = ", ")) %>%
  ungroup() %>%
  right_join(stock %>% select(store)) %>%
  mutate(fruits = if_else(is.na(fruits), "", fruits))
库(dplyr)
图书馆(tidyr)
结果%
采集(水果,二进制,-存储)%>%
变异(果=if_-else(二进制==1,果,NA_字符))%>%
选择(-binary)%>%
过滤器(!is.na(水果))%>%
分组依据(门店)%>%
汇总(水果=浆糊(水果,折叠=“,”)%%
解组()%>%
右键加入(库存%>%选择(商店))%%>%
变异(水果=如果其他(is.na(水果),“”,水果))

该任务需要将输入数据的格式从宽改为长

虽然问题被明确地标记为
tidyverse
,但我想从一个简明的
data.table
解决方案开始,该解决方案使用
melt()
,我比较熟悉:

library(data.table)
melt(setDT(stock), id.vars = "store")[
  value > 0, .(fruits = toString(variable)), keyby = store][.(stock$store)]
它将
stock
强制为class
data.table
,并将其从宽格式改为长格式。然后,在随后的聚合中只考虑至少有一个结果的行,其中结果按
store
分组
toString()
用于聚合,它是
paste()
的简明替代方法。为了包括所有的商店,甚至那些没有任何水果的商店,最终的加入权是必需的


按照OP的要求,使用
tidyr
dplyr
软件包中的函数也可以实现相同的目标:

library(magrittr)
stock %>% 
  tidyr::gather(fruits, , -store) %>% 
  dplyr::filter(value > 0) %>% 
  dplyr::group_by(store) %>% 
  dplyr::summarise(toString(fruits)) %>% 
  dplyr::right_join(stock %>% dplyr::select(store))
#一个tible:3 x 2
商店`toString(水果)`
1阿斯达苹果、香蕉
2个摊位香蕉
3合作社
这两个结果是等价的


请注意,对
tidyverse
函数的引用是明确的,以避免由于混乱的名称空间而产生名称冲突。

该任务需要将输入数据的格式从宽改为长

虽然问题被明确地标记为
tidyverse
,但我想从一个简明的
data.table
解决方案开始,该解决方案使用
melt()
,我比较熟悉:

library(data.table)
melt(setDT(stock), id.vars = "store")[
  value > 0, .(fruits = toString(variable)), keyby = store][.(stock$store)]
它将
stock
强制为class
data.table
,并将其从宽格式改为长格式。然后,在随后的聚合中只考虑至少有一个结果的行,其中结果按
store
分组
toString()
用于聚合,它是
paste()
的简明替代方法。为了包括所有的商店,甚至那些没有任何水果的商店,最终的加入权是必需的


按照OP的要求,使用
tidyr
dplyr
软件包中的函数也可以实现相同的目标:

library(magrittr)
stock %>% 
  tidyr::gather(fruits, , -store) %>% 
  dplyr::filter(value > 0) %>% 
  dplyr::group_by(store) %>% 
  dplyr::summarise(toString(fruits)) %>% 
  dplyr::right_join(stock %>% dplyr::select(store))
#一个tible:3 x 2
商店`toString(水果)`
1阿斯达苹果、香蕉
2个摊位香蕉
3合作社
这两个结果是等价的


请注意,对
tidyverse
函数的引用是明确的,以避免由于混乱的名称空间而产生名称冲突。

非常感谢您在仔细注意我的问题标签的同时,为我的问题提供了两种解决方案,并感谢您额外的编码注释,清楚地解释了问题!虽然我首选的
tidyverse
解决方案非常简洁,但我也对
data.table
替代方案的简洁性感到惊讶。@elarry老实说,我更喜欢
data.table
不仅因为它的代码简洁,而且因为更大问题的性能原因。例如,请参阅。非常感谢您为我的问题提供了两种解决方案,同时对我的问题标签给予了周到的关注,以及您额外的编码注释,清楚地解释了问题!虽然我首选的
tidyverse
解决方案非常简洁,但我也对
data.table
替代方案的简洁性感到惊讶。@elarry老实说,我更喜欢
data.table
不仅因为它的代码简洁,而且因为更大问题的性能原因。例如,请参阅。非常感谢您共享一个用于将二进制数据转换为字符向量的
paste()
替代方案-它对于像我这样不知道
toString()
函数的人特别有用。:)非常感谢您分享一个将二进制数据转换为字符向量的
paste()
替代方案-它对像我这样不知道
toString()
函数的人特别有用。:)
library(magrittr)
stock %>% 
  tidyr::gather(fruits, , -store) %>% 
  dplyr::filter(value > 0) %>% 
  dplyr::group_by(store) %>% 
  dplyr::summarise(toString(fruits)) %>% 
  dplyr::right_join(stock %>% dplyr::select(store))
# A tibble: 3 x 2
   store `toString(fruits)`
  <fctr>              <chr>
1   Asda      apple, banana
2 Booths             banana
3  Co-op               <NA>