2016-12-20 2 views
3

У меня есть большой стол в формате следующим образом (до 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', где:

  1. А является сумма значений типа каждого человека (в том строка), где состояние = 0.
  2. в является сумма значений типа каждого человека (в этой строке), где состояние = 1.

Например, результирующие столбцы «A» и «B» будет выглядеть следующим образом:

A | B 
70 | 10 

Объяснение этого:

«А» имеет значение 70, так как лицом1 и person3 имеют «статус "0 и имеют соответствующий тип 7 ​​и 6 (что соответствует значениям 30 и 40).

Аналогичным образом должен быть другой столбец «B», который имеет значение «10», потому что только человек2 имеет статус «1», а их тип «4» (который имеет соответствующее значение 10).

Это, наверное, глупый вопрос, но как это сделать векторным способом? Я не хочу использовать цикл for или что-то еще, так как он будет менее эффективным ...

Я надеюсь, что это имело смысл ... мог ли кто-нибудь мне помочь? Я думаю, что я мертв мозгом, пытаясь понять это.

Для более простых вычисляемых столбцов я уходил только с np.where, но я немного застрял здесь, так как мне нужно вычислить сумму значений из нескольких столбцов при определенных условиях, потянув эти значения из отдельной таблицы. ..

надежда, что имело смысл

+1

Можете ли вы предоставить [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve)? –

+0

Вот пример, который я дал более ясно – shishy

ответ

1

использовать метод фильтр, который будет фильтровать имена столбцов для тех, где появляется строка в них.

Создайте dataframe для значений поиска 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 

Отфильтровывать статус и тип столбцов своих dataframes

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 
+0

Точно, что я хотел, спасибо! Я не знал о команде фильтра, поэтому ... это и функция лямбда сделали ее проще. Очень признателен :). – shishy

0

рассмотреть dataframe 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 

enter image description here

Путь это структурированная мы можем сделать это для 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) 
Смежные вопросы