gpt4 book ai didi

r - dplyr::filter嵌套数据框

转载 作者:行者123 更新时间:2023-12-04 10:30:19 25 4
gpt4 key购买 nike

题:

如何使用dplyr:filter基于嵌套数据框过滤行



问题:
以下代码提供了一个示例数据集,以启用一个有效的示例。

使用示例代码,我可以使用which进行子集设置,但是由于嵌套了数据帧,因此在使用dplyr时遇到了问题。

现在,我很欣赏可以使用jsonlite展平数据框,但是我很想知道是否以及如何在不展平数据框的情况下利用dplyr。

感谢所有的帮助,并表示赞赏。

requiredPackages <- c("devtools","dplyr","tidyr","data.table","ggplot2","ggvis","RMySQL", "jsonlite", "psych", "plyr", "knitr")

ipak <- function(pkg)
{
new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
if (length(new.pkg))
install.packages(new.pkg, dependencies = TRUE)
sapply(pkg, require, character.only = TRUE)
}

ipak(requiredPackages)

dataDir <- "./data"
fileUrl <- "https://d396qusza40orc.cloudfront.net/dsscapstone/dataset/yelp_dataset_challenge_academic_dataset.zip"
filePath <- file.path(dataDir)

# Does the directory Exist? If it does'nt create it
if (!file.exists(dataDir)) {
dir.create(dataDir)
}

# Now we check if we have downloaded the data already into
# "./data/yelp_dataset_challenge_academic_dataset". If not, then we download the
# zip file... and extract it under the data directory as
# './data/yelp_dataset_challenge_academic_dataset'...

if (!file.exists( file.path(dataDir,"yelp_dataset_challenge_academic_dataset"))) {
temp <- tempfile()
download.file(fileUrl, temp, mode = "wb", method = "curl")
unzip(temp, exdir = dataDir)
unlink(temp)
}

if ( !exists("yelpBusinessData") )
{
if (file.exists( file.path(dataDir,"yelpBusinessData.rds"))) {
yelpBusinessData <- readRDS(file.path(dataDir,"yelpBusinessData.rds"))
} else {
yelpBusinessDataFilePath <- file.path(dataDir,
"yelp_dataset_challenge_academic_dataset/yelp_academic_dataset_business.json")
yelpBusinessData <- fromJSON(sprintf("[%s]",
paste(readLines(yelpBusinessDataFilePath),
collapse = ",")),
flatten = FALSE)
str(yelpBusinessData, max_level = 1)
# Fix the column name duplication issue
# If and when you flatten the data the you create two columns wiht the same column id
#
# i.e. yelpBusinessData$attributes.Good.for.kids
#
# This fixes the issue by renaming the first column...
#
colnames(yelpBusinessData$attributes)[6] <- "Price_Range"
colnames(yelpBusinessData$attributes)[7] <- "Good_For_Kids"
saveRDS( yelpBusinessData, file.path(dataDir, "yelpBusinessData.rds"))
}
}




上面的代码加载示例数据帧。

这是我上面提到的问题的一个示例。第一个代码示例有效并利用 which选择四个记录。问题是如何使用dplyr :: filter进行相同操作-我缺少什么?具体来说,如何解除对嵌套数据框的引用?

# Extract the Phoenix subset using `which`
yelpBusinessData.PA <- yelpBusinessData[which(yelpBusinessData$city == "Phoenix"),]
yelpBusinessData.PA.rest <- yelpBusinessData.PA[which(grepl("Restaurants",
yelpBusinessData.PA$categories)),]
Exp <- yelpBusinessData.PA.rest[which(yelpBusinessData.PA.rest$attributes$Price_Range == 4),]
dim(Exp)




结果-选择了四个记录:-)

> dim(Exp)
[1] 4 15


问题:如何使用dplyr?

