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

问题描述:

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

注意,经过的/实际>用户+系统。这表明CPU正在磁盘上等待。

我怀疑R的速度慢与在读取数据做看来我是对的。

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

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

+6

R和unix中有很多函数具有不同的速度。在R和unix中,你是否至少有一个具有相同功能的具体例子,以及定时测试? – cr1msonB1ade

+0

这个问题是非常广泛的... – nrussell

+0

@ cr1msonB1ade和nrussell是这个更好 –

我不确定你在说什么操作,但是一般来说,像R这样的更复杂的处理系统使用更复杂的内部数据结构来表示正在操作的数据,构建这些数据结构可能是一个很大的瓶颈,比像grep这样的Unix命令倾向于操作的简单的行,单词和字符慢得多。

另一个因素(取决于您的脚本的设置方式)在于您是以“流模式”一次处理数据,还是将所有内容都读入内存。 Unix命令往往被写成在管线中操作,并读取一小段数据(通常是一行),处理它,也许写出一个结果,然后转到下一行。另一方面,如果在处理之前将整个数据集读入内存,那么即使您拥有足够的RAM,分配和组织所有必需的内存也可能非常昂贵。

[更新内容,以响应您的附加信息]

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

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

  1. 无缓冲小,随机读取。我们一次询问操作系统一个或几个字符,并在我们阅读时处理它们。
  2. 无缓冲的大块读取。我们要求操作大块的内存 - 通常是1k或8k的大小 - 并在请求下一个块之前咀嚼每块内存。
  3. 缓冲读取。我们的编程语言为我们提供了一种方法,可以根据需要从中间缓冲区中获取所需的字符数,并且内置于该语言中的代码(“库”代码)会自动通过读取较大的块大小来自动保留该缓冲区来自操作系统的大块。

现在,重要的是要知道的是,操作系统将宁可阅读大块大小的块。所以#1可以大大慢于2和3.(我已经看过10或100的因子)。但没有一个写得很好的程序使用#1,所以我们几乎可以忘掉它。只要你使用2或3,I/O速度将大致相同。 (在极端情况下,如果您知道自己在做什么,可以通过使用2而不是3来提高效率)。

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

  1. 一次只读一个字符。 (我可以向你保证,它使用方法3)
  2. 对于每个角色读,添加一个字符数。
  3. 如果读取的字符是换行符,请将行数加1。
  4. 如果读取的字符是或不是一个字分隔符,更新的字数。
  5. 在最后,打印出的线条,即,和/或字符的计数,作为请求。

因此,您可以看到它是所有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建立一张桌子。表格是一个特定的,高度规则的数据结构,它将所有数据排列成刚性的行和列以进行有效的查找。要看看可以做多少工作,让我们用一个稍微牵强的假设现实世界的例子。

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

但首先你必须建立那个教室。你不知道有多少人会走过,所以你建立一个普通的教室,空间可容纳5排6个桌子,可容纳30人,并且你可以在桌子上拖动,然后人们开始归档,并在30人们在你身上发现有一个31号,你做什么?你可以让他站在后面,但是你有点关注刚性行列的想法,所以你要求第三十一个人等待,然后你立即打电话给建设者,让他们建立第二个30人的教室就在第一个旁边,现在你可以接受第31个人,实际上29个人可以接受60个人,但是你会注意到第61个人。

所以你问他要等待,您再次致电建设者,你有他们建立更多的教室,所以现在你已经有了一个30人的教室里一个不错的2x2的网格,但不断有人即将到来,第121位的人出现了,没有足够的空间,你甚至还没有开始询问你的调查问题。

所以你叫一些知道如何做钢结构的建设者,并让他们在隔壁建造一栋5层的大楼,每层5个教室,总共50 x 5 x 5 = 1,250张办公桌,你有120个人(耐心等待的人)从旧房间搬进新大楼,现在有121人的空间,还有更多的人在他身后,你雇用了一些失事者拆除旧教室并回收一些材料,并且人们不断地到来,很快有新的大楼中有1,250人在等待接受调查,而1,251人刚刚出现。

因此,您要在每层楼和100层楼上建造一座拥有1,000个办公桌的巨型新摩天大楼,并且拆除旧的5层建筑,但人们不断前来,您说您的大数据集有多大? 1e7 x 50?所以我不认为这座100层的建筑也不够大。 (当你完成了所有这些,你要问的唯一的“调查问题”是“有多少行?”)

看起来似乎这样做,这其实并不太糟糕这是R内部建立表来存储数据集的一个类比。

同时,Bob的折扣调查公司,他只能告诉你他调查了多少人,有多少人是男性和女性,其中的年龄段落在街角上,人们正在归档,而鲍勃正在剪贴板上记下相应的标记,并且曾经接受调查的人们正在走开并开始他们的业务,而鲍勃并不是那种“不要浪费时间和金钱建设任何教室。

我对R一无所知,但看看有没有办法在前面构建一个空的1e7 x 50矩阵,并将CSV文件读入它。你可能会发现更快。 R仍然需要做一些建设,但至少它不会有任何错误的开始。

+0

谢谢!一般来说,我猜想Unix代码很快的原因有两个。首先,R的数据结构比Unix更复杂。其次,所有内容都被加载到R的复杂数据结构中的RAM中,对于Unix来说也是如此,即一次只读入小块数据。作为一个简要说明,Unix命令的数据结构是什么(抱歉,最后一句可能措辞不佳,因为你可能已经猜到了我不是计算机科学家) –

+0

谢谢你太棒了! –