# import packages, set nan
import pandas as pd
import numpy as np
nan = np.nan
Проблема
У меня есть фрейм данных с определенным количеством наблюдений в виде столбцов, измерений в виде строк. Результаты наблюдений равны A, B, C, D ...
. В нем также есть столбец категория , который обозначает категорию из измерения . Категории: a, b, c, d ...
. Если столбец содержит nan
в строке, это означает, что наблюдение во время этого измерения не проводилось (поэтому nan
не observation
, это его отсутствие). An MRE :
data = {'observation0': ['A','A','A','A','B'],'observation1': ['B','B','B','C',nan], 'category': ['a', 'b', 'c','a','b']}
df = pd.DataFrame.from_dict(data)
df
выглядит так:
I would like to count how many times each observational result (ie A, B, C, D...
) is observed using each category of measurement (ie a, b, c, d ...
).
I would like to get:
obs_A_in_cat_a 2
obs_A_in_cat_b 1
obs_A_in_cat_c 1
obs_B_in_cat_a 1
obs_B_in_cat_b 2
obs_B_in_cat_c 1
obs_C_in_cat_a 1
obs_C_in_cat_b 0
obs_C_in_cat_c 0
Observation A
appears in rows with index
0
and 3
(see above df) while the measurement category
is a
, so obs_A_in_cat_a
is 2
. Observation A
appears only once (row index
1
) in a measurement with category
: b
, so obs_A_in_cat_b
is 1
, and so on.
My solution
First I gather the outcomes of observations, стараясь не включать nans :
observations = pd.unique(pd.concat([df[col] for col in df.columns if 'observation' in col]).dropna())
Различные категории, к которым они принадлежат:
categories = pd.unique(df['category'])
Затем повторите наблюдения. Если он полагается на , это ,
for observation in observations:
for category in categories:
df['obs_'+observation+'_in_cat_'+category]=\
df.apply(lambda row: int(observation in [row[col]
for col in df.columns
if 'observation' in col]
and row['category'] == category),axis=1)
Лямбда-функция проверяет, появляется ли observation
в каждом row
, и что измерение находится в категории, которая в настоящее время рассматривается в итерация. Создаются новые столбцы с заголовками obs_OBSERVATION_in_cat_CATEGORY, где OBSERVATION
равно A, B, C, D ...
, CATEGORY
равно a, b, c, d ...
Если observationX
в categoryY
было сделано во время измерения, obs_OBSERVATIONX_in_cat_CATEGORYY
равно 1
в строка, соответствующая этому измерению, иначе это 0
.
Результирующий df
(его части) выглядит так:
Finish using sum()
ming значения вновь созданных столбцов, выбирая те, которые имеют понимание условного списка :
df[[col for col in df.columns if '_in_cat_' in col]].sum()
Это дает мне результат, который я хотел бы получить, как показано выше. Вся записная книжка здесь .
Вопрос
Кажется, этот метод работает, но он слишком медленный, чтобы его можно было легко применить в реальной жизни. Как я могу сделать это быстрее? Я ищу что-то вроде:
how_many_times_each_observation_was_made_using_each_category_of_measurement(
df,
list_of_observation_columns,
category_column)