有效地写入pandas中的多个相邻列

时间:2015-06-30 08:04:23

标签: python numpy pandas

使用numpy ndarray,可以一次写入多个列,而无需先复制(只要它们相邻)。如果我想写一个数组的前三列,我会写

a[0,0:3] = 1,2,3 # this is very fast ('a' is a numpy ndarray)

我希望在大熊猫中,我同样可以通过“标签切片”选择多个相邻的列,如此(假设前3列标有'a','b','c')

a.loc[0,'a':'c'] = 1,2,3 # this works but is very slow ('a' is a pandas DataFrame)

或类似地

a.iloc[0,3:6] = 1,2,3 # this is equally as slow

然而,与写入仅需几微秒的numpy数组相比,这需要几百毫秒。我不清楚大熊猫是否正在制作阵列的副本。我能找到以这种方式写入数据帧以提供良好速度的唯一方法是直接处理底层的ndarray

a.values[0,0:3] = 1,2,3 # this works fine and is fast

我是否遗漏了Pandas文档中的内容,或者他们无法在Pandas数据帧上进行多个相邻列索引,速度可与numpy相媲美?

修改

这是我正在使用的实际数据框架。

>> conn = sqlite3.connect('prath.sqlite')
>> prath = pd.read_sql("select image_id,pixel_index,skin,r,g,b from pixels",conn)
>> prath.shape
(5913307, 6)
>> prath.head()
   image_id  pixel_index  skin    r    g    b
0        21       113764     0    0    0    0
1        13       187789     0  183  149  173
2        17       535758     0  147   32   35
3        31         6255     0  116    1   16
4        15       119272     0  238  229  224
>> prath.dtypes
image_id       int64
pixel_index    int64
skin           int64
r              int64
g              int64
b              int64
dtype: object

以下是不同索引方法的一些运行时比较(同样,pandas索引非常慢)

>> %timeit prath.loc[0,'r':'b'] = 4,5,6
1 loops, best of 3: 888 ms per loop
>> %timeit prath.iloc[0,3:6] = 4,5,6
1 loops, best of 3: 894 ms per loop
>> %timeit prath.values[0,3:6] = 4,5,6
100000 loops, best of 3: 4.8 µs per loop

2 个答案:

答案 0 :(得分:2)

编辑以澄清:我不相信大熊猫在速度和语法方面都可以直接模拟numpy中的视图。 ilocloc在语法和目的方面可能是最直接的模拟,但速度要慢得多。这是numpy和pandas相当普遍的情况。熊猫比numpy(标记的列/索引,自动对齐等)做得更多,但是在不同程度上更慢。当你需要速度并且可以在numpy中做事时,那就把它们做成numpy。

我想简而言之,这里的权衡是lociloc会慢一点,但是100%的时间工作,而values会很快但不总是有效(对于values说实话,我甚至没有意识到它会以你的工作方式发挥作用。)

但这是一个非常简单的例子prath['g'] = 3.33 prath.values[0,3:6] = 4,5,6 prath.head(3) image_id pixel_index skin r g b 0 21 113764 0 0 3.33 0 1 13 187789 0 183 3.33 173 2 17 535758 0 147 3.33 35 prath.iloc[0,3:6] = 4,5,6 prath.head(3) image_id pixel_index skin r g b 0 21 113764 0 4 5.00 6 1 13 187789 0 183 3.33 173 2 17 535758 0 147 3.33 35 不起作用,因为列' g'是浮点而不是整数。

values

当列是同类型时,您通常可以从pandas获得类似numpy的速度和行为,您要小心这一点。 编辑添加:正如评论中的@toes说明,文档确实说明您可以使用同类数据执行此操作。但是,正如上面的例子所示,它可能非常容易出错,我并不认为很多人会认为这是大熊猫的一般做法。

我的一般建议是,在你需要速度(并且具有同类数据类型)的情况下,在numpy中做事情,在你不需要的时候做pandas。好的是,numpy和pandas可以很好地协同工作,所以在你去的时候,在数据帧和数组之间进行转换并不是那么难。

编辑以添加:以下内容似乎有用(尽管有警告),即使是列' g'作为一个浮动。速度介于loc/iloc路和prath[0:1][['r','g','b']] = 4,5,6 路之间。我不确定这是否可以预期一直有效。只是把它作为可能的中间道路。

<script type="text/javascript" src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/bootstrap.js"></script>
<script type="text/javascript" src="~/Scripts/bootstrap-datepicker.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>

<link rel=" stylesheet" href="~/Content/bootstrap-theme.css">
<link rel=" stylesheet" href="~/Content/datepicker.min.css">
<link rel=" stylesheet" href="~/Content/bootstrap-datepicker3.min.css">

答案 1 :(得分:2)

我们正在添加直接索引的功能,即使在多dtype帧中也是如此。这是现在的主人,将在0.17.0。你可以在&lt; 0.17.0,但它需要(更多)操纵内部。

In [1]: df = DataFrame({'A' : range(5), 'B' : range(6,11), 'C' : 'foo'})

In [2]: df.dtypes
Out[2]: 
A     int64
B     int64
C    object
dtype: object

copy=False标志是新的。这给你一个dtypes-&gt;块的字典(dtype可分离)

In [3]: b = df.as_blocks(copy=False)

In [4]: b
Out[4]: 
{'int64':    A   B
 0  0   6
 1  1   7
 2  2   8
 3  3   9
 4  4  10, 'object':      C
 0  foo
 1  foo
 2  foo
 3  foo
 4  foo}

这是基础的numpy数组。

In [5]: b['int64'].values
Out[5]: 
array([[ 0,  6],
       [ 1,  7],
       [ 2,  8],
       [ 3,  9],
       [ 4, 10]])

这是原始数据集中的数组

In [7]: id(df._data.blocks[0].values)
Out[7]: 4429267232

以下是我们对它的看法。它们是相同的

In [8]: id(b['int64'].values.base)
Out[8]: 4429267232

现在您可以访问该框架,并使用pandas set操作进行修改。 您也可以通过.values直接访问numpy数组,现在它是原始的VIEW。

修改后不会产生任何速度惩罚,因为只要您不改变数据本身的类型,就不会制作副本(例如,不要尝试在此处输入字符串) ;它会起作用,但视图会丢失)

In [9]: b['int64'].loc[0,'A'] = -1

In [11]: b['int64'].values[0,1] = -2

由于我们有一个视图,您可以更改基础数据。

In [12]: df
Out[12]: 
   A   B    C
0 -1  -2  foo
1  1   7  foo
2  2   8  foo
3  3   9  foo
4  4  10  foo

请注意,如果您修改数据的形状(例如,如果您添加列),那么视图将会丢失。