xref # 11173
или ИМХО просто замените на pd.to_datetime,pd.to_timedelta,pd.to_numeric
.
Иметь автоугадателя - это нормально, но когда вы пытаетесь принудить, все может пойти наперекосяк.
cc @bashtage
@jorisvandenbossche @shoyer @TomAugspurger @sinhrks
Уже есть _convert, которого можно было бы продвигать.
Пт, 2 октября 2015 г., 10:16 Джефф Рэйбэк (Jeff Reback) [email protected] написал:
cc @bashtage https://github.com/bashtage
@jorisvandenbossche https://github.com/jorisvandenbossche @shoyer
https://github.com/shoyer @TomAugspurger
https://github.com/TomAugspurger @sinhrks https://github.com/sinhrks-
Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/pydata/pandas/issues/11221#issuecomment -145033282.
Преимущество хорошо разработанного convert
том, что он работает с DataFrames. Все to_*
предназначены только для одномерных типов.
@bashtage о, я согласен.
Проблема в том, что coerce
, вы должны в основном частично не приводить к автоматическому принуждению и поэтому оставлять неоднозначные вещи на усмотрение пользователя (через 1-мерное использование pd.to_*
). Но если предположить, что мы это сделаем, тогда да, вы можете заставить это работать.
Я просто подумал о случае, когда я импортировал данные, которые должны быть числовыми, в DF, но в нем есть несколько смешанных символов, и мне нужны только числа или NaN. Этот тип преобразования - то, что я в конечном итоге хотел, когда я начал смотреть на convert_objects
когда я был удивлен, что запрос coerce
всех строк не привел к NaN.
но проблема в том, что смешанное логическое / наноразмерное значение неоднозначно (так что, возможно, просто нужно `` обработать '' это)
Некоторые комментарии / наблюдения:
convert_objects
больше, чем convert
, потому что он более четко говорит о том, что он делает: попробуйте преобразовать столбцы с типами объектов во встроенный dtype (convert является довольно общим).convert_objects
для нового converts
. Я думаю, что технически возможно отказаться от старых _keywords_ (а не от функции) в пользу новых ключевых слов. (на самом деле оригинальный подход в обратном PR).convert_objects
полезна (как уже было сказано выше: вы можете делать что-то вроде to_datetime/to_numeric/..
на фреймах данных). Использование функций to_..
для каждой серии по отдельности всегда будет предпочтительным решением для надежного кода, но до тех пор, пока convert_objects
очень четко определено (теперь есть некоторые странные несоответствия), я думаю, что это так. полезно иметь это. Было бы очень хорошо, если бы это можно было просто реализовать в терминах методов to_..
.
def convert_objects(self, numeric=False, datetime=False, timedelta=False, coerce=False):
for each column:
if numeric:
pd.to_numeric(self, coerce=coerce)
elif datetime:
pd.to_datetime(self, coerce=coerce)
elif timedelta:
pd.to_timedelta(self, coerce=coerce)
convert_objects
сейчас полезна, заключается именно в том, что у него есть дополнительное «правило», которого нет в методах to_..
: _only преобразовать столбец, если есть по крайней мере одно значение, которое можно преобразовать_.`` ''
В [2]: df = pd.DataFrame ({'int_str': ['1', '2'], 'real_str': ['a', 'b']})
В [3]: df.convert_objects (convert_numeric = True)
Из [3]:
int_str real_str
0 1 а
1 2 б
В [4]: df.convert_objects (convert_numeric = True) .dtypes
Из [4]:
int_str int64
объект real_str
dtype: объект
`` ''
и не дает:
Out[3]:
int_str real_str
0 1 NaN
1 2 NaN
что было бы бесполезно (хотя, возможно, более предсказуемо). Тот факт, что не всегда принуждение к NaN, считался ошибкой, для которой @bashtage сделал PR (а для to_numeric
также логично, что он возвращает NaN). Но это сделало convert_objects
менее полезным (так что в конце концов его отменили).
Поэтому я думаю, что в этом случае нам придется отклониться от поведения to_..
Возможно, это может быть дополнительным параметром для convert/convert_objects
: нужно ли приводить неконвертируемые столбцы к NaN или нет (что означает: столбцы, для которых нет хотя бы одного конвертируемого элемента и приведет к полному столбцу NaN) . @bashtage, тогда вы можете иметь
Хорошо, вопрос в том, должны ли мы отказаться от convert_objects thrn?
Я на самом деле думаю, что convert - это гораздо лучшее название, и мы, безусловно, могли бы добавить параметры, которые вы описываете, чтобы сделать его более полезным
convert_objects
просто кажется плохой функцией API, поскольку у него есть зависимость от пути, где он
пытается преобразовать в тип
пытается преобразовать в тип b в случае неудачи, но не в случае успеха
пытается преобразовать в тип c - a и b терпят неудачу, но не в случае успеха
В лучшем дизайне будет преобразован только один тип, что устранит любую двусмысленность, если некоторые данные когда-либо будут преобразованы в более чем один тип. to to_*
вроде как добираются туда, с оговоркой, что они работают столбец за столбцом.
Да здравствует convert_objects!
может быть, нам нужно в документации несколько примеров, показывающих:
df.apply(pd.to_numeric)
и тому подобное (что эффективно / безопаснее) заменяет .convert_objects
Всем привет,
В настоящее время я использую convert_objects во многих своих кодах, и я думаю, что эта функция очень полезна при импорте наборов данных, которые могут каждый день различаться с точки зрения состава столбцов. Действительно ли необходимо отказаться от него или есть шанс сохранить его?
Большое спасибо,
Умберто
.convert_objects
было неоднозначным по своей сути, и несколько версий назад оно устарело. см. документацию здесь, чтобы узнать, как явно выполнить преобразование объекта.
Я согласен с @jreback - convert_objects
был полон магии, и ему было трудно угадать поведение, которое было несовместимым для разных целей конверсии (например, числа не были принудительными, если все не были числами, даже если было сказано принудить).
Хорошо спроектированный отгадыватель с ясным, простым правилом и без возможности принуждения может быть полезен, но нетрудно написать свое собственное с вашим любимым набором правил.
К вашему сведению, параметры convert all (errors = 'coerce') и ignore (errors = 'ignore') в .to_numeric являются проблемой в файлах данных, содержащих столбцы строк, которые вы хотите сохранить, и столбцы строк, которые на самом деле являются числами, выраженными в научная нотация (например, 6.2e + 15), которая требует «принуждения» для преобразования из строк в float64.
В (устаревшем) файле convert.py есть удобная функция мягкого преобразования, которая проверяет, производит ли принудительное преобразование все NaN (например, строку, которую вы хотите сохранить), а затем отклоняет преобразование всего столбца.
Четвертый вариант ошибки, такой как «мягкое принуждение», будет улавливать числа в научной нотации, не переводя все строки в NaN.
На данный момент моя работа:
for col in df.columns:
converted = pd.to_numeric(df[col],errors='coerce')
df[col] = converted if not pd.isnull(converted).all() else df[col]
Преимущество convert_objects
перед различными методами to_*
заключается в том, что вам не нужно заранее знать типы данных. Как сказал @usagliaschi , у вас могут быть разнородные данные, и вам нужна одна функция для их обработки. Это как раз моя нынешняя ситуация.
Есть ли какая-либо замена функции, которая будет соответствовать этой функциональности, в частности, вывести даты / время?
xref https://github.com/pandas-dev/pandas/pull/15757#issuecomment -288090118
Я думаю, что стоило бы раскрыть то, что новый API-интерфейс soft convert 0.20 (я не рассматривал его подробно), сославшись на него в сообщении depr convert_objects, а затем, если возможно, отложить convert_objects до следующей версии.
Я говорю это, потому что знаю, что есть люди (например, я), которые проигнорировали сообщение convert_objects depr в нескольких случаях, в частности, работая с данными, где вы не обязательно знаете столбцы. Реальный экземпляр:
df = pd.read_html(source)[0] # poorly formatted table, everything inferred to object
# exact columns can vary
df.columns = df.loc[0, :]
df = df.drop(0).dropna()
df = df.convert_objects()
Посмотрев на это еще раз, я понимаю, что df.apply(lambda x: pd.to_numeric(x, errors='ignore'))
также будет работать нормально в этом случае, но это было не сразу очевидно, и я не уверен, что мы достаточно держались за руки (из-за отсутствия лучшего термина), чтобы помочь людям перейти.
ЕСЛИ мы решим предоставить «объекты мягкого преобразования», хотели бы мы, чтобы это называлось .covert_objects()
? или другое имя, может быть .convert()
? (например, вместо того, чтобы удалить устаревание, мы просто изменили его - что, вероятно, больше нарушает обратную совместимость).
xref # 15550
поэтому я думаю, что решение этого может быть:
.to_*
в Series
(# 15550).to_*
к DataFrame
soft
тогда достаточно просто сделать:
df.to_numeric(errors='soft')
если вы действительно действительно хотите преобразовать вещи в исходный .convert_object()
.
df.to_datetime(errors='soft').to_timedelta(errors='soft').to_numeric(errors='soft')
И я полагаю, что мог бы предложить удобную функцию для этого:
df.to_converted()
df.convert()
(возможно, слишком общий)df.convert_objects()
(воскресить)df.to_just_figure_this_out()
Я думаю, что наиболее полезная функция мягкого преобразования могла бы иметь либо возможность упорядочить правила to_*
, например, числовое-дата-время или время-дата-числовое, поскольку иногда есть данные, которые могут быть интерпретированы как несколько типов. По крайней мере, так было в случае с convert_objects
. В качестве альтернативы можно было выбрать только подмножество фильтров, например, учитывать только числовую дату.
Я согласен, что расширение to_*
для правильной работы с DataFrames было бы полезно.
Спасибо @jreback - мне нравится добавлять to_...
в DataFrame
api, хотя, возможно, стоит выделить варианты использования. Рассмотрим этот плохо сформированный фрейм:
df = pd.DataFrame({'num_objects': [1, 2, 3], 'num_str': ['1', '2', '3']}, dtype=object)
df
Out[2]:
num_objects num_str
0 1 1
1 2 2
2 3 3
df.dtypes
Out[3]:
num_objects object
num_str object
dtype: object
Поведение по умолчанию convert_objects
- это только переинтерпретировать целые числа Python в правильный тип int dtype, а не приводить строки. Это поведение, которое я бы очень скучал по убийству convert_objects
, и подозреваю, что другие тоже могут.
df.convert_objects().dtypes
Out[4]:
num_objects int64
num_str object
dtype: object
In [5]: df.apply(pd.to_numeric).dtypes
Out[5]:
num_objects int64
num_str int64
dtype: object
Так стоит ли добавлять convert_pyobjects
(... не люблю это имя) только в этом случае?
infer_python_types
convert_python_types
??
Я думаю, что достаточно просто добавить опцию soft
к errors
чтобы сделать именно это.
Будет ли кастовать pd.Series(['1', '2', '3']).to_numeric(errors='soft')
?
soft
просто вернет [3] (как и coerce
Разница в [4] (в нем серия). Я думаю, soft
вернет [5], а coerce
вернет [4]
In [3]: pd.to_numeric(pd.Series(['1', '2', '3']), errors='coerce')
Out[3]:
0 1
1 2
2 3
dtype: int64
In [4]: pd.to_numeric(pd.Series(['1', '2', 'foo']), errors='coerce')
Out[4]:
0 1.0
1 2.0
2 NaN
dtype: float64
In [5]: pd.to_numeric(pd.Series(['1', '2', 'foo']), errors='ignore')
Out[5]:
0 1
1 2
2 foo
dtype: object
Спасибо за примеры.
Я все еще думаю, что «только преобразование объектов Python без потерь в правильные типы данных» может быть лучше в качестве отдельной операции от to_numeric
? Не было бы способа получить Out[4]
из моего примера выше?
Я не думаю, что возможно преобразование объектов python без потерь в правильные типы dtypes, как правило, хорошо определено. Конечно, есть объекты, которые не имеют собственного представления без потерь (например, str-> float).
Эта только что описанная двусмысленность как раз и является проблемой при написании полезного, правильного и точного конвертера.
Следует ли описывать набор параметров преобразования и правила, которые будут использоваться, до их внедрения? Я думаю, они должны, иначе код по умолчанию будет эталонным набором правил (что было одной из проблем с convert_objects
).
Чтобы было ясно, то, что я имею в виду под преобразованием без потерь, делает именно то, что сделал бы pd.Series([<python objects]>)
- преобразование в numpy dtype, если это возможно, в противном случае оставление как объект.
Я думаю, что смысл convert_objects
и любого его преемника в том, чтобы строго выходить за рамки того, что эти инструменты io будут делать автоматически. IOW, некоторые принуждение некоторых объектов некоторое время имеет важное значение. Старый convert_objects
, например, приводил бы смешанные строки и числа к числам и нулям. Такие инструменты, как read_csv
намеренно не делают этого, поскольку это довольно произвольно.
to_*
довольно точны и делают то, что вы им говорите, даже с не-объектами. Например:
import pandas as pd
import datetime as dt
t = pd.Series([dt.datetime.now(), dt.datetime.now()])
pd.to_numeric(t)
Out[7]:
0 1490739351272159000
1 1490739351272159000
dtype: int64
Я бы предположил, что преемник convert_objects
преобразует только object
dtype
и не будет вести себя подобным образом.
Причина, по которой мне не нравится добавлять функции .to_
качестве метода в DataFrame (или, по крайней мере, не в качестве решения в этом обсуждении), заключается в том, что IMO вы обычно не хотите применять это ко всем столбцам и / или не таким же образом (и если вы этого хотите, вы можете легко использовать подход apply
как вы можете сделать сейчас).
Например, с DataFrame.to_datetime
, я ожидал, что он сделает это для всех столбцов, что означает преобразование числовых столбцов в строковые столбцы. Я не думаю, что обычно это то, что вам нужно.
Поэтому для меня одна из причин использовать метод convert_objects
(независимо от точных деталей поведения) заключается в том, что он будет пытаться преобразовать только фактические столбцы с типом object
dtyped.
хорошо, если мы воскресим это с новой подписью. это актуально.
In [1]: DataFrame.convert_objects?
Signature: DataFrame.convert_objects(self, convert_dates=True, convert_numeric=False, convert_timedeltas=True, copy=True)
Docstring:
Deprecated.
Attempt to infer better dtype for object columns
Parameters
----------
convert_dates : boolean, default True
If True, convert to date where possible. If 'coerce', force
conversion, with unconvertible values becoming NaT.
convert_numeric : boolean, default False
If True, attempt to coerce to numbers (including strings), with
unconvertible values becoming NaN.
convert_timedeltas : boolean, default True
If True, convert to timedelta where possible. If 'coerce', force
conversion, with unconvertible values becoming NaT.
copy : boolean, default True
If True, return a copy even if no copy is necessary (e.g. no
conversion was done). Note: This is meant for internal use, and
should not be confused with inplace.
IIRC @jorisvandenbossche предложил. (с модом).
DataFrame.convert_object(self, datetime=True, timedelta=True, numeric=False, copy=True)
Хотя если все поменять. Тогда, возможно, нам стоит просто переименовать это. (обратите внимание на .convert_object
)
Извините, я просто возвращаюсь к этому, вот предложение о том, как я думаю, это могло бы работать, открытое для предложений по любой части.
0.20.1
- оставьте convert_objects
но обновите сообщение depr новыми методами, которые я буду использовать
0.20.2
- удалить convert_objects
Во-первых, для преобразований, которые представляют собой просто распаковку объектов Python, добавьте новый метод infer_objects
без параметров. Это по существу повторно применяет наш вывод ctor к любым столбцам объекта, и если столбец может быть без потерь распакован в собственный тип, сделайте это, в противном случае оставьте без изменений. Полезно в случайных сценариях, в которых исходный вывод терпит неудачу. Пример:
df = pd.DataFrame({'a': ['a', 1, 2, 3],
'b': ['b', 2.0, 3.0, 4.1],
'c': ['c', datetime.datetime(2016, 1, 1), datetime.datetime(2016, 1, 2),
datetime.datetime(2016, 1, 3)]})
df = df.iloc[1:]
In [194]: df
Out[194]:
a b c
1 1 2 2016-01-01 00:00:00
2 2 3 2016-01-02 00:00:00
3 3 4.1 2016-01-03 00:00:00
In [195]: df.dtypes
Out[195]:
a object
b object
c object
dtype: object
# exactly what convert_objects does in this scenario today!
In [196]: df.infer_objects().dtypes
Out[196]:
a int64
b float64
c datetime64[ns]
dtype: object
Во-вторых, для всех других преобразований добавьте to_numeric
, to_datetime
и to_datetime
в DataFrame
API со следующей подписью. В основном работают так же, как и сегодня, но есть некоторые варианты выбора удобных столбцов. Не уверен в настройках по умолчанию, начиная с наиболее "удобных".
"""
DataFrame.to_...(self, errors='ignore', object_only=True, include=None, exclude=None)
Parameters
------------
errors: {'ignore', 'coerce', 'raise'}
error mode passed to `pd.to_....`
object_only: boolean
if True, only apply inference to object typed columns
include / exclude: column selection
"""
Пример кадра, с тем, что нужно сегодня:
df1 = pd.DataFrame({
'date': pd.date_range('2014-01-01', periods=3),
'date_unconverted': ['2014-01', '2015-01', '2016-01'],
'number': [1, 2, 3],
'number_unconverted': ['1', '2', '3']})
In [198]: df1
Out[198]:
date date_unconverted number number_unconverted
0 2014-01-01 2014-01 1 1
1 2014-01-02 2015-01 2 2
2 2014-01-03 2016-01 3 3
In [199]: df1.dtypes
Out[199]:
date datetime64[ns]
date_unconverted object
number int64
number_unconverted object
dtype: object
In [202]: df1.convert_objects(convert_numeric=True, convert_dates='coerce').dtypes
C:\Users\chris.bartak\AppData\Local\Continuum\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: convert_objects is deprecated. Use the data-type specific converters pd.to_datetime, pd.to_timedelta and pd.to_numeric.
"""Entry point for launching an IPython kernel.
Out[202]:
date datetime64[ns]
date_unconverted datetime64[ns]
number int64
number_unconverted int64
dtype: object
С новым API:
In [202]: df1.to_numeric().to_datetime()
Out[202]:
date datetime64[ns]
date_unconverted datetime64[ns]
number int64
number_unconverted int64
dtype: object
И, честно говоря, меня лично не волнует второй API, мой отказ от отказа от поддержки convert_objects
был полностью основан на отсутствии чего-то вроде infer_objects
Я бы добавил infer_objects()
если правила были кристально ясными и реализация соответствовала описанию. Другой важный вариант использования - это когда в конце получается DF, транспонированный со всеми столбцами объекта, а затем что-то вроде df = df.T.infer_types()
дает
Я думаю, что такие функции, как to_numeric
и т. Д., Не должны использовать методы в фрейме данных, а должны быть просто автономными. Я не думаю, что они используются достаточно часто, чтобы загрязнить
Круто, да, чем больше я думаю, тем меньше думаю, что добавление to_...
в API DataFrame - хорошая идея. С точки зрения infer_objects
impl в основном будет следующим - на основе maybe_convert_objects
, что, как правило, неудивительно (на мой взгляд):
In [251]: from pandas._libs.lib import maybe_convert_objects
In [252]: converter = lambda x: maybe_convert_objects(np.asarray(x, dtype='O'), convert_datetime=True, convert_timedelta=True)
In [253]: converter([1,2,3])
Out[253]: array([1, 2, 3], dtype=int64)
In [254]: converter([1,2,3])
Out[254]: array([1, 2, 3], dtype=int64)
In [255]: converter([1,2,'3'])
Out[255]: array([1, 2, '3'], dtype=object)
In [256]: converter([datetime.datetime(2015, 1, 1), datetime.datetime(2015, 1, 2)])
Out[256]: array(['2015-01-01T00:00:00.000000000', '2015-01-02T00:00:00.000000000'], dtype='datetime64[ns]')
In [257]: converter([datetime.datetime(2015, 1, 1), 'a'])
Out[257]: array([datetime.datetime(2015, 1, 1, 0, 0), 'a'], dtype=object)
In [258]: converter([datetime.datetime(2015, 1, 1), 1])
Out[258]: array([datetime.datetime(2015, 1, 1, 0, 0), 1], dtype=object)
In [259]: converter([datetime.timedelta(seconds=1), datetime.timedelta(seconds=1)])
Out[259]: array([1000000000, 1000000000], dtype='timedelta64[ns]')
In [260]: converter([datetime.timedelta(seconds=1), 1])
Out[260]: array([datetime.timedelta(0, 1), 1], dtype=object)
да, возможно ,_convert_objects - это мягкое преобразование
он будет преобразован только в том случае, если все они строго конвертируемы
В этом случае я мог бы быть на борту с очень простым .infer_objects()
. Думаю, он не примет никаких аргументов?
можно добавить новую функцию и изменить сообщение об устаревании convert_objects, чтобы указать на .infer_objects()
и .to_*
на 0,21, а затем удалить в 1.0
@jreback : Судя по этому разговору, удаление convert_objects
не произойдет в 0.21. Было бы лучше закрыть # 15757 и позволить новому PR занять свое место для реализации infer_objects
(что, кстати, кажется хорошей идеей)?
IIUC, в какой степени infer_objects
просто порт convert_objects
чтобы быть методом DataFrame
(или просто NDFrame
в целом)?
convert_objects
имеет собственную логику и варианты. infer_objects
должен использовать вывод по умолчанию как если бы для DataFrame (но только столбцы объектов).
А, верно, значит, вы имеете в виду, что infer_objects
- это convert_objects
с переданными значениями по умолчанию (более или менее, может быть, некоторые специально настроены для DataFrame
)?
infer_objects
должно иметь параметров, просто выполните мягкое преобразование (в основном это вызовет maybe_convert_objects
с параметрами по умолчанию
О'кей, в этом есть смысл. Я просто пытался понять и сопоставить в уме комментарии, сделанные во время этого обсуждения.
fyi, открыл # 16915 для infer_objects
если кому-то интересно - в частности, если у вас есть пограничные тестовые примеры
Самый полезный комментарий
Да здравствует convert_objects!