==
тесты для ссылочного равенства (независимо от того, являются ли они одним и тем же объектом).
.equals()
тесты для равенства значений (независимо от того, являются ли они логически «равными»).
Objects.equals () проверяет наличие null
перед вызовом .equals()
, поэтому вам не нужно (доступно с JDK7, также доступным в Guava ).
String.contentEquals () сравнивает содержимое String
с содержимым любого CharSequence
(доступно с Java 1.5).
Следовательно, если вы хотите проверить, имеет ли две строки одно и то же значение, вы, вероятно, захотите использовать Objects.equals()
.
// These two have the same value
new String("test").equals("test") // --> true
// ... but they are not the same object
new String("test") == "test" // --> false
// ... neither are these
new String("test") == new String("test") // --> false
// ... but these are because literals are interned by
// the compiler and thus refer to the same object
"test" == "test" // --> true
// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true
// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true
Вы почти всегда хотите использовать Objects.equals()
. В редкой ситуации, когда вы знаете, что имеете дело с интернированными строками, вы можете использовать ==
.
Из JLS 3.10. 5. Строковые литералы :
Кроме того, строковый литерал всегда ссылается на тот же экземпляр класса
String
. Это связано с тем, что строковые литералы, или, в более общем смысле, строки, которые являются значениями константных выражений ( §15.28 ), «интернированы», чтобы обмениваться уникальными экземплярами, используя методString.intern
.. Подобные примеры также можно найти в JLS 3.10.5-1 .
В целом точка SettingWithCopyWarning
должна показывать пользователям (и другим пользователям), что они могут работать на копии, а не на оригинале, как они думают. Там есть ложные срабатывания (IOW вы знаете, что делаете, поэтому ok ). Одна из возможностей - просто отключить (по умолчанию предупреждение warn ), как предлагает @Garrett.
Ниже приведено значение для каждого параметра.
In [1]: df = DataFrame(np.random.randn(5,2),columns=list('AB'))
In [2]: dfa = df.ix[:,[1,0]]
In [3]: dfa.is_copy
Out[3]: True
In [4]: dfa['A'] /= 2
/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_index,col_indexer] = value instead
#!/usr/local/bin/python
Вы можете установить флаг is_copy
на False
, который эффективно отключит проверку * для этого объекта``
In [5]: dfa.is_copy = False
In [6]: dfa['A'] /= 2
Если вы копируете текст, то вы знаете, что вы делают , поэтому дальнейшее предупреждение не будет.
In [7]: dfa = df.ix[:,[1,0]].copy()
In [8]: dfa['A'] /= 2
Код, который OP показывает выше, в то время как законный, и, вероятно, что-то, что я делаю, является технически обоснованным для этого предупреждения , а не ложным положительным. Другой способ not иметь предупреждение - выполнить операцию выбора через reindex
, например
quote_df = quote_df.reindex(columns=['STK',.......])
Или,
quote_df = quote_df.reindex(['STK',.......], axis=1) # v.0.21
Когда вы идете и делаете что-то вроде этого:
quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]
pandas.ix
в этом случае возвращает новый, автономный формат данных.
Любые значения, которые вы решите изменить в этом фрейме данных, не изменят исходный фрейм.
Это то, что панды пытаются вас предупредить.
.ix
- плохая идея Объект .ix
пытается сделать больше чем одно, а для любого, кто прочитал что-нибудь о чистом коде, это сильный запах.
Учитывая этот фрейм данных:
df = pd.DataFrame({"a": [1,2,3,4], "b": [1,1,2,2]})
Два поведения:
dfcopy = df.ix[:,["a"]]
dfcopy.a.ix[0] = 2
Поведение одно: dfcopy
теперь является автономным фреймворком данных. Изменение этого параметра не изменится df
df.ix[0, "a"] = 3
Поведение два: это изменяет исходный фрейм.
.loc
вместо Разработчики pandas признали что объект .ix
был довольно вонючим [спекулятивно] и таким образом создал два новых объекта, которые помогают при вступлении и назначении данных. (Другое значение .iloc
)
.loc
выполняется быстрее, потому что он не пытается создать копию данных.
.loc
предназначен для изменения существующего (f17)
.loc
является предсказуемым, он имеет одно поведение.
Что вы делаете в своем коде Например, загружается большой файл с большим количеством столбцов, а затем изменяется его на меньший размер.
Функция pd.read_csv
может помочь вам с большим количеством этого, а также сделать загрузку файла намного быстрее .
Итак, вместо этого
quote_df = pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
quote_df.rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]
Сделайте это
columns = ['STK', 'TPrice', 'TPCLOSE', 'TOpen', 'THigh', 'TLow', 'TVol', 'TAmt', 'TDate', 'TTime']
df = pd.read_csv(StringIO(str_of_all), sep=',', usecols=[0,3,2,1,4,5,8,9,30,31])
df.columns = columns
. Это будет читать только интересующие вас столбцы и назовите их правильно , Не нужно использовать объект зла .ix
для создания магического материала.
.iloc
. Это два основных метода индексирования структур данных панд. Подробнее в документации.
– Ninjakannon
13 May 2017 в 15:02
Вы можете избежать всей этой проблемы, я полагаю:
return (
pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
.rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
.ix[:,[0,3,2,1,4,5,8,9,30,31]]
.assign(
TClose=lambda df: df['TPrice'],
RT=lambda df: 100 * (df['TPrice']/quote_df['TPCLOSE'] - 1),
TVol=lambda df: df['TVol']/TVOL_SCALE,
TAmt=lambda df: df['TAmt']/TAMT_SCALE,
STK_ID=lambda df: df['STK'].str.slice(13,19),
STK_Name=lambda df: df['STK'].str.slice(21,30)#.decode('gb2312'),
TDate=lambda df: df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10]),
)
)
Использование Assign. Из документации : Назначьте новые столбцы в DataFrame, возвращая новый объект (копию) со всеми исходными столбцами в дополнение к новым.
См. статью Тома Аугспургера о цепочке методов в пандах: https://tomaugspurger.github.io/method-chaining
Это должно работать:
quote_df.loc[:,'TVol'] = quote_df['TVol']/TVOL_SCALE
Для меня эта проблема возникла в следующем упрощенном & lt; пример. И я также смог его решить (надеюсь, с правильным решением):
старый код с предупреждением:
def update_old_dataframe(old_dataframe, new_dataframe):
for new_index, new_row in new_dataframe.iterrorws():
old_dataframe.loc[new_index] = update_row(old_dataframe.loc[new_index], new_row)
def update_row(old_row, new_row):
for field in [list_of_columns]:
# line with warning because of chain indexing old_dataframe[new_index][field]
old_row[field] = new_row[field]
return old_row
Это напечатало предупреждение для строки old_row[field] = new_row[field]
Поскольку строки в методе update_row на самом деле являются типом Series
, я заменил строку:
old_row.at[field] = new_row.at[field]
, т.е. метод для доступа / поиска для Series
. Несмотря на то, что оба работают очень хорошо, и результат тот же, таким образом, мне не нужно отключать предупреждения (= держать их для других проблем с индексацией цепочки где-то еще).
Надеюсь, это может кому-то помочь.
Чтобы устранить все сомнения, моим решением было сделать глубокую копию среза вместо обычной копии. Это может быть неприменимо в зависимости от вашего контекста (ограничения / размер памяти среза, потенциал для снижения производительности - особенно если копия происходит в цикле, как это было для меня и т. Д.)
To ясно, вот предупреждение, которое я получил:
/opt/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:54:
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
У меня возникли сомнения в том, что предупреждение было выброшено из-за столбца, который я бросал на копию фрагмента. Хотя технически не пыталось установить значение в копии среза, это все еще было модификацией копии среза. Ниже приведены (упрощенные) шаги, которые я предпринял для подтверждения подозрения, я надеюсь, что это поможет тем из нас, кто пытается понять это предупреждение.
Мы знали это уже, но это здоровое напоминание. Это NOT , о чем предупреждает.
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1
A B
0 111 121
1 112 122
2 113 123
>> df2 = df1
>> df2
A B
0 111 121
1 112 122
2 113 123
# Dropping a column on df1 affects df2
>> df1.drop('A', axis=1, inplace=True)
>> df2
B
0 121
1 122
2 123
Возможно, чтобы изменения, сделанные на df1, влияли на df2
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1
A B
0 111 121
1 112 122
2 113 123
>> import copy
>> df2 = copy.deepcopy(df1)
>> df2
A B
0 111 121
1 112 122
2 113 123
# Dropping a column on df1 does not affect df2
>> df1.drop('A', axis=1, inplace=True)
>> df2
A B
0 111 121
1 112 122
2 113 123
Это на самом деле иллюстрирует предупреждение.
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1
A B
0 111 121
1 112 122
2 113 123
>> df2 = df1
>> df2
A B
0 111 121
1 112 122
2 113 123
# Dropping a column on df2 can affect df1
# No slice involved here, but I believe the principle remains the same?
# Let me know if not
>> df2.drop('A', axis=1, inplace=True)
>> df1
B
0 121
1 122
2 123
Возможно, чтобы изменения, сделанные на df2, влияли на df1
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]}
>> df1 = pd.DataFrame(data1)
>> df1
A B
0 111 121
1 112 122
2 113 123
>> import copy
>> df2 = copy.deepcopy(df1)
>> df2
A B
0 111 121
1 112 122
2 113 123
>> df2.drop('A', axis=1, inplace=True)
>> df1
A B
0 111 121
1 112 122
2 113 123
Приветствия!
Если вы назначили срез переменной и хотите установить эту переменную следующим образом:
df2 = df[df['A'] > 2]
df2['B'] = value
И вы не хотите использовать решение Jeffs, потому что ваше вычисление состояния df2
длится или по какой-либо другой причине, вы можете использовать следующее:
df.loc[df2.index.tolist(), 'B'] = value
df2.index.tolist()
возвращает индексы из всех записей в df2, которые затем будут использоваться для установки столбца B в оригинале dataframe.
.ix
, улучшенные.iloc
и т. Д.) Могут определенно рассматриваться как «основной способ». без предупреждения, непрестанно о других путях. Вместо этого пусть они будут взрослыми, и если они захотят сделать прикованное назначение, пусть будет так. Мои два цента в любом случае. Здесь часто встречаются недовольные комментарии от разработчиков Pandas, когда прикомандированные назначения будут работать для решения проблемы, но не будут рассматриваться как «первичные», способ сделать это. – ely 17 December 2013 в 23:000.16
я вижу гораздо больше ложных срабатываний, проблема с ложными срабатываниями - это то, что вы учитесь игнорировать его, хотя иногда это и является законным. – dashesy 6 July 2015 в 21:58undefined
. Если что-нибудь, то он должен выкинуть ошибку (во избежание ошибок, увиденных вC
), так какapi
заморожен, то текущее поведение предупреждения имеет смысл для обратной совместимости. И я сделаю их бросить, чтобы поймать их как ошибки в моем производственном коде (warnings.filterwarnings('error', r'SettingWithCopyWarning
). Также предложение использовать.loc
иногда также не помогает (если оно находится в группе). – dashesy 7 July 2015 в 18:50