为什么Unix /终端比R更快?

时间:2015-06-19 22:46:29

标签: r bash shell unix terminal

我是Unix的新手,但是,我最近意识到非常简单的Unix命令可以非常快速地对大数据集做很简单的事情。我的问题是为什么这些Unix命令相对于R如此之快?

首先假设数据很大,但不大于计算机上的RAM量。

计算上,我知道Unix命令可能比它们的R对应物更快。但是,我无法想象这会解释整个时差。所有基本的R函数(如Unix命令)都是用C / C ++等低级语言编写的。

因此我怀疑速度增益与I / O有关。虽然我只对计算机的工作方式有基本的了解,但我确实理解操作数据最先从磁盘读取(假设数据是本地的)。这很慢。但是,无论您使用R函数还是Unix命令来操作数据,大多数都是从磁盘获取数据。

因此,我怀疑如何从磁盘读取数据,如果这是有道理的,那就是推动时差的原因。这种直觉是否正确?

谢谢!

更新:抱歉模糊不清。这是故意的,我希望能够一般性地讨论这个想法,而不是专注于一个具体的例子。

无论如何,我将生成一个计算行数的例子

首先,我将生成一个大数据集。

row = 1e7
col = 50
df<-matrix(rpois(row*col,1),row,col)
write.csv(df,"df.csv")

使用Unix

time wc -l df.csv
real    0m12.261s
user    0m1.668s
sys     0m2.589s

用R

library(data.table)
system.time({ nrow(fread("df.csv")) })
...
user   system   elapsed
26.77    1.67     47.07

请注意,已过去/真实&gt;用户+系统。这表明CPU正在等待磁盘。

我怀疑R的速度慢与读取数据有关。看来我是对的:

system.time(fread("df.csv"))
user  system  elapsed
34.69   2.81    47.41

我的问题是Unix和R的I / O有何不同?为什么?

1 个答案:

答案 0 :(得分:10)

我不确定您正在谈论的操作,但一般来说,像R这样的更复杂的处理系统使用更复杂的内部数据结构来表示被操纵的数据,构建这些数据结构可以是一个很大的瓶颈,比像grep这样的Unix命令操作的简单线条,单词和字符要慢得多。

另一个因素(取决于您的脚本的设置方式)是您是一次一个地处理数据,流式传输模式&#34;还是将所有内容都读入内存。 Unix命令倾向于编写为在管道中操作,并读取一小段数据(通常是一行),处理它,可能写出结果,然后继续下一行。另一方面,如果在处理之前将整个数据集读入内存,那么即使你有足够的RAM,分配和组织所有必要的内存也会非常昂贵。

[根据您的其他信息更新]

啊哈。所以你 要求R一次将整个文件读入内存。这占了很大差异。让我们谈谈更多的事情。

