Панды вычисляют сумму нескольких столбцов с учетом нескольких условий
У меня есть широкая таблица в следующем формате (до 10 человек):
person1_status | person2_status | person3_status | person1_type | person_2 type | person3_type
0 | 1 | 0 | 7 | 4 | 6
Где статус может быть 0 или 1 (первые 3 столбца).
Где тип может быть # в диапазоне 4-7. Значение здесь соответствует другой таблице, которая указывает значение в зависимости от типа. Так...
Type | Value
4 | 10
5 | 20
6 | 30
7 | 40
Мне нужно рассчитать два столбца, "A" и "B", где:
- A - сумма значений типа каждого человека (в этом ряду), где status = 0.
- B - сумма значений типа каждого человека (в этом ряду), где статус = 1.
Например, результирующие столбцы "A" и "B" будут выглядеть следующим образом:
A | B
70 | 10
Объяснение этого:
"A" имеет значение 70, потому что person1 и person3 имеют "status" 0 и имеют соответствующий тип 7 и 6 (что соответствует значениям 30 и 40).
Точно так же должен быть другой столбец "B", который имеет значение "10", потому что только person2 имеет статус "1", а их тип - "4" (который имеет соответствующее значение 10).
Это, вероятно, глупый вопрос, но как мне сделать это векторизованным способом? Я не хочу использовать цикл for или что-то еще, так как это будет менее эффективно...
Надеюсь, это имело смысл... кто-нибудь может мне помочь? Я думаю, что я с ума с ума, пытаясь понять это.
Для более простых вычисляемых столбцов мне не нравилось просто np.where, но я немного застрял здесь, поскольку мне нужно вычислить сумму значений из нескольких столбцов при определенных условиях, извлекая эти значения из отдельной таблицы...
надеюсь, что это имело смысл
2 ответа
Используйте метод filter, который будет фильтровать имена столбцов для тех, где в них появляется строка.
Создайте фрейм данных для значений поиска other_table
и установите индекс в качестве столбца типа.
df_status = df.filter(like = 'status')
df_type = df.filter(like = 'type')
df_type_lookup = df_type.applymap(lambda x: other_table.loc[x]).values
df['A'] = np.sum((df_status == 0).values * df_type_lookup, 1)
df['B'] = np.sum((df_status == 1).values * df_type_lookup, 1)
Полный пример ниже:
Создать поддельные данные
df = pd.DataFrame({'person_1_status':np.random.randint(0, 2,1000) ,
'person_2_status':np.random.randint(0, 2,1000),
'person_3_status':np.random.randint(0, 2,1000),
'person_1_type':np.random.randint(4, 8,1000),
'person_2_type':np.random.randint(4, 8,1000),
'person_3_type':np.random.randint(4, 8,1000)},
columns= ['person_1_status', 'person_2_status', 'person_3_status',
'person_1_type', 'person_2_type', 'person_3_type'])
person_1_status person_2_status person_3_status person_1_type \
0 1 0 0 7
1 0 1 0 6
2 1 0 1 7
3 0 0 0 7
4 0 0 1 4
person_3_type person_3_type
0 5 5
1 7 7
2 7 7
3 7 7
4 7 7
Делать other_table
other_table = pd.Series({4:10, 5:20, 6:30, 7:40})
4 10
5 20
6 30
7 40
dtype: int64
Отфильтруйте столбцы состояния и типа в их собственные рамки данных.
df_status = df.filter(like = 'status')
df_type = df.filter(like = 'type')
Сделать таблицу поиска
df_type_lookup = df_type.applymap(lambda x: other_table.loc[x]).values
Применить матричное умножение и суммирование по строкам.
df['A'] = np.sum((df_status == 0).values * df_type_lookup, 1)
df['B'] = np.sum((df_status == 1).values * df_type_lookup, 1)
Выход
person_1_status person_2_status person_3_status person_1_type \
0 0 0 1 7
1 0 1 0 4
2 0 1 1 7
3 0 1 0 6
4 0 0 1 5
person_2_type person_3_type A B
0 7 5 80 20
1 6 4 20 30
2 5 5 40 40
3 6 4 40 30
4 7 5 60 20
Рассмотреть кадр данных df
mux = pd.MultiIndex.from_product([['status', 'type'], ['p%i' % i for i in range(1, 6)]])
data = np.concatenate([np.random.choice((0, 1), (10, 5)), np.random.rand(10, 5)], axis=1)
df = pd.DataFrame(data, columns=mux)
df
Как это структурировано, мы можем сделать это для type == 1
df.status.mul(df.type).sum(1)
0 0.935290
1 1.252478
2 1.354461
3 1.399357
4 2.102277
5 1.589710
6 0.434147
7 2.553792
8 1.205599
9 1.022305
dtype: float64
и для type == 0
df.status.rsub(1).mul(df.type).sum(1)
0 1.867986
1 1.068045
2 0.653943
3 2.239459
4 0.214523
5 0.734449
6 1.291228
7 0.614539
8 0.849644
9 1.109086
dtype: float64
Вы можете получить ваши столбцы в этом формате, используя следующий код
df.columns = df.columns.str.split('_', expand=True)
df = df.swaplevel(0, 1, 1)