如何根据特定列自动对 Dataframe 进行子集化并存储在R中的单独dfs中

ruoxqz4g  于 2023-03-10  发布在  其他
关注(0)|答案(4)|浏览(148)

我正在R中使用一个数据集。这个数据集包含一些值列和一些城市列,每个城市都是虚拟变量(0和1)。数据集如下所示:

df<-data.frame(A=c(1,2,2,3,4,5,1,1,2,3,4,4),
            B=c(4,4,2,3,4,2,1,5,2,2,5,1) ,
            C=c(rep(0:1, each=3, times=2)),
            D=round(rnorm(12, mean=50, sd=10), 2) ,
            City1=c(rep(0:1, each=6)),
            City2=c(rep(c(1, 0), c(6,6))))

上面的数据集是一个原型。真实的的数据集有不同数量的“城市”变量,即有时一个数据集有2个“城市”列,有时它有10个“城市”列。我想要一个解决方案,我可以根据每个“城市”的值创建单独的数据集。例如,代码基于“1”值创建数据集(非“0”值)并存储在名为“City1”的 Dataframe 中。然后,转到列“City2”并基于列“City2”中的“1”值(不是“0”值)创建数据集,并存储在名为“City2”的单独 Dataframe 中。
我知道下面的一些代码可以完成这项工作,但这样一来,我每次都必须根据“城市”变量的名称来编写代码,而且每个数据集中的城市数量也不同。

df1 <- df[df$City1==1,]
df2 <- df[df$City2==1,]

有人能帮我解决这个问题吗?先谢谢你。

dy1byipe

dy1byipe1#

识别城市列,然后循环通过它们并 * 拆分 *:

#cc <- which(grepl("^City", colnames(df)))
# when cities start on 4th column.
cc <- 4:ncol(df)
lapply(cc, function(i){ split(df[, -cc], df[ i ]) })

**编辑:**要将列表作为单独的 Dataframe 输出到环境中,我们需要命名列表项,然后使用 list2env

result <- unlist(
  lapply(cc, function(i){ split(df[, -cc], df[ i ]) }),
  recursive = FALSE)
# make unique names
names(result) <- make.names(names(result), unique = TRUE)

list2env(result, globalenv())
odopli94

odopli942#

这里有一个使用purrr::maprlang::bind_env的方法。这会在全局环境中创建df1df2,注意不要覆盖现有对象!如果你只想要一个data.frame的列表,那么就停止使用map

library(purrr)
library(rlang)

grep("City", names(df), value = TRUE) %>% 
  set_names() %>% 
  map(~ df[df[[.x]] == 1, ]) %>% 
  env_bind(.GlobalEnv, !!! .)

数据来自OP

df <- data.frame(A = c(1,2,2,3,4,5,1,1,2,3,4,4),
                 B = c(4,4,2,3,4,2,1,5,2,2,5,1),
                 C = c(rep(0:1, each=3, times=2)),
                 D = round(rnorm(12, mean=50, sd=10), 2),
                 City1 = c(rep(0:1, each=6)),
                 City2 = c(rep(c(1, 0), c(6,6)))
                 )

reprex package(v2.0.1)于2023年3月7日创建

pbpqsu0x

pbpqsu0x3#

您可以paste列,然后split

Citys <- startsWith(colnames(df), "City")
split(df, do.call("paste", df[Citys]))

或者,对于pivot_longer

library(tidyr)
library(dplyr)
df %>% 
  pivot_longer(starts_with("City"), names_to = "Cities") %>% 
  filter(value == 1) %>% 
  split(.$Cities)

如果要在全局环境中将列表转换为多个数据框,请使用list2env(your_list, .GlobalEnv)

bf1o4zei

bf1o4zei4#

您可以使用startsWith为以 City 开头的列设置df的子集,测试它们是否等于1 == 1,并获得这样的列,其中max.col . Pastedf 位于列的前面,并将其用于splitdf。使用list2env获得全局环境中的data.frames

list2env(split(df, paste0("df", max.col(df[startsWith(names(df), "City")] ==
                                        1))), globalenv())

df1
#   A B C     D City1 City2
#7  1 1 0 65.30     1     0
#8  1 5 0 45.81     1     0
#9  2 2 0 43.37     1     0
#10 3 2 1 55.14     1     0
#11 4 5 1 59.21     1     0
#12 4 1 1 50.55     1     0

df2
#  A B C     D City1 City2
#1 1 4 0 62.32     0     1
#2 2 4 0 45.78     0     1
#3 2 2 0 54.80     0     1
#4 3 3 1 44.96     0     1
#5 4 4 1 61.42     0     1
#6 5 2 1 51.26     0     1

如果要将其保存在列表中,并假设城市仅编码为0或1,您可以尝试:

split(df, max.col(df[startsWith(names(df), "City")]))

或者使用lapply和子集df

lapply(df[startsWith(names(df), "City")], \(i) df[i==1,])

基准

bench::mark(check = FALSE,
zx8754 = {cc <- which(grepl("^City", colnames(df)))  #Returns something different
  lapply(cc, function(i){ split(df[, -cc], df[ i ]) })},
TimTeaFan = {grep("City", names(df), value = TRUE) %>% 
  set_names() %>% 
  map(~ df[df[[.x]] == 1, ])},
Maël = split(df, do.call("paste", df[startsWith(colnames(df), "City")])),
GKi = split(df,  max.col(df[startsWith(names(df), "City")])),
GKi2 = lapply(df[startsWith(names(df), "City")], \(i) df[i==1,])
)
#  expression      min median itr/s…¹ mem_al…² gc/se…³ n_itr  n_gc total…⁴ result
#  <bch:expr> <bch:tm> <bch:>   <dbl> <bch:by>   <dbl> <int> <dbl> <bch:t> <list>
#1 zx8754        495µs  548µs   1621.  11.27KB    10.3   788     5   486ms <NULL>
#2 TimTeaFan     226µs  247µs   3863.       0B    12.3  1877     6   486ms <NULL>
#3 Maël          250µs  264µs   3754.       0B    12.3  1824     6   486ms <NULL>
#4 GKi           302µs  321µs   3051.     240B    12.4  1480     6   485ms <NULL>
#5 GKi2          161µs  177µs   5575.   6.36KB    14.5  2694     7   483ms <NULL>

相关问题