尝试随机化数据帧的列时的KeyError

时间:2018-02-16 07:42:23

标签: python pandas numpy train-test-split

最小例子:
请考虑此数据框temp

temp = pd.DataFrame({"A":[1,2,3,4,5,6,7,8,9,10],"B":[2,3,4,5,6,7,8,9,10,11],"C":[3,4,5,6,7,8,9,10,11,12]})
>>> temp
    A   B   C
0   1   2   3
1   2   3   4
2   3   4   5
3   4   5   6
4   5   6   7
5   6   7   8
6   7   8   9
7   8   9  10
8   9  10  11
9  10  11  12

现在,尝试在for循环中一次洗牌每一列。

>>> for i in temp.columns:
...     np.random.shuffle(temp.loc[:,i])
...     print(temp)
...
    A   B   C
0   8   2   3
1   3   3   4
2   9   4   5
3   6   5   6
4   4   6   7
5  10   7   8
6   7   8   9
7   1   9  10
8   2  10  11
9   5  11  12
    A   B   C
0   8   7   3
1   3   9   4
2   9   8   5
3   6  10   6
4   4   4   7
5  10  11   8
6   7   5   9
7   1   3  10
8   2   2  11
9   5   6  12
    A   B   C
0   8   7   6
1   3   9   8
2   9   8   4
3   6  10  10
4   4   4   7
5  10  11  11
6   7   5   5
7   1   3   3
8   2   2  12
9   5   6   9

这很有效。
具体示例:

现在,如果我想获得此数据框的一部分,出于培训和测试目的,那么我将使用train_test_split中的sklearn.model_selection函数。

>>> from sklearn.model_selection import train_test_split
>>> temp = pd.DataFrame({"A":[1,2,3,4,5,6,7,8,9,10],"B":[2,3,4,5,6,7,8,9,10,11],"C":[3,4,5,6,7,8,9,10,11,12]})
>>> y = [i for i in range(16,26)]
>>> len(y)
10
>>> X_train,X_test,y_train,y_test = train_test_split(temp,y,test_size=0.2)
>>> X_train
    A   B   C
2   3   4   5
6   7   8   9
8   9  10  11
0   1   2   3
7   8   9  10
3   4   5   6
1   2   3   4
9  10  11  12

现在,我们已经获得了X_train数据框。为了改组每一栏:

>>> for i in X_train.columns:
...     np.random.shuffle(X_train.loc[:,i])
...     print(X_train)
...

不幸的是,这会导致错误 错误:

sys:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
    Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "mtrand.pyx", line 4852, in mtrand.RandomState.shuffle
  File "mtrand.pyx", line 4855, in mtrand.RandomState.shuffle
  File "C:\Users\H.P\AppData\Local\Programs\Python\Python36\lib\site-packages\pandas\core\series.py", line 623, in __getitem__
    result = self.index.get_value(self, key)
  File "C:\Users\H.P\AppData\Local\Programs\Python\Python36\lib\site-packages\pandas\core\indexes\base.py", line 2560, in get_value
    tz=getattr(series.dtype, 'tz', None))
  File "pandas\_libs\index.pyx", line 83, in pandas._libs.index.IndexEngine.get_value
  File "pandas\_libs\index.pyx", line 91, in pandas._libs.index.IndexEngine.get_value
  File "pandas\_libs\index.pyx", line 139, in pandas._libs.index.IndexEngine.get_loc
  File "pandas\_libs\hashtable_class_helper.pxi", line 811, in pandas._libs.hashtable.Int64HashTable.get_item
  File "pandas\_libs\hashtable_class_helper.pxi", line 817, in pandas._libs.hashtable.Int64HashTable.get_item
KeyError: 4

追踪问题及其解决方案:

SettingWithCopyWarning下,我发现了this问题,其中第一个答案就是这句话:

  

但是,它可以创建一个更新data['amount']副本的副本   你不会看到的。然后你会想知道它为什么不是   更新

但是,如果是这种情况,那么为什么代码适用于第一种情况?

答案中也给出了:

  

Pandas几乎在所有方法调用中都返回一个对象的副本。该   就地操作是一种有效的操作,但是在   一般不清楚数据是否正在修改和可能   可能在复制品上工作。

因此,我们可以使用np.random.shuffle代替np.random.permutation,而不是>>> for i in X_train.columns: ... X_train.loc[:,i] = np.random.permutation(X_train.loc[:,i]) ... print(X_train) ... 。所以:

SettingWithCopyWarning

但是,我再次得到C:\Users\H.P\AppData\Local\Programs\Python\Python36\lib\site-packages\pandas\core\indexing.py:621: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy self.obj[item_labels[indexer[info_axis]]] = value A B C 2 10 4 5 6 9 8 9 8 2 10 11 0 8 2 3 7 1 9 10 3 3 5 6 1 4 3 4 9 7 11 12 A B C 2 10 5 5 6 9 11 9 8 2 4 11 0 8 9 3 7 1 3 10 3 3 8 6 1 4 10 4 9 7 2 12 A B C 2 10 5 10 6 9 11 5 8 2 4 11 0 8 9 3 7 1 3 4 3 3 8 6 1 4 10 12 9 7 2 9 ,答案也是。

train_test_split

这可能是一种解决方法。

问题:

  1. 当我使用SettingWithCopyWarning时,为什么代码适用于第一种情况,而不适用于第二种情况?
  2. 当我没有使用inplace shuffler np.random.shuffle时,为什么我仍然会收到<md-tabs> <md-tab> <md-tab-label> <span ng-class="......"> Title </span> </md-tab-label> <md-tab-body> content </md-tab-body> </md-tab> </md-tabs>
  3. 建议要求:

    1. 是否有更好的(易于使用/无错误/更快)的方法来进行列改组?

2 个答案:

答案 0 :(得分:2)

  

1.当我使用train_test_split时,为什么代码适用于第一种情况,而不是第二种情况?

因为train_test_split会对X_train行进行洗牌。因此每列的索引不是范围而是一组值

您可以通过检查tempX_train

的索引来查看此内容
X_train.index
Int64Index([6, 8, 9, 5, 0, 2, 3, 4], dtype='int64')

temp.index
RangeIndex(start=0, stop=10, step=1)

在第一种情况下,与第二种情况不同,可以安全地将列视为一个数组。如果您将第二种情况中的代码更改为

for i in X_train.columns:
    np.random.shuffle(X_train.loc[:,i].values)
    print(X_train)  

这不会导致错误。

请注意,在您呈现的情况下,随机播放将导致每列不同的随机播放。即数据点会混淆。

  

2.当我没有使用inplace shuffler SettingWithCopyWarning时,为什么我仍然得到np.random.shuffle

使用最新版本的pandas(0.22.0)

时,我没有收到警告
  

建议请求:

     
      
  1. 是否有更好的(易于使用/无错误/更快)的方法来进行列改组?
  2.   

我建议在axis=1时使用样本,它会对列进行随机播放,样本数应该是列数。即X_train.shape[1]

X_train = X_train.sample(X_train.shape[1],axis=1)

In []: X_train.sample(X_train.shape[1],axis=1)
Out[]: 
    B   A   C
6   8   7   9
9  11  10  12
8  10   9  11
4   6   5   7
5   7   6   8
0   2   1   3
2   4   3   5
3   5   4   6

答案 1 :(得分:0)

我在使用 train_test_split 时也遇到了这个问题。我改用这个:

np.random.shuffle(x.iloc[:, i].values)

不知道为什么有效,但似乎解决了问题