2017-12-25 195 views
9

Uważam, że wynik jest trochę losowy. Czasami jest to kopia, czasami jest to widok. Na przykład:W Pandach, czy metoda .iloc daje kopię lub widok?

df = pd.DataFrame([{'name':'Marry', 'age':21},{'name':'John','age':24}],index=['student1','student2']) 

df 
       age name 
    student1 21 Marry 
    student2 24 John 

Teraz, pozwól mi spróbować trochę zmodyfikować.

df2= df.loc['student1'] 
df2 [0] = 23 
df 
       age name 
    student1 21 Marry 
    student2 24 John 

Jak widać, nic się nie zmieniło. df2 to kopia. Jednakże, jeśli dodam innego ucznia do dataframe ...

df.loc['student3'] = ['old','Tom'] 
df 
       age name 
    student1 21 Marry 
    student2 24 John 
    student3 old Tom 

Spróbuj ponownie zmienić wiek ..

df3=df.loc['student1'] 
df3[0]=33 
df 
       age name 
    student1 33 Marry 
    student2 24 John 
    student3 old Tom 

Teraz DF3 nagle stał się pogląd. Co się dzieje? Domyślam się, że kluczem jest wartość "stary"?

Odpowiedz

5

Generalnie można uzyskać pogląd, jeśli dane rama ma jeden dtype, który jest nie w przypadku oryginalnego danych ramki:

In [4]: df 
Out[4]: 
      age name 
student1 21 Marry 
student2 24 John 

In [5]: df.dtypes 
Out[5]: 
age  int64 
name object 
dtype: object 

Jednak po zrobić:

In [6]: df.loc['student3'] = ['old','Tom'] 
    ...: 

pierwsza kolumna get zmuszany do object, ponieważ kolumny nie może mieć mieszane dtypes:

In [7]: df.dtypes 
Out[7]: 
age  object 
name object 
dtype: object 

W przypadku bazowych .values zawsze zwraca tablicę z tego samego buforu podstawowego, i zmiany w tej tablicy będą widoczne w danych ramki:

In [11]: vals = df.values 

In [12]: vals 
Out[12]: 
array([[21, 'Marry'], 
     [24, 'John'], 
     ['old', 'Tom']], dtype=object) 

In [13]: vals[0,0] = 'foo' 

In [14]: vals 
Out[14]: 
array([['foo', 'Marry'], 
     [24, 'John'], 
     ['old', 'Tom']], dtype=object) 

In [15]: df 
Out[15]: 
      age name 
student1 foo Marry 
student2 24 John 
student3 old Tom 

Z drugiej strony z mieszane typy jak z oryginalnego danych ramki:

In [26]: df = pd.DataFrame([{'name':'Marry', 'age':21},{'name':'John','age':24}] 
    ...: ,index=['student1','student2']) 
    ...: 

In [27]: vals = df.values 

In [28]: vals 
Out[28]: 
array([[21, 'Marry'], 
     [24, 'John']], dtype=object) 

In [29]: vals[0,0] = 'foo' 

In [30]: vals 
Out[30]: 
array([['foo', 'Marry'], 
     [24, 'John']], dtype=object) 

In [31]: df 
Out[31]: 
      age name 
student1 21 Marry 
student2 24 John 

jednak pamiętać, że widok zostanie zwrócone tylko wtedy, gdy jest to możliwe, aby mieć widok, to znaczy, czy jest to właściwa plaster, inaczej Kopia zostanie wykonana niezależnie od dtypes:

In [39]: df.loc['student3'] = ['old','Tom'] 


In [40]: df2 
Out[40]: 
      name 
student3 Tom 
student2 John 

In [41]: df2.loc[:] = 'foo' 

In [42]: df2 
Out[42]: 
     name 
student3 foo 
student2 foo 

In [43]: df 
Out[43]: 
      age name 
student1 21 Marry 
student2 24 John 
student3 old Tom 
+0

Czy to oznacza, że ​​zawsze otrzymam kopię, jeśli ramka danych zawiera wiele dtypów? – Qiyu

+0

@Qiyu z wieloma dtypami tak. –

+0

Mam to. Dzięki! – Qiyu

10

Zaczynasz z DataFrame który ma dwie kolumny z dwóch różnych dtypes:

df.dtypes 
Out: 
age  int64 
name object 
dtype: object 

Ponieważ różne dtypes przechowywane są w różnych tablic numpy Pod maską masz dwa różne bloki do nich:

df.blocks 

Out: 
{'int64':   age 
student1 21 
student2 24, 'object':   name 
student1 Marry 
student2 John} 

Przy próbie ucięcia pierwszego wiersza tej ramki DataFrame, należy uzyskać jedną wartość z każdego bloku, co powoduje konieczność utworzenia kopii.

df2.is_copy 
Out[40]: <weakref at 0x7fc4487a9228; to 'DataFrame' at 0x7fc4488f9dd8> 

W drugiej próbie zmieniasz dtypes. Ponieważ "stary" nie może być przechowywany w tablicy liczb całkowitych, rzutuje serię jako serię obiektów.

df.loc['student3'] = ['old','Tom'] 

df.dtypes 
Out: 
age  object 
name object 
dtype: object 

Teraz wszystkie dane tego DataFrame jest przechowywany w jednym bloku (a w jednym numpy tablicy)

df.blocks 

Out: 
{'object':   age name 
student1 21 Marry 
student2 24 John 
student3 old Tom} 

Na tym etapie krojenia pierwszy rząd może być wykonane na numpy tablicy bez tworzenia kopii, więc zwraca widok.

df3._is_view 
Out: True 
+0

Nigdy nie wiedział o 'df.blocks' –

+0

@ juanpa.arrivillaga Nauczyłem się o tym z [piRSquared] (https://stackoverflow.com/a/45805614/2285236), ale sądzę, że zamierzają uczynić z tego prywatną cechę. – ayhan

+0

'_is_view' to naprawdę dobra funkcjonalność, nie wiedziałem o tym. Dzięki –