Contoh Kode
# My code
df.loc[0, 'column_name'] = 'foo bar'
Kode di Pandas 20.3 ini melempar SettingWithCopyWarning dan menyarankan untuk
"Coba gunakan .loc[row_indexer,col_indexer] = value
sebagai gantinya".
Saya sudah melakukannya, sepertinya ada bug kecil. Saya menggunakan Jupyter.
Terima kasih! :)
pd.show_versions()
commit: Tidak ada
python: 3.6.1.final.0
python-bits: 64
OS: Windows
Rilis OS: 8.1
mesin: AMD64
prosesor: Intel64 Family 6 Model 61 Stepping 4, GenuineIntel
byteorder: sedikit
LC_ALL: Tidak ada
LANG: Tidak ada
LOCALE: Tidak ada. Tidak ada
panda: 0.20.1
pytest: 3.0.7
pip: 9.0.1
setuptools: 35.0.2
Cython: 0.25.2
numpy: 1.12.1
scipy: 0.19.0
xarray: Tidak ada
IPython: 5.3.0
sphinx: 1.5.6
patsy: 0.4.1
dateutil: 2.6.0.0
pytz: 2017.2
blosc: Tidak ada
kemacetan: 1.2.1
tabel: 3.2.2
numexpr: 2.6.2
bulu: Tidak ada
matplotlib: 2.0.2
openpyxl: Tidak ada
xlrd: 1.0.0
xlwt: 1.2.0
xlsxwriter: 0.9.6
lxml: 3.7.3
bs4: 4.6.0
html5lib: 0,999
sqlalchemy: 1.1.9
pymysql: Tidak ada
psycopg2: Tidak ada
jinja2: 2.9.6
s3fs: Tidak ada
pandas_gbq: Tidak ada
pandas_datareader: Tidak ada
@NadiaRom Bisakah Anda memberikan contoh lengkap? Sulit untuk mengatakan dengan pasti, tetapi saya menduga bahwa df
berasal dari operasi yang mungkin berupa tampilan atau salinan. Sebagai contoh:
In [8]: df = pd.DataFrame({"A": [1, 2], "B": [3, 4], "C": [4, 5]})
In [9]: df1 = df[['A', 'B']]
In [10]: df1.loc[0, 'A'] = 5
/Users/taugspurger/Envs/pandas-dev/lib/python3.6/site-packages/pandas/pandas/core/indexing.py:180: 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
self._setitem_with_indexer(indexer, value)
/Users/taugspurger/Envs/pandas-dev/bin/ipython: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
#!/Users/taugspurger/Envs/pandas-dev/bin/python3.6
Jadi kami memperbarui df1
dengan benar. Kerancuannya adalah apakah df
akan diperbarui juga atau tidak. Saya pikir hal serupa terjadi pada Anda, tetapi tanpa contoh yang dapat direproduksi, sulit untuk mengatakan dengan pasti.
@TomAugspurger Ini kodenya, secara umum, saya tidak pernah memberikan nilai ke panda tanpa .loc
df = pd.read_csv('df_unicities.tsv', sep='\t')
df.replace({'|': '--'}, inplace=True)
df_c = df.loc[df.encountry == country, : ]
df_c['sort'] = (df_c.encities_ua == 'all').astype(int) # new column
df_c['sort'] += (df_c.encities_foreign == 'all').astype(int)
df_c.sort_values(by='sort', inplace=True)
# ---end of chunk, everything is fine ---
if df_c.encities_foreign.str.contains('all').sum() < len(df_c):
df_c.loc[df_c.encities_foreign.str.contains('all'), 'encities_foreign'] = 'other'
df_c.loc[df_c.cities_foreign.str.contains('всі'), 'cities_foreign'] = 'інші'
else:
df_c.loc[df_c.encities_foreign.str.contains('all'), 'encities_foreign'] = country
df_c.loc[df_c.cities_foreign.str.contains('всі'), 'cities_foreign'] = df_c.country.iloc[0]
if df_c.encities_ua.str.contains('all').sum() < len(df_c):
df_c.loc[df_c.encities_ua.str.contains('all'), 'encities_ua'] = 'other'
df_c.loc[df_c.cities_ua.str.contains('всі'), 'cities_ua'] = 'інші'
else:
df_c.loc[df_c.encities_ua.str.contains('all'), 'encities_ua'] = 'Ukraine'
df_c.loc[df_c.cities_ua.str.contains('всі'), 'cities_ua'] = 'Україна'
# Warning after it
Terima kasih atas jawaban cepatnya!
Masalahnya di sini adalah Anda mengiris dataframe Anda terlebih dahulu dengan .loc
di baris 4. Mencoba menetapkan nilai ke potongan itu.
df_c = df.loc[df.encountry == country, :]
Panda tidak 100% yakin jika Anda ingin menetapkan nilai hanya ke potongan df_c
, atau menyebarkannya kembali ke aslinya df
. Untuk menghindari hal ini saat pertama kali menetapkan df_c
pastikan Anda memberi tahu panda bahwa itu adalah bingkai datanya sendiri (dan bukan potongan) dengan menggunakan
df_c = df.loc[df.encountry == country, :].copy()
Melakukan ini akan memperbaiki kesalahan Anda. Saya akan memberikan contoh singkat untuk membantu menjelaskan hal di atas karena saya telah memperhatikan banyak pengguna yang bingung dengan panda dalam aspek ini.
>>> import pandas as pd
>>> df = pd.DataFrame({'A':[1,2,3,4,5], 'B':list('QQQCC')})
>>> df
A B
0 1 Q
1 2 Q
2 3 Q
3 4 C
4 5 C
>>> df.loc[df['B'] == 'Q', 'new_col'] = 'hello'
>>> df
A B new_col
0 1 Q hello
1 2 Q hello
2 3 Q hello
3 4 C NaN
4 5 C NaN
Jadi di atas berfungsi seperti yang kami harapkan! Sekarang mari kita coba contoh yang mencerminkan apa yang Anda coba lakukan dengan data Anda.
>>> df = pd.DataFrame({'A':[1,2,3,4,5], 'B':list('QQQCC')})
>>> df_q = df.loc[df['B'] == 'Q']
>>> df_q
A B
0 1 Q
1 2 Q
2 3 Q
>>> df_q.loc[df['A'] < 3, 'new_col'] = 'hello'
/Users/riddellcd/anaconda/lib/python3.6/site-packages/pandas/core/indexing.py:337: 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[key] = _infer_fill_value(value)
>>> df_q
A B new_col
0 1 Q hello
1 2 Q hello
2 3 Q NaN
Sepertinya kita mengalami kesalahan yang sama! Tapi itu berubah df_q
seperti yang kami harapkan! Ini karena df_q
adalah potongan dari df
jadi, meskipun kita menggunakan .loc [] df_q
pandas memperingatkan kita bahwa itu tidak akan menyebarkan perubahan menjadi df
. Untuk menghindari hal ini, kita perlu lebih eksplisit dan mengatakan bahwa df_q
adalah kerangka datanya sendiri, terpisah dari df
dengan menyatakannya secara eksplisit.
Mari kita mulai kembali dari df_q
tetapi gunakan .copy()
kali ini.
>>> df_q = df.loc[df['B'] == 'Q'].copy()
>>> df_q
A B
0 1 Q
1 2 Q
2 3 Q
Lets try to reassign our value now!
>>> df_q.loc[df['A'] < 3, 'new_col'] = 'hello'
>>> df_q
A B new_col
0 1 Q hello
1 2 Q hello
2 3 Q NaN
Ini berfungsi tanpa kesalahan karena kami telah memberi tahu panda bahwa df_q
terpisah dari df
Jika Anda sebenarnya ingin perubahan ini ke df_c
menyebar hingga df
poin lain sepenuhnya dan akan menjawab jika Anda mau.
@CRiddler Hebat, terima kasih !
Seperti yang Anda sebutkan, dirantai .loc
tidak pernah memberikan hasil yang tidak diharapkan. Seperti yang saya pahami, .copy()
memastikan Pandas yang kami perlakukan dipilih df_sliced_once
sebagai objek terpisah dan tidak bermaksud untuk mengubah awal df
. Harap perbaiki jika saya campur aduk.
Dokumentasinya ada di sini http://pandas.pydata.org/pandas-docs/stable/indexing.html#returning -a-view-versus-a-copy dan @CRiddler punya inplace
sama sekali.
Jika Anda sebenarnya ingin perubahan ini ke
df_c
menyebar hinggadf
poin lain sepenuhnya dan akan menjawab jika Anda mau.
@ CRiddler Terima kasih, jawaban Anda lebih baik daripada yang ada di Stack Overflow, bisakah Anda menambahkan ketika Anda ingin menyebarkan ke kerangka data awal atau memberikan indikasi bagaimana hal itu dilakukan?
@persep Secara umum saya tidak suka mengubah masalah menjadi utas stackoverflow untuk mendapatkan bantuan, tetapi tampaknya masalah ini telah mendapat sedikit perhatian sejak posting terakhir jadi saya akan melanjutkan dan memposting metode saya untuk menangani jenis masalah ini di panda. Saya biasanya melakukan ini dengan tidak men-subset kerangka data menjadi variabel terpisah, tetapi saya malah mengubah topeng menjadi variabel- kemudian menggabungkan topeng sesuai kebutuhan dan menetapkan nilai berdasarkan topeng tersebut untuk memastikan perubahan terjadi dalam kerangka data asli, dan bukan pada beberapa salinan yang beredar .
Data asli:
>>>import pandas as pd
>>> df = pd.DataFrame({'A':[1,2,3,4,5], 'B':list('QQQCC')})
>>> df
A B
0 1 Q
1 2 Q
2 3 Q
3 4 C
4 5 C
Ingatlah bahwa membuat kerangka data sementara TIDAK akan menyebarkan perubahan
Seperti yang ditunjukkan pada contoh sebelumnya, ini membuat perubahan hanya menjadi df_q
dan memunculkan peringatan pandas (tidak disalin / ditempel di sini). DAN TIDAK menyebarkan perubahan apa pun ke df
>>> df_q = df.loc[df["B"] == "Q"]
>>> df_q.loc[df["A"] < 3, "new_column"] = "hello"
# df remains unchanged because we only made changes to `df_q`
>>> df
A B
0 1 Q
1 2 Q
2 3 Q
3 4 C
4 5 C
Sepengetahuan saya, tidak ada cara untuk menggunakan kode yang sama seperti di atas dan memaksa perubahan untuk disebarkan kembali ke kerangka data asli.
Namun, jika kita sedikit mengubah pemikiran kita dan bekerja dengan topeng alih-alih subset penuh, kita dapat mencapai hasil yang diinginkan. Meskipun ini tidak selalu "menyebarkan" perubahan ke dataframe asli dari subset, kami memastikan bahwa setiap perubahan yang kami lakukan terjadi pada dataframe asli df
. Untuk melakukan ini, kita membuat topeng terlebih dahulu, lalu menerapkannya ketika kita ingin membuat perubahan ke subset df
>>> q_mask = df["B"] == "Q"
>>> a_mask = df["A"] < 3
# Combine masks (in this case we used "&") to achieve what a nested subset would look like
# In the same step we add in our item assignment. Instructing pandas to create a new column in `df` and assign
# the value "hello" to the rows in `df` where `q_mask` & `a_mask` overlap.
>>> df.loc[q_mask & a_mask, "new_col"] = "hello"
# Successful "propagation" of new values to the original dataframe
>>> df
A B new_col
0 1 Q hello
1 2 Q hello
2 3 Q NaN
3 4 C NaN
4 5 C NaN
Terakhir, jika kami ingin melihat seperti apa df_q, kami selalu dapat membuat subset dari dataframe asli menggunakan q_mask
>>> df.loc[q_mask, :]
A B new_col
0 1 Q hello
1 2 Q hello
2 3 Q NaN
Meskipun ini belum tentu "menyebarkan" perubahan dari df_q
menjadi df
kami mencapai hasil yang sama. Propagasi yang sebenarnya perlu dilakukan secara eksplisit dan akan kurang efisien daripada hanya bekerja dengan topeng.
@CRiddler Terima kasih, Anda telah sangat membantu
Komentar yang paling membantu
Masalahnya di sini adalah Anda mengiris dataframe Anda terlebih dahulu dengan
.loc
di baris 4. Mencoba menetapkan nilai ke potongan itu.Panda tidak 100% yakin jika Anda ingin menetapkan nilai hanya ke potongan
df_c
, atau menyebarkannya kembali ke aslinyadf
. Untuk menghindari hal ini saat pertama kali menetapkandf_c
pastikan Anda memberi tahu panda bahwa itu adalah bingkai datanya sendiri (dan bukan potongan) dengan menggunakanMelakukan ini akan memperbaiki kesalahan Anda. Saya akan memberikan contoh singkat untuk membantu menjelaskan hal di atas karena saya telah memperhatikan banyak pengguna yang bingung dengan panda dalam aspek ini.
Contoh dengan data yang dibuat-buat
Jadi di atas berfungsi seperti yang kami harapkan! Sekarang mari kita coba contoh yang mencerminkan apa yang Anda coba lakukan dengan data Anda.
Sepertinya kita mengalami kesalahan yang sama! Tapi itu berubah
df_q
seperti yang kami harapkan! Ini karenadf_q
adalah potongan daridf
jadi, meskipun kita menggunakan .loc []df_q
pandas memperingatkan kita bahwa itu tidak akan menyebarkan perubahan menjadidf
. Untuk menghindari hal ini, kita perlu lebih eksplisit dan mengatakan bahwadf_q
adalah kerangka datanya sendiri, terpisah daridf
dengan menyatakannya secara eksplisit.Mari kita mulai kembali dari
df_q
tetapi gunakan.copy()
kali ini.Ini berfungsi tanpa kesalahan karena kami telah memberi tahu panda bahwa
df_q
terpisah daridf
Jika Anda sebenarnya ingin perubahan ini ke
df_c
menyebar hinggadf
poin lain sepenuhnya dan akan menjawab jika Anda mau.