正确的 DataFrame 切片修改

Posted

技术标签:

【中文标题】正确的 DataFrame 切片修改【英文标题】:Proper DataFrame slice modification 【发布时间】:2016-01-05 19:37:35 【问题描述】:

我正在尝试从一组行中修改一组列,当然我会收到以下警告:

A value is trying to be set on a copy of a slice from a DataFrame

我看到了一个类似的问题here,但我无法理解它。

所以如果我们按照这个示例代码:

from random import random as rd
ex= pd.DataFrame(["group": ["a","b"][int(round(rd()))], "colA": rd()*10, "colB": rd()*10, "colC": rd()*10,  "colD": rd()*10 for _ in range(20)])
cols = [col for col in ex.columns if col != "group"]

我只想修改属于 group a 的行和列 cols 上的行,对此我有点直觉地尝试(并收到警告警告):

ex[ex["group"]=="a"][cols] = ex[ex["group"]=="a"][cols]/ex.ix[0,cols]

列数匹配并且具有相同的标签,所以我想知道是否必须像这样一一进行:

for idx in ex[ex["group"]=="a"].index:
    for col in cols:
        ex.ix[idx, col]=ex.ix[idx, col]/ex.ix[0,col]

这当然可行,但感觉像是退后一步。那么做这样的事情的正确方法是什么?

【问题讨论】:

【参考方案1】:

IIUC 您可以使用您的布尔条件 .loc 一步完成此操作并传递 cols 列表:

In [110]:
from random import random as rd
ex= pd.DataFrame(["group": ["a","b"][int(round(rd()))], "colA": rd()*10, "colB": rd()*10, "colC": rd()*10,  "colD": rd()*10 for _ in range(20)])
cols = [col for col in ex.columns if col != "group"]
ex

Out[110]:
        colA      colB      colC      colD group
0   5.895114  3.961007  0.589091  9.846131     a
1   1.789049  7.532745  2.767378  9.144689     b
2   1.218778  2.715299  3.626688  6.516540     a
3   9.327049  3.207037  4.513850  1.910565     b
4   1.822876  0.049689  0.794706  8.463579     a
5   1.451741  6.045066  6.575130  4.882635     b
6   6.741825  4.253489  2.162466  1.050275     a
7   5.186613  3.401384  1.055468  4.060071     a
8   0.921352  8.076272  6.727293  3.219364     a
9   3.209232  8.883085  9.696195  4.089006     b
10  0.970030  6.412611  5.377420  5.475744     b
11  7.905807  4.576925  6.991989  2.974597     b
12  4.907642  7.123328  9.851058  2.337944     b
13  1.191606  2.636071  5.740342  3.301008     b
14  1.454777  3.086801  3.573110  1.402692     b
15  3.253882  1.853393  5.156287  8.268881     b
16  4.779060  4.689739  1.228976  6.339238     b
17  7.950160  4.973974  4.304821  4.492152     b
18  0.581628  6.860053  2.974577  6.542594     a
19  6.872025  9.216597  0.936447  5.518941     b

In [111]:    
ex.loc[ex['group']=='a', cols] /= ex.iloc[0][cols]
ex

Out[111]:
        colA      colB       colC      colD group
0   1.000000  1.000000   1.000000  1.000000     a
1   1.789049  7.532745   2.767378  9.144689     b
2   0.206744  0.685507   6.156417  0.661838     a
3   9.327049  3.207037   4.513850  1.910565     b
4   0.309218  0.012545   1.349039  0.859584     a
5   1.451741  6.045066   6.575130  4.882635     b
6   1.143629  1.073840   3.670853  0.106669     a
7   0.879816  0.858717   1.791690  0.412352     a
8   0.156291  2.038944  11.419789  0.326967     a
9   3.209232  8.883085   9.696195  4.089006     b
10  0.970030  6.412611   5.377420  5.475744     b
11  7.905807  4.576925   6.991989  2.974597     b
12  4.907642  7.123328   9.851058  2.337944     b
13  1.191606  2.636071   5.740342  3.301008     b
14  1.454777  3.086801   3.573110  1.402692     b
15  3.253882  1.853393   5.156287  8.268881     b
16  4.779060  4.689739   1.228976  6.339238     b
17  7.950160  4.973974   4.304821  4.492152     b
18  0.098663  1.731896   5.049437  0.664484     a
19  6.872025  9.216597   0.936447  5.518941     b

时间

In [112]:
%%timeit
for idx in ex[ex["group"]=="a"].index:
    for col in cols:
        ex.ix[idx, col]=ex.ix[idx, col]/ex.ix[0,col]
100 loops, best of 3: 11 ms per loop

In [113]:
%timeit ex.loc[ex['group']=='a', cols] /= ex.iloc[0][cols]
100 loops, best of 3: 5.3 ms per loop

因此,在您的小样本量下,我的方法速度提高了 2 倍以上,我希望它在矢量化后能够更好地扩展更大的数据集

【讨论】:

作为更新:当使用浮动的列名时,例如[1.1, 2.1, 3.4, 4.5] 而不是 ["colA", "colB", "colC", "colD"] 切片将在您想要查看时起作用,但是如果要对该切片进行归因,它将不起作用! 对列或索引值使用浮点数通常不是一个好主意

以上是关于正确的 DataFrame 切片修改的主要内容,如果未能解决你的问题,请参考以下文章

将 Pandas DataFrame 切片成新的 DataFrame

从 MultiIndex DataFrame 为切片分配新值

使用 loc 方法获取 DataFrame 的视图

数据分析2 numpy(ndarray数组,属性,创建,索引切片,运算,函数,随机数), Pandas(Series创建,缺失值处理,特性,索引,DataFrame)

基于DataFrame join写列

DataFrame[]中括号,通过列名取数据