I / O。我们可以考虑从文件中读取字符的三种方法,特别是如果我们正在处理的处理方式影响了阅读最方便的方式。

  1. 无缓冲的小型随机读取。我们一次向操作系统询问1个或几个字符,并在阅读时对其进行处理。
  2. 无缓冲的大型块大小读取。我们要求操作大块内存 - 通常大小为1k或8k - 并在要求下一个块之前在内存中的每个块上进行咀嚼。
  3. 缓冲读取。我们的编程语言为我们提供了一种从中间缓冲区中请求尽可能多的字符的方法,并且语言内置的代码(&#34;库和#34;代码)会自动保持这一点。通过从操作系统中读取大块大小的块来填充缓冲区。
  4. 现在,重要的是要知道操作系统更愿意读取块大小的块。所以#1可能比2和3慢得多。(我已经看过10或100的因素。)但没有编写良好的程序使用#1,所以我们几乎可以忘记它。只要您使用2或3,I / O速度就会大致相同。 (在极端情况下,如果你知道你正在做什么,你可以通过使用2代替3来提高效率,如果可以的话。)

    现在让我们谈谈每个程序处理数据的方式。 wc基本上有5个步骤:

    1. 一次读取一个字符。 (我可以向你保证它使用方法3.)
    2. 对于每个读取的字符,请在字符数中添加一个。
    3. 如果读取的字符是换行符,请在行计数中添加一个。
    4. 如果读取的字符是或不是字分隔符,请更新字数。
    5. 最后,根据要求打印出行数,单词和/或字符数。
    6. 因此,您可以看到它的所有I / O和非常简单的基于字符的处理。 (唯一复杂的步骤是4.作为练习,我曾经写过wc的一个版本,设法不在读取循环中执行所有步骤2,3和4,如果用户没有要求所有的计数。如果您调用wc -cwc -l,我的版本确实运行得更快。但显然代码要复杂得多。)

      另一方面,在R的情况下,事情要复杂得多。首先,您告诉它读取CSV文件。因此,当它读取时,它必须找到分隔行的新行和分隔列的逗号。这大致相当于wc必须执行的处理。但是,对于它找到的每个数字,它必须将其转换为可以有效工作的内部数字。例如,如果CSV文件中的某个位置出现序列

      ...,12345,...
      

      R将必须读取这些数字(作为单个字符),然后执行相当于数学问题

       1 * 10000 + 2 * 1000 + 3 * 100 + 4 * 10 + 5 * 1
      

      获取值12345。

      但还有更多。你要求R建一张桌子。表是一种特定的,高度规则的数据结构,它将所有数据排序为刚性行和列,以便进行有效查找。为了了解可以做多少工作,让我们使用一个稍微牵强的假设现实世界的例子。

      假设您是一家调查公司,并且要求在街上走过某些问题的人是您的工作。但是假设问题很复杂,你需要所有坐在教室里的人。 (进一步假设人们不介意这种不便。)

      但首先你必须建立那个教室。你不确定要走多少人,所以你建造了一个普通的教室,可容纳30人的5排6张办公桌,你可以在办公桌上拖拉,然后人们开始归档, 30个人在你注册后发现有31个,所以你做了什么?你可以让他站在后面,但你有点注意刚性的行和列的想法,所以你要求第31个人等待,你很快就打电话给建设者并要求他们建立在第一个旁边的第二个30人教室,现在你可以接受第31个人,实际上还有29个人,总共60个,但是你注意到了第61个人。

      所以你让他等一下,然后再打电话给建设者,你让他们建造了两个的教室,所以现在你已经有了一个很好的2人网格的30人教室,但人们不断前来,很快就会有第121个人出现,而且还没有足够的空间,你甚至还没有开始询问你的调查问题。

      所以你打电话给一些知道如何做钢结构的爱好者,你可以让他们在隔壁建造一个5层高的大楼,有50人教室,每层5个,总共50 x 5 x 5 = 1,250办公桌,你有前120人(耐心等待的人)从旧房间进入新楼,现在有第121个人的房间,还有更多的房间,并且你雇用了一些清洁工来拆除旧教室并回收一些材料,人们不断前来,很快你们新楼里的1,250人等待接受调查,而第1,251人刚刚出现。 / p>

      所以你建造了一个巨大的新摩天大楼,每层楼和100层楼都有1000个办公桌,你要拆除旧的5层建筑,但人们不断前来,你说你的大数据集有多大? 1e7 x 50?因此,我不认为这座100层高的建筑也足够大。 (当你完成所有这些时,唯一的&#34;调查问题&#34;你要问的是&#34;有多少行?&#34;)< / p>

      看起来很可能,这实际上并不是一个类比,因为R必须在内部构建表以存储该数据集。

      与此同时,鲍勃的折扣调查公司只能告诉你他调查了多少人,男人和女人有多少人以及哪个年龄段在街角上,人们正在通过鲍勃正在他的剪贴板上记下计数标记,一旦接受调查,人们就会走开并开始他们的生意,鲍勃并不浪费时间和金钱建造任何教室。

      我对R一无所知,但看看是否有预先构建空1e7 x 50矩阵的方法,并将CSV文件读入其中。你可能会发现它明显更快。 R仍然需要做一些建设,但至少它不会有任何错误的开始。