【问题标题】:Converting C# to idiomatic R将 C# 转换为惯用的 R
【发布时间】:2013-08-05 21:30:14
【问题描述】:

最初,我使用我编写的一个简短的 C# 程序来平均一些数字。但是现在我想做更广泛的分析,所以我将我的 C# 代码转换为 R。但是,我真的不认为我在 R 中以正确的方式或利用该语言。我编写 R 的方式与编写 C# 的方式完全相同。

我有一个包含两列的 CSV。第一列标识行的类型(三个值之一:C、E 或 P),第二列有一个数字。我想平均按类型(C、E 或 P)分组的数字。

我的问题是,在 R 中这样做的惯用方式是什么?

C#代码:

        string path = "data.csv";
        string[] lines = File.ReadAllLines(path);

        int cntC = 0; int cntE = 0; int cntP = 0; //counts
        double totC = 0; double totE = 0; double totP = 0; //totals
        foreach (string line in lines)
        {
            String[] cells = line.Split(',');
            if (cells[1] == "NA") continue; //skip missing data

            if (cells[0] == "C") 
            {
                totC += Convert.ToDouble(cells[1]);
                cntC++;
            }
            else if (cells[0] == "E")
            {
                totE += Convert.ToDouble(cells[1]);
                cntE++;
            }
            else if (cells[0] == "P")
            {
                totP += Convert.ToDouble(cells[1]);
                cntP++;
            }
        }
        Console.WriteLine("C found " + cntC + " times with a total of " + totC + " and an average of " + totC / cntC);
        Console.WriteLine("E found " + cntE + " times with a total of " + totE + " and an average of " + totE / cntE);
        Console.WriteLine("P found " + cntP + " times with a total of " + totP + " and an average of " + totP / cntP);

R代码:

dat = read.csv("data.csv", header = TRUE)

cntC = 0; cntE = 0; cntP = 0  # counts
totC = 0; totE = 0; totP = 0  # totals
for(i in 1:nrow(dat))
{
    if(is.na(dat[i,2])) # missing data
        next

    if(dat[i,1] == "C"){
        totC = totC + dat[i,2]
        cntC = cntC + 1
    }
    if(dat[i,1] == "E"){
        totE = totE + dat[i,2]
        cntE = cntE + 1
    }
    if(dat[i,1] == "P"){
        totP = totP + dat[i,2]
        cntP = cntP + 1
    }
}
sprintf("C found %d times with a total of %f and an average of %f", cntC, totC, (totC / cntC))
sprintf("E found %d times with a total of %f and an average of %f", cntE, totE, (totE / cntE))
sprintf("P found %d times with a total of %f and an average of %f", cntP, totP, (totP / cntP))

【问题讨论】:

    标签: c# r idioms


    【解决方案1】:

    我会使用data.table 包,因为它内置了group by 功能。

     library(data.table)
     dat <- data.table(dat)
    
     dat[, mean(COL_NAME_TO_TAKE_MEAN_OF), by=COL_NAME_TO_GROUP_BY]
           # no quotes for the column names
    

    如果您想在多列上取平均值(或执行其他功能),仍然按组,请使用:

     dat[, lapply(.SD, mean), by=COL_NAME_TO_GROUP_BY]
    

    或者,如果你想使用 Base R,你可以使用类似

     by(dat, dat[, 1], lapply, mean)
     # to convert the results to a data.frame, use  
     do.call(rbind,  by(dat, dat[, 1], lapply, mean) )
    

    【讨论】:

    • 基本R方式返回几个argument is not numeric or logical: returning NA
    • 你可能有一些factors。运行sapply(dat, is.factor) 看看哪个。然后转换为数字(通过as.character)。但是,如果您可以处理 SQL 等并快速掌握语言,我会坚持使用data.table
    • data.table 方式在by 上给我一个错误,“未使用的参数”。我必须做一些特别的事情来定义列标题吗?它们已包含在 CSV 中。
    • 检查names(DT)。然后尝试复制并粘贴您在那里看到的值
    • @RicardoSaporta 我做了,我仍然得到错误:[.data.frame``(dat, , lapply(.SD, mean), by = treatment) : unused argument (by = treatment)
    【解决方案2】:

    我会做这样的事情:

    dat = dat[complete.cases(dat),]  ## The R way to remove missing data
    dat[,2] <- as.numeric(dat[,2])   ## convert to numeric as you do in c#
    by(dat[,2],dat[,1],mean)         ## compute the mean by group
    

    当然要将结果汇总到 data.frame 中,您可以使用经典的,但我认为这里没有必要,因为它是 3 个变量的列表:

     do.call(rbind,result)
    

    EDIT1

    这里的另一个选择是使用优雅的ave

    ave(dat[,2],dat[,1])
    

    但是这里的结果是不同的。从某种意义上说,您将获得与原始数据长度相同的向量。

    EDIT2要包含更多结果,您可以详细说明您的匿名函数:

    by(dat[,2],dat[,1],function(x) c(min(x),max(x),mean(x),sd(x)))
    

    或者返回data.frame 更适合rbind 调用并带有列名:

    by(dat[,2],dat[,1],function(x) 
                data.frame(min=min(x),max=max(x),mean=mean(x),sd=sd(x)))
    

    或者使用优雅的内置函数(你也可以定义你的)summary:

    by(dat[,2],dat[,1],summary)
    

    【讨论】:

    • 我应该如何扩展它以包括标准偏差、最小值、最大值等其他内容?
    【解决方案3】:

    一种方式:

    library(plyr)
    
    ddply(dat, .(columnOneName), summarize, Average = mean(columnTwoName))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 2012-04-25
      • 1970-01-01
      相关资源
      最近更新 更多