yelpBusinessData.PA.rest <- yelpBusinessData %>% 
filter(city == "Phoenix") %>%
filter(grepl("Restaurants", categories)) %>%
filter(attributes$Price_Range == 4)


上面的代码失败...现在,如果我将文件展平,我可以使其正常工作,但是...

请注意从“ attributes $ Price_Range”到“ attributes.Price_Range”的细微变化。

yelpBusinessData2 <- flatten(yelpBusinessData, recursive = TRUE)
dim(yelpBusinessData2)

Exp2 <- yelpBusinessData2 %>%
filter(city == "Phoenix") %>%
filter(grepl("Restaurants", categories)) %>%
filter(attributes.Price_Range == 4)
dim(Exp2)


但是,我的目标是了解如何在不展平嵌套数据帧的情况下执行此操作。

即-> **如何将dplyr与嵌套数据帧一起使用? **

我在这里想念什么? :-)

我尝试过的一个可能的答案是使用[[]]索引嵌套的数据帧,这确实有效,但是却失去了dplyr的优雅。

有没有更好的办法?

Exp2 <- yelpBusinessData %>% 
filter(city == "Phoenix") %>%
filter(grepl("Restaurants", categories)) %>%
filter( attributes[[6]][] == 4)


当使用嵌套数据帧时,以上索引为“ attributes $ Price_range”并返回了正确的结果。即Price_Range是属性数据框的第六个数据框...

> sessionInfo()
R version 3.2.2 (2015-08-14)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.11.2 (El Capitan)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats graphics grDevices utils datasets methods base

other attached packages:
[1] knitcitations_1.0.6 pander_0.5.2 plyr_1.8.3 jsonlite_0.9.16 ggvis_0.4.2.9000
[6] tidyr_0.2.0 devtools_1.8.0 qmap_1.0-3 fitdistrplus_1.0-4 knitr_1.11
[11] dplyr_0.4.3.9000 data.table_1.9.4 psych_1.5.6 mapproj_1.2-4 maptools_0.8-36
[16] rworldmap_1.3-1 sp_1.1-1 maps_2.3-11 ggmap_2.5.2 ggplot2_1.0.1
[21] RMySQL_0.10.5 DBI_0.3.1 setwidth_1.0-4 colorout_1.1-1 vimcom_1.2-3

loaded via a namespace (and not attached):
[1] httr_1.0.0 splines_3.2.2 shiny_0.12.2 assertthat_0.1 highr_0.5
[6] yaml_2.1.13 lattice_0.20-33 chron_2.3-47 digest_0.6.8 RefManageR_0.8.63
[11] colorspace_1.2-6 htmltools_0.2.6 httpuv_1.3.3 XML_3.98-1.3 bibtex_0.4.0
[16] xtable_1.7-4 scales_0.3.0 jpeg_0.1-8 git2r_0.11.0 lazyeval_0.1.10.9000
[21] mnormt_1.5-3 proto_0.3-10 survival_2.38-3 RJSONIO_1.3-0 magrittr_1.5
[26] mime_0.3 memoise_0.2.1 evaluate_0.7.2 MASS_7.3-43 xml2_0.1.1
[31] foreign_0.8-66 ggthemes_2.2.1 rsconnect_0.4.1.4 tools_3.2.2 geosphere_1.4-3
[36] RgoogleMaps_1.2.0.7 formatR_1.2 stringr_1.0.0 munsell_0.4.2 rversions_1.0.2
[41] grid_3.2.2 RCurl_1.95-4.7 rstudioapi_0.3.1 rjson_0.2.15 spam_1.0-1
[46] bitops_1.0-6 labeling_0.3 rmarkdown_0.7 gtable_0.1.2 curl_0.9.3
[51] reshape2_1.4.1 R6_2.1.1 lubridate_1.3.3 stringi_0.5-5 parallel_3.2.2
[56] Rcpp_0.12.0 fields_8.2-1 png_0.1-7

最佳答案

