多级数据框

时间:2016-08-22 19:00:44

标签: r variables dataframe

我正在研究如何在R中存储不同变量类型的多个实例。我试图使用数据帧(和列表),但无法让它做我想要的。让我试着向你展示一下我想要实现的目标。

假设我创建了一种包含数字和字符串的数据类型(一个篮子),如:

iNbLine = 2
df<-data.frame(Weight=double(iNbLine), Color=character(iNbLine),stringsAsFactors=F)
row.names(df)<-c("apples","pears")
df
       Weight Color
apples      0      
pears       0    

我现在可以根据需要更新我的数据结构。例如:

df$Weight[1]=158
df$Color[1]="green"
df
       Weight Color
apples    158 green
pears       0    

我想要做的是拥有更高级别的数据,而不是包含其中一些带有额外数据的篮子(这里是价格),所以我尝试了这个:

iNbBasket =5
df2<-data.frame(Price=double(iNbBasket), Basket=rep(df,iNbBasket))

但是这给了我

Error in data.frame(Price = double(iNbBasket), Basket = rep(df, iNbBasket)) : arguments imply differing number of rows: 5, 2

我希望能够做的是获取我的第二个篮子的苹果的重量;同时保留设定第二篮子价格的可能性。我希望这很清楚。在C语言中,我认为我能够使用“struct”定义一个新的数据类型(篮子),然后我可以将其包含在另一种数据类型中,但我无法在这里想到如何做到这一点。

对于@joran,这是一个尝试展示我想要的东西:

                       Baskets      
Name    Price   Names   Weight  Color
Basket1 250     apples  158     green
                pears   32      yellow
Basket2 120     apples  70      green
                pears   10      yellow

但能够通过以下方式访问第3行:

myBasket<-myData[2]
myBasket$Weight[1]
70

并且做:

myBasket$Price = 130

更新1 我查看了列表,S3变量类型和dplyr。我不得不承认我并不了解所有事情,但到目前为止我并没有完全符合我的要求。我目前正在做以下事情

iNbLine = 2
df<-data.frame(Weight=double(iNbLine), Color=c("green","yellow"),stringsAsFactors=F)
row.names(df)<-c("apples","pears")

iNbBasket=3
dfBaskets<-data.frame(Price=double(iNbBasket))
row.names(dfBaskets)=c("Basket1","Basket2","Basket3")

lBasketsContent<-list()
for(i in 1:iNbBasket){
    lBasketsContent[[i]]=df
}

这样我可以访问价格:

iBasket =2
dfBaskets$Price[2] = 150

和给定篮子的任何元素:

lBasketsContent[[2]]$Weight[1] = 300

以及篮子本身(我将它传递给我的实际情况中的函数)

dfBasket<-lBasketsContent[[2]]

易于阅读,但需要2个容器。

3 个答案:

答案 0 :(得分:1)

哈德利的tidyrpurrr)提供了类似的东西。请查看"tidyr 0.4.0",了解嵌套在data.frame单元格中的复杂结构。

他们的示例通常依赖于在填充其他单元格之前在其他单元格中包含相关信息,甚至根据某种形式的分组填充它们。例如,使用mtcars

library(dplyr)
library(tidyr)
library(purrr)

mtcars %>%
  transmute(model = rownames(mtcars), mpg, cyl, disp, gear) %>%
  group_by(cyl)
# Source: local data frame [32 x 5]
# Groups: cyl [3]
#                model   mpg   cyl  disp  gear
#                <chr> <dbl> <dbl> <dbl> <dbl>
# 1          Mazda RX4  21.0     6 160.0     4
# 2      Mazda RX4 Wag  21.0     6 160.0     4
# 3         Datsun 710  22.8     4 108.0     4
# 4     Hornet 4 Drive  21.4     6 258.0     3
# 5  Hornet Sportabout  18.7     8 360.0     3
# 6            Valiant  18.1     6 225.0     3
# 7         Duster 360  14.3     8 360.0     3
# 8          Merc 240D  24.4     4 146.7     4
# 9           Merc 230  22.8     4 140.8     4
# 10          Merc 280  19.2     6 167.6     4
# # ... with 22 more rows

如果我们在分组上调用nest(),您可以看到事情是如何被压缩的:

quux1 <- mtcars %>%
  transmute(model = rownames(mtcars), mpg, cyl, disp, gear) %>%
  group_by(cyl) %>%
  nest()
quux1
# # A tibble: 3 x 2
#     cyl              data
#   <dbl>            <list>
# 1     6  <tibble [7 x 4]>
# 2     4 <tibble [11 x 4]>
# 3     8 <tibble [14 x 4]>
quux1$data[[1]]
# # A tibble: 7 x 4
#            model   mpg  disp  gear
#            <chr> <dbl> <dbl> <dbl>
# 1      Mazda RX4  21.0 160.0     4
# 2  Mazda RX4 Wag  21.0 160.0     4
# 3 Hornet 4 Drive  21.4 258.0     3
# 4        Valiant  18.1 225.0     3
# 5       Merc 280  19.2 167.6     4
# 6      Merc 280C  17.8 167.6     4
# 7   Ferrari Dino  19.7 145.0     5

您可以对此进行一些处理,dplyr - 样式:

