import pandas as pd
import numpy as np
df = pd.DataFrame([
[100, 'm1', 1, 4],
[200, 'm2', 7, 5],
[120, 'm1', 4, 4],
[240, 'm2', 8, 5],
[300, 'm3', 5, 4],
[330, 'm3', 2, 4],
[350, 'm3', 11, 4],
[200, 'm4', 9, 4]],
columns=['Col1', 'Col2', 'Col3', 'Col4'])
Я хочу сгруппировать данные в две группы на основе группы Col2. Однако первому совпадению должно быть присвоено одно значение, а остальным совпадениям должно быть присвоено другое значение. Ралф помог мне создать функцию
def my_function(x, val):
if x.shape[0]==1:
if x.iloc[0]>val:
return 'high'
else:
return 'low'
if x.iloc[0]>val and any(i<=val for i in x.iloc[1:]):
return 'high'
elif x.iloc[0]>val:
return 'med'
elif x.iloc[0]<=val:
return 'low'
else:
return np.nan
и затем
df['Col5'] = df.sort_values(['Col2','Col1']).groupby('Col2')['Col3'].transform(my_function, (4))
Однако мне нужны две модификации функции. Вместо val он примет соответствующее значение из Col 4, а затем вернет одно значение (например, "low" для первого совпадения в группе (на основе отсортированного col1), а затем скажем "low_red" для остальной части совпадений в группе.
Итак, мой вопрос в том, как изменить функцию для этого?
Мои данные:
Col1 Col2 Col3 Col4
100 m1 1 4
200 m2 7 5
120 m1 4 4
240 m2 8 5
300 m3 5 4
330 m3 2 4
350 m3 11 4
200 m4 9 4
Ожидаемый результат:
Col1 Col2 Col3 Col4 Col 5
100 m1 1 4 low
200 m2 7 5 med
120 m1 4 4 low_red
240 m2 8 5 med_red
300 m3 5 4 high
330 m3 2 4 high_red
350 m3 11 4 high_red
200 m4 9 4 high
Вы можете создать функцию более высокого уровня (позвоните на нее my_function()
), которая вызывается функцией transform()
, которая затем вызывает функцию нижнего уровня (пусть называет ее deeper_logic()
), которая применяет предыдущую логику, изложенную в вашем вопросе, например:
def my_function(group):
val = df.iloc[group.index]['Col4']
value = deeper_logic(group.iloc[0], val.iloc[0], group)
return [value if i==0 else value + '_red' for i in range(group.shape[0])]
def deeper_logic(x, val, group):
if group.shape[0]==1:
if x>val:
return 'high'
else:
return 'low'
if x>val and any(i<=val for i in group.iloc[1:]):
return 'high'
elif x>val:
return 'med'
elif x<=val:
return 'low'
else:
return np.nan
df['Col5'] = df.sort_values(['Col2','Col1']).groupby('Col2')['Col3'].transform(my_function)
Это дает:
Col1 Col2 Col3 Col4 Col5
0 100 m1 1 4 low
1 200 m2 7 5 med
2 120 m1 4 4 low_red
3 240 m2 8 5 med_red
4 300 m3 5 4 high
5 330 m3 2 4 high_red
6 350 m3 11 4 high_red
7 200 m4 9 4 high
Обратите внимание, что transform()
работает с последовательностью и возвращает NDFrame с подобным индексом, который является результатом, который мы хотим (т.е. Сохраняем индекс исходного фрейма). Таким образом, мы можем назвать transform()
с нашей Col3
колонке, а затем извлечь соответствующие Col4
значения столбцов из исходного индекса с использованием iloc
в вызываемой функции от transform()
.