#python #pandas
#python #pandas
Вопрос:
Мне нужно очистить довольно много столбцов в фрейме данных pandas; поэтому я определил и использовал несколько функций с помощью метода apply для столбцов фрейма данных.
Фиктивный пример:
def fn_a(x):
if x<50:
return 'OK'
else:
return 'not OK'
def fn_b(x):
if x<=40:
return 'too small'
elif x>40 and x<70:
return 'just right'
else:
return 'too high'
df = pd.DataFrame(np.random.randint(0, 100, size=(5, 2)), columns=['a','b'])
df['a'] = df['a'].apply(fn_a)
df['b'] = df['b'].apply(fn_b)
Есть ли способ применить только одну функцию, т. Е. Определить Одну fn()
функцию и передать ее в метод apply вместо перехода по столбцам по столбцам? Другими словами, что я должен добавить fn
, чтобы
def fn(x):
...
df = df.apply(fn)
достаточно?
Комментарии:
1. Вам лучше использовать векторизацию для повышения производительности….
2. Но ваши две функции разные, как вы можете программно закодировать это в одну функцию? Или вы хотите объединить оба
fn_a
иfn_b
в одну функцию с помощью оператора if?3. Для функции в примере вы не должны использовать
apply
вообще. Достаточно ли близок пример к вашим реальным функциям?4. @DYZ Они похожи по духу; в основном объединяют кучу разных значений под определенным количеством общих терминов. Должен ли я использовать
np.where
здесь? Почему бы и нетapply
?5. @itaishz да, мой вопрос заключается в объединении нескольких операторов if-else (специфичных для конкретных столбцов) в рамках одной функции и применении ее ко всему фрейму данных.
Ответ №1:
Воспроизводимые данные:
np.random.seed(0)
df = pd.DataFrame(np.random.randint(0, 100, size=(5, 2)), columns=['a','b'])
a b
0 44 47
1 64 67
2 67 9
3 83 21
4 36 87
Использование pandas применяется:
Если вы действительно хотите использовать apply для этого, вы можете установить axis=1
и получить имя столбца с x[colname]
указанием, где x
находится ваша текущая строка:
def fn_a(x):
x['a'] = 'OK' if x['a'] < 50 else 'not OK'
if x['b'] <= 40:
x['b'] = 'too small'
elif x['b'] > 40 and x['b'] < 70:
x['b'] = 'just right'
else:
x['b'] = 'too high'
return x
df = df.apply(fn_a, axis=1)
print(df)
Вывод:
a b
0 OK just right
1 not OK just right
2 not OK too small
3 not OK too small
4 OK too high
Использование векторизованного подхода:
Вы можете рассмотреть возможность использования np.where
и np.select
. Кроме того, взгляните на pd.cut
. Вы можете установить функцию для обновления фрейма данных на месте с помощью:
def fn(df):
df['a'] = np.where(df.a.lt(50), 'OK', 'not OK')
df['b'] = np.select(
condlist=[df.b.le(40), df.b.gt(40) amp; df.b.lt(70)],
choicelist=['too small', 'just right'],
default='too high'
)
fn(df)
print(df)
Выход:
a b
0 OK just right
1 not OK just right
2 not OK too small
3 not OK too small
4 OK too high
Если вы не хотите изменять фрейм данных на месте, создайте копию внутри функции, измените скопированный фрейм данных, а затем верните его:
def fn(df):
df = df.copy()
df['a'] = np.where(df.a.lt(50), 'OK', 'not OK')
df['b'] = np.select(
condlist=[df.b.le(40), df.b.gt(40) amp; df.b.lt(70)],
choicelist=['too small', 'just right'],
default='too high'
)
return df
df = fn(df)
print(df)
которая возвращает тот же результат.
Ответ №2:
Попробуйте:
def fn(x1, x2):
return [fn_a(x1), fn_b(x2)]
df[['c', 'd']] = df.apply(lambda row: fn(row.a, row.b), axis=1).values.tolist()