Взгляды панд против копии: документы говорят, что "никто не знает"?
В Stackru много вопросов о цепной индексации и о том, создает ли конкретная операция представление или копию. (например, здесь или здесь). Я до сих пор не до конца понял, но поразительная часть - официальные документы говорят, что "никто не знает". (!?!??) Вот пример из документации; Можете ли вы сказать мне, если они действительно имели в виду, или они просто легкомысленны?
От http://pandas-docs.github.io/pandas-docs-travis/indexing.html?highlight=view
def do_something(df):
foo = df[['bar', 'baz']] # Is foo a view? A copy? Nobody knows!
# ... many lines here ...
foo['quux'] = value # We don't know whether this will modify df or not!
return foo
Шутки в сторону? Для этого конкретного примера действительно ли "никто не знает", и это недетерминировано? Будет ли это действительно вести себя по-разному на двух разных фреймах данных? Правила действительно так сложны? Или парень имел в виду, что есть определенный ответ, но большинство людей об этом не знают?
3 ответа
Я думаю, что могу продемонстрировать кое-что, чтобы прояснить вашу ситуацию, в вашем примере, изначально это будет представление, но как только вы попытаетесь изменить, добавив столбец, он превратится в копию. Вы можете проверить это, посмотрев на атрибут ._is_view
:
In [29]:
df = pd.DataFrame(np.random.randn(5,3), columns=list('abc'))
def doSomething(df):
a = df[['b','c']]
print('before ', a._is_view)
a['d'] = 0
print('after ', a._is_view)
doSomething(df)
df
before True
after False
Out[29]:
a b c
0 0.108790 0.580745 1.820328
1 1.066503 -0.238707 -0.655881
2 -1.320731 2.038194 -0.894984
3 -0.962753 -3.961181 0.109476
4 -1.887774 0.909539 1.318677
Итак, здесь мы можем видеть, что изначально a
Это вид исходного подраздела исходного df, но как только вы добавите к нему столбец, это уже не так, и мы видим, что исходный df не изменился.
Вот основная часть документации, которую, я думаю, вы могли пропустить:
За исключением простых случаев, очень трудно предсказать, будет ли он возвращать представление или копию (это зависит от структуры памяти массива, о которой панды не дает никаких гарантий)
Таким образом, существует базовый массив с некоторой разметкой памяти. Панды не заботятся о каких-либо знаниях об этом. Кроме того, я не слишком внимательно читал документы, но я предполагаю, что у них есть какой-то подход, который вы должны использовать вместо этого, если вы действительно хотите установить значения.
Вот пример, который, как мне показалось, хорошо проиллюстрировал несоответствие.
Я помещаю подмножество dataframe, который возвращает представление. Затем я могу перезаписать значения во всем столбце, но в зависимости от того, как я это делаю синтаксически, я получаю разные результаты.
df = pd.DataFrame(np.random.randn(100, 100))
x = df[(df > 2).any(axis=1)]
print x._is_view
>>> True
# Prove that below we are referring to the exact same slice of the dataframe
assert (x.iloc[:len(x), 1] == x.iloc[:, 1]).all()
# Assign using equivalent notation to below
x.iloc[:len(x), 1] = 1
print x._is_view
>>> True
# Assign using slightly different syntax
x.iloc[:, 1] = 1
print x._is_view
>>> False