【问题标题】:R - most efficient way to get specific row from nested dataframe inside a dataframeR - 从数据框中的嵌套数据框中获取特定行的最有效方法
【发布时间】:2021-01-18 23:22:11
【问题描述】:

我正在处理来自FoodData Central API 的 API 数据。返回的 JSON 包括每个匹配食物的行,以及包含相同食物的特定营养信息 (foodNutrients) 的嵌套数据框。请注意,foodNutrients 数据框并非始终可用,并且它返回的列数各不相同。

我正在尝试从 foodNutrients df 的 1 个特定行(其中 nutrientId==1008)中提取 2 个特定列(值、unitName),前提是父 df 的给定行可用。

我正在寻找最有效的方法来完成这个丑陋、丑陋的代码正在做的事情:

##############################################################################
# ugly hacky version
library(jsonlite)
library(dplyr)

# search FoodData Central API and get JSON
api_key = "DEMO_KEY"
search_keyword = "banana cream pie"
endpoint_url <- paste("https://api.nal.usda.gov/fdc/v1/foods/search?api_key=",api_key,"&query=",gsub(" ","%20",search_keyword),"&requireAllWords=true",sep="")
json <- fromJSON(endpoint_url)

# here is our dataframe which contains a list containing another dataframe (foodNutrients)
df1 <- json$foods %>%
  select(fdcId, description, brandOwner, ingredients, foodNutrients)

# here is some hacky code to show what I am trying to do
# yes, this is probably the stupidest way I could code this
# may God have mercy on my soul

# help me Obi Wan, you're my only hope

# hold output here
output <- data.frame() 

# yes, I am using a loop, which is dumb
for(i in 1:nrow(df1)) {
  
  # grab the nested dataframe and add our index
  nested_df <- df1[i,"foodNutrients"][[1]]

  # hack
  chk <- data.frame() 
  
  # if nested_df exists and has all needed columns...
  if(nrow(nested_df)>0 & 
     "value" %in% colnames(nested_df) & 
     "unitName" %in% colnames(nested_df) & 
     "nutrientId" %in% colnames(nested_df)) {chk <- nested_df %>% filter(nutrientId==1008)}
  
  # pull out energy if available
  if(nrow(chk)==1) {
    energy_value <- chk[1,"value"]
    energy_unit <- chk[1,"unitName"]    
  } else {
    energy_value <- 0
    energy_unit <- NA    
  }
  
  # add a row to a new dataframe with everything I want
  row <- data.frame(fdcId=df1[i,"fdcId"],
                    description=df1[i,"description"],
                    brandOwner=df1[i,"brandOwner"],
                    ingredients=df1[i,"ingredients"],
                    energy_value,
                    energy_unit)
  output <- rbind(output, row)  
}

# hello there!
print(head(output))

我一直在玩各种 map() 函数,但还没有找到合适的组合来完成我在这里尝试做的事情。如何在没有循环和一堆 hack 的情况下获得相同的结果?

【问题讨论】:

    标签: r dataframe dplyr purrr data-wrangling


    【解决方案1】:

    我不确定这是否正是您要寻找的,但我想...

    注意你的想法......他们背叛了你......(欧比万说)

    ...所以我尝试了foodNutrients 列的mapunnest

    library(tidyverse)
    
    df1 %>%
      mutate(foodNutrients = map(foodNutrients, as_tibble)) %>%
      unnest(cols = foodNutrients) %>%
      filter(nutrientId == 1008) %>%
      select(value, unitName)
    

    而且,如果您想在没有可用能量时添加零,您可以添加:

    right_join(df1, by = "fdcId") %>%
    mutate(value = replace_na(value, 0)) %>%
    

    select之前。

    这能满足您的需要吗?

    输出

    # A tibble: 43 x 2
       value unitName
       <dbl> <chr>   
     1   292 KCAL    
     2   422 KCAL    
     3   300 KCAL    
     4   247 KCAL    
     5   231 KCAL    
     6   254 KCAL    
     7   269 KCAL    
     8   237 KCAL    
     9   269 KCAL    
    10   251 KCAL    
    # … with 33 more rows
    

    【讨论】:

      猜你喜欢
      • 2023-03-20
      • 1970-01-01
      • 2020-07-14
      • 2016-05-08
      • 2016-05-16
      • 2023-03-21
      • 2014-07-21
      • 2020-07-30
      • 1970-01-01
      相关资源
      最近更新 更多