这个问题至少有3个不同的部分,每个部分都很可能在SO的其他地方得到了很好的回答。

这些是:


如何在R / dplyr中使用“混乱”的data.frame?

您在此处提供的示例比“嵌套” data.frame更为混乱,因为它包含列表列以及包含data-frame-columns的data-frame-columns。
如何在R / dplyr中清理“混乱”的data.frame?
是否有更好的方法来处理这些数据,并保持其层次结构?


使用R / dplyr中的“混乱”数据帧?

通常,特别是刚开始时,我会采用迭代方式清理数据的方法。这意味着我首先要确定最需要使用的列,最有问题的列,并仅清除交叉点处的列。

特别:


筛选出有问题但不重要的任何列
将我的精力集中在任何有问题且重要的专栏上
保留任何重要且无问题的列


撇开:这留下了第四列,它们都不重要也不成问题。您如何处理这些取决于问题。例如,如果我正在准备生产数据库,则将它们排除在外,而仅包括“清除”列(上面的#2和#3)。如果我要进行探索性分析,我将把它们包括在内,因为我可能会改变他们对重要性的看法。

在本示例中,有问题的列是包含data.frames的列。 (这是有问题的,因为它们破坏了与dplyr的兼容性-并不是因为它们很乱)。

您可以使用dplyr::select_if过滤掉它们:

yelpBusinessData %>%
dplyr::select_if(purrr::negate(is.data.frame)) %>%
dplyr::filter(city == 'Phoenix')


之后,您的示例中的其他 dplyr运算符将起作用,只要它们不引用data.frames列中的数据(例如, attribute)。这使我进入第二部分。

如何在R / dplyr中清除“混乱”的data.frame?

处理此数据中“混乱”数据帧列的一种方法是每个 flatten并将其联接回原始数据帧。

attributes列为例,我们可以在此子数据帧上使用 jsonlite::flatten,然后将其重新加入到原始图像中:

yelpBusinessData %>%
dplyr::select_if(purrr::negate(is.data.frame)) %>%
dplyr::bind_cols(jsonlite::flatten(yelpBusinessData$attributes, recursive = T)) %>%
dplyr::filter(city == 'Phoenix') %>%
dplyr::filter(grepl("Restaurants", categories)) %>%
dplyr::filter(Price_Range == 4)


但是, hours组件可能需要不同的处理方式。在此示例中, hours data.frame包含一周中每一天的data.frame,具有两个字段(“打开”和“关闭”)。在这里,我使用 purrr:map将函数应用于每一列,从而将data.frame简化为字符向量。

hours <- 
yelpBusinessData$hours %>%
purrr::map(. %>%
dplyr::transmute(hours = stringr::str_c(open, close, sep = ' - ')) %>%
unlist()) %>%
tibble::as_tibble()


这将产生一个 data.frame,其中包含一周中每一天的开始-停止时间:

> str(hours)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 61184 obs. of 7 variables:
$ Tuesday : chr "08:00 - 17:00" NA NA "10:00 - 21:00" ...
$ Friday : chr "08:00 - 17:00" NA NA "10:00 - 21:00" ...
$ Monday : chr "08:00 - 17:00" NA NA "10:00 - 21:00" ...
$ Wednesday: chr "08:00 - 17:00" NA NA "10:00 - 21:00" ...
$ Thursday : chr "08:00 - 17:00" NA NA "10:00 - 21:00" ...
$ Sunday : chr NA NA NA "11:00 - 18:00" ...
$ Saturday : chr NA NA NA "10:00 - 21:00" ...


类似地,可以使用 map2_dfc(在映射后自动调用 bind_cols)自己折叠此对象的数据帧:

hours <- yelpBusinessData$hours %>% 
purrr::map2_dfc(.x = .,
.y = names(.),
.f = ~ .x %>%
dplyr::rename_all(funs(stringr::str_c(.y, ., sep = '_'))))


这将产生一个具有特定于一天的开始和结束时间的 data.frame

> str(hours)
'data.frame': 61184 obs. of 14 variables:
$ Tuesday_close : chr "17:00" NA NA "21:00" ...
$ Tuesday_open : chr "08:00" NA NA "10:00" ...
$ Friday_close : chr "17:00" NA NA "21:00" ...
$ Friday_open : chr "08:00" NA NA "10:00" ...
$ Monday_close : chr "17:00" NA NA "21:00" ...
$ Monday_open : chr "08:00" NA NA "10:00" ...
$ Wednesday_close: chr "17:00" NA NA "21:00" ...
$ Wednesday_open : chr "08:00" NA NA "10:00" ...
$ Thursday_close : chr "17:00" NA NA "21:00" ...
$ Thursday_open : chr "08:00" NA NA "10:00" ...
$ Sunday_close : chr NA NA NA "18:00" ...
$ Sunday_open : chr NA NA NA "11:00" ...
$ Saturday_close : chr NA NA NA "21:00" ...
$ Saturday_open : chr NA NA NA "10:00" ...


但是,您可能希望将某些数据“去规范化”,以产生更整洁的结构,而不是在字段名称中放入重要信息:

> purrr::flatten_dfr(yelpBusinessData$hours, .id = 'day')
# A tibble: 61,184 x 3
day close open
<chr> <chr> <chr>
1 1 NA NA
2 1 NA NA
3 1 NA NA
4 1 21:00 10:00
5 1 16:00 10:00
6 1 NA NA
7 1 NA NA
8 1 NA NA
9 1 NA NA
10 1 02:00 08:00
# ... with 61,174 more rows


是否有更好的方法来过滤这些数据,并保持其原始层次结构?

归根结底,原始数据结构中存在一个基本问题。 R中的 data.frame实现为列表列表,但是您的数据存储为data.frames的data.frame。当索引到结构的各个部分时,这会导致混乱。

这有点不合常规,但是一种选择是将数据保留为列表列表,而不是立即转换为data.frame。使用 purrr包中的工具,您可以轻松地使用列表来过滤/展平数据,然后从过滤后的结果构造一个data.frame。

例如:

> ## read in yelpBusinessData without converting to data.frame
> yelpBusinessData2 <- fromJSON(sprintf("[%s]",
paste(readLines(yelpBusinessDataFilePath),
collapse = ",")),
flatten = FALSE,
simplify = FALSE)

# filter to Phoenix cities _before_ converting to a data.frame
> yelpBusinessData2 %>%
purrr::keep(~ .$'city' == 'Phoenix'
&& grepl("Restaurants", .$categories)) %>%
jsonlite:::simplify(., flatten = T) %>%
dplyr::select(business_id, full_address, contains('kids')) %>%
str()
'data.frame': 8410 obs. of 5 variables:
$ business_id : chr "vcNAWiLM4dR7D2nwwJ7nCA" "x5Mv61CnZLohZWxfCVCPTQ" "2ZnCITVa0abGce4gZ6RhIw" "EmzaQR5hQlF0WIl24NxAZA" ...
$ full_address : chr "4840 E Indian School Rd\nSte 101\nPhoenix, AZ 85018" "2819 N Central Ave\nPhoenix, AZ 85004" "1850 N Central Ave\nPhoenix, AZ 85004" "132 E Washington St\nPhoenix, AZ 85004" ...
$ attributes.Good for Kids : logi NA FALSE TRUE FALSE NA NA ...
$ attributes.Good For Kids : logi NA NA NA NA NA NA ...
$ attributes.Hair Types Specialized In.kids: logi NA NA NA NA NA NA ...


最后,我想说的是,如果您仍然遇到变量命名问题,请看一下R中的 janitor包,特别是 clean_names()函数。该程序包具有处理混乱数据的一些不错的功能,尤其是从Excel读取时。

关于r - dplyr::filter嵌套数据框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33715225/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com