In[216]: foo = pd.DataFrame({'a':[1,2,3], 'b':[3,4,5]})
In[217]: bar = foo.ix[:1]
In[218]: bar
Out[218]:
a b
0 1 3
1 2 4
按预期创建视图。
In[219]: bar['a'] = 100
In[220]: bar
Out[220]:
a b
0 100 3
1 100 4
In[221]: foo
Out[221]:
a b
0 100 3
1 100 4
2 3 5
如果修改了视图,原始数据帧foo也是如此。 但是,如果使用“无”进行分配,则似乎会进行复制。 任何人都可以了解正在发生的事情以及可能背后的逻辑吗?
In[222]: bar['a'] = None
In[223]: bar
Out[223]:
a b
0 None 3
1 None 4
In[224]: foo
Out[224]:
a b
0 100 3
1 100 4
2 3 5
答案 0 :(得分:7)
当您指定bar['a'] = None
时,您强制该列将其dtype从例如I4
更改为object
。
这样做会强制它为列分配一个新的object
数组,然后它会写入该新数组,而不是写入与原始DataFrame
共享的旧数组。< / p>
答案 1 :(得分:6)
你正在做一种链式作业的形式,请参阅here为什么这是一个非常糟糕的主意。
同时查看此问题here
Pandas通常会警告您正在修改视图(在0.15.0中更是如此)。
In [49]: foo = pd.DataFrame({'a':[1,2,3], 'b':[3,4,5]})
In [51]: foo
Out[51]:
a b
0 1 3
1 2 4
2 3 5
In [52]: bar = foo.ix[:1]
In [53]: bar
Out[53]:
a b
0 1 3
1 2 4
In [54]: bar.dtypes
Out[54]:
a int64
b int64
dtype: object
# this is an internal method (but is for illustration)
In [56]: bar._is_view
Out[56]: True
# this will warn in 0.15.0
In [57]: bar['a'] = 100
/usr/local/bin/ipython:1: 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 the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
#!/usr/local/bin/python
In [58]: bar._is_view
Out[58]: True
# bar is now a copied object (and will replace the existing dtypes with new ones).
In [59]: bar['a'] = None
In [60]: bar.dtypes
Out[60]:
a object
b int64
dtype: object
你应该从不依赖某些东西是否是一个视图(即使是在numpy中),除非在某些非常高效的情况下。它不是有保证的构造,具体取决于底层数据的内存布局。
你应该很少尝试通过视图设置传播数据。当你混合dtypes时,在pandas
中执行此操作几乎总会导致麻烦。 (在numpy中你可以只在一个dtype上有一个视图;我甚至不确定在多个dtyped数组上哪个更改 dtype的视图,或者是甚至允许)。