将数据帧列表合并为单个数据帧,或完全避免它

时间:2014-10-03 13:38:56

标签: r

我有一个像:

这样的数据集
Company,Product,Users
MSFT,Office,1000
MSFT,VS,4000
GOOG,gmail,3203
GOOG,appengine,45454
MSFT,Windows,1500
APPL,iOS,6000
APPL,iCloud,3442

我正在编写一个函数来为每个公司的第n个产品返回一个数据框,用#34;用户"所以rankcompany(1)的输出应该是:

     Company   Prodcut Users
APPL    APPL       iOS  6000
GOOG    GOOG appengine 45454
MSFT    MSFT        VS  4000

该功能如下:

rankcompany <- function(num=1){

    #Read data file
    company_data <- read.csv("company.csv",stringsAsFactors = FALSE)

    #split by company
    split_data <- split(company_data, company_data$Company)

    #sort and select the nth row
    selected <- lapply(split_data, function(df) {
                                                df <- df[order(-df$Users, df$Product),]
                                                df[num,]
                                                 })

    #compose output data frame
    #this part needs to be smarter??
    len <- length(selected)
    selected_df <- data.frame(Company=character(len),Prodcut=character(len), Users=integer(len),stringsAsFactors = FALSE)
    row.names(selected_df) <- names(selected)


    for (n in names(selected)){
        print(str(selected[[n]]))
        selected_df[n,] <- selected[[n]][1,]

    }

    selected_df
}

我将输入数据框拆分为一个列表,然后执行排序和选择,然后尝试将结果合并到输出数据框中&#34; selected_df&#34;

我是R的新手,我可以更聪明地完成合并。或者我应该首先避免分裂?有什么建议吗?

由于

4 个答案:

答案 0 :(得分:5)

您可以使用dplyr

以更简单的方式完成此操作
rankcompany <- function(d, num=1) {
   d %>% group_by(Company) %>% arrange(desc(Users)) %>% slice(num)
}

然后你可以这样做:

rankcompany(d,2)

或:

d %>% rankcompany(1)

答案 1 :(得分:4)

根据@DMT的评论 我用以下代码替换了合并代码:

    selected_df <- rbindlist(selected)
    selected_df <- as.data.frame(selected_df)
    row.names(selected_df) <- names(selected)
    selected_df

它运作正常。

答案 2 :(得分:2)

如果您喜欢splitlapply的清晰度,则可以使用功能更短的版本。

rankcompany <- function(N){
    byCompany <- split(df, sorted$Company)
    ranks <- lapply(byCompany,
             function(x)
             {
               r <- which(rank(-x$Users)==N)
               x[r,]
             })
    do.call("rbind", ranks)
}

rankcompany(1)

> rankcompany(1)
     Company   Product Users
APPL    MSFT        VS  4000
GOOG    GOOG appengine 45454
MSFT    APPL       iOS  6000

答案 3 :(得分:2)

如果您使用的是rbindlist,则可能需要在执行此操作之前转换为data.frame

library(data.table) ## 1.9.2+
n <- 1L
setDT(company_data)[order(-Users), .SD[n], keyby=Company]
#   Company   Product Users
#1:    APPL       iOS  6000
#2:    GOOG appengine 45454
#3:    MSFT        VS  4000

setDT通过引用将<{1}}转换为data.frame (无任何额外的副本/内存使用情况)。然后我们按data.table列的降序对data.table进行排序,然后按 Users group进行排序,对于每个组,我们获取company行来自 D ata(n)的 S ubset。

在你的情况下,或许,

.SD

但是之前的解决方案是一个更有效,更容易解决问题的单线程。

数据

DT <- rbindlist(selected)
DT[order(-Users), .SD[n], keyby=Company]