quux2 <- mtcars %>%
  transmute(model = rownames(mtcars), mpg, cyl, disp, gear) %>%
  group_by(cyl) %>%
  nest() %>%
  mutate(mpg2 = purrr::map(data, ~ lm(mpg ~ disp + gear, data = .)))
quux2
# # A tibble: 3 x 3
#     cyl              data     mpg2
#   <dbl>            <list>   <list>
# 1     6  <tibble [7 x 4]> <S3: lm>
# 2     4 <tibble [11 x 4]> <S3: lm>
# 3     8 <tibble [14 x 4]> <S3: lm>

单独处理模型:

summary(quux2$mpg2[[2]])
# Call:
# lm(formula = mpg ~ disp + gear, data = .)
# Residuals:
#     Min      1Q  Median      3Q     Max 
# -3.2691 -1.7130  0.0708  1.7617  3.4351 
# Coefficients:
#             Estimate Std. Error t value Pr(>|t|)   
# (Intercept) 30.77234    7.33123   4.197  0.00301 **
# disp        -0.13189    0.03094  -4.263  0.00275 **
# gear         2.38529    1.54132   1.548  0.16032   
# ---
# Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Residual standard error: 2.623 on 8 degrees of freedom
# Multiple R-squared:  0.7294,  Adjusted R-squared:  0.6618 
# F-statistic: 10.78 on 2 and 8 DF,  p-value: 0.005361

当然,更加强大的使用会以编程方式处理模型,但这只是一个开始。

注意:我并不是说mpg ~ disp + gear是合理的模式: - )

更新1

这个怎么样:

以&#34开头;默认&#34;篮子内容,混合列表/ data.frame:

df <- list(Price = 0,
           Contents = data.frame(Names = c("apples", "pears"),
                                 Weight = rep(0, 2L),
                                 Color = c("green","yellow"),
                                 stringsAsFactors = F)
           )

创建三个篮子列表(三个客户?):

nBaskets <- 3L
# start with 3 empty baskets
lBaskets <- replicate(nBaskets, df, simplify = FALSE)
str(lBaskets)
# List of 3
#  $ :List of 2
#   ..$ Price   : num 0
#   ..$ Contents:'data.frame':  2 obs. of  3 variables:
#   .. ..$ Names : chr [1:2] "apples" "pears"
#   .. ..$ Weight: num [1:2] 0 0
#   .. ..$ Color : chr [1:2] "green" "yellow"
#  $ :List of 2
#   ..$ Price   : num 0
#   ..$ Contents:'data.frame':  2 obs. of  3 variables:
#   .. ..$ Names : chr [1:2] "apples" "pears"
#   .. ..$ Weight: num [1:2] 0 0
#   .. ..$ Color : chr [1:2] "green" "yellow"
#  $ :List of 2
#   ..$ Price   : num 0
#   ..$ Contents:'data.frame':  2 obs. of  3 variables:
#   .. ..$ Names : chr [1:2] "apples" "pears"
#   .. ..$ Weight: num [1:2] 0 0
#   .. ..$ Color : chr [1:2] "green" "yellow"

现在,客户2想要买东西:

cust <- 2
lBaskets[[ cust ]]$Contents$Weight[1] <- 300
lBaskets[[ cust ]]$Price <- 150
lBaskets[[ cust ]]
# $Price
# [1] 150
# $Contents
#    Names Weight  Color
# 1 apples    300  green
# 2  pears      0 yellow

没有进入S4对象(可能是为了你想做的事情而过度设计),我认为这是最直接的方式。如果您希望/需要快速参考特定客户Contents并将其重新分配回列表,那肯定是可行但不是必需的。

答案 1 :(得分:1)

使用lists。列表是能够包含其他对象的通用向量

例如使用data.table

> library(data.table)
> baskets = data.table( 
    'name'=c('basket1','basket2'),
    'price'=c(250,120),
    'names'=list( list('apples','pears') , list('apples','pears') ),
    'weight'=list( list(158,32) , list(70,10) ),
    'color'=list( list('green','yellow') , list('green','yellow'))
)

> baskets
      name price  names weight  color
1: basket1   250 <list> <list> <list>
2: basket2   120 <list> <list> <list>
> 

抓住第一行信息

> baskets[1][['price']]
[1] 250
> baskets[1][['names']][[1]][[2]]
[1] "pears"
> baskets[1][['weight']][[1]][[2]]
[1] 32

答案 2 :(得分:0)

我们需要将第一个data.frame转换为矩阵并使用byrow=TRUE

iNbLine = 2
DF<-data.frame(Weight=double(iNbLine), Color=character(iNbLine),stringsAsFactors=F)
row.names(DF)<-c("apples","pears")
DF

DF$Weight[1]=158
DF$Color[1]="green"
DF$Weight[2]=200
DF$Color[2]="red"


iNbBasket =5
DF_MultiLevel<-data.frame(Price=double(iNbBasket), Basket= matrix(rep(DF,iNbBasket),nrow=iNbBasket,byrow=TRUE) )

#> DF_MultiLevel
#  Price Basket.1   Basket.2
#1     0 158, 200 green, red
#2     0 158, 200 green, red
#3     0 158, 200 green, red
#4     0 158, 200 green, red
#5     0 158, 200 green, red