Selecionei um subconjunto de colunas numéricas de um banco de dados e quero iterar pelas colunas, selecionando uma target_column
e comparando-a com o resultado de uma operação numérica entre duas outras colunas no dataframe. No entanto, não tenho certeza de como comparar o resultado (por exemplo, col1 * col2 = target_column
).
# For all possible combinations of numeric columns
for col1, col2 in combinations(numeric_cols, 2):
# For a target column in numeric_columns
for target_column in numeric_cols:
# Skip if the target column is one of the relationship columns
if target_column in (col1, col2):
continue
Editar : Eu descobri algo, mas ainda não tenho certeza se esta é a maneira mais eficiente de fazer isso
def analyse_relationships(df):
numeric_cols = df.select_dtypes(include=[np.number])
threshold = 0.001
relationships = []
# For all possible combinations of numeric columns
for col1, col2 in combinations(numeric_cols, 2):
# For a target column in numeric_columns
for target_column in numeric_cols:
# Skip if the target column is one of the relationship columns
if target_column in (col1, col2):
continue
# Calculate different operations
product = numeric_cols[col1] * numeric_cols[col2]
sum_cols = numeric_cols[col1] + numeric_cols[col2]
diff = numeric_cols[col1] - numeric_cols[col2]
if np.allclose(product, numeric_cols[target_column], rtol=threshold):
relationships.append(f"{col1} * {col2} = {target_column}")
elif np.allclose(sum_cols, numeric_cols[target_column], rtol=threshold):
relationships.append(f"{col1} + {col2} = {target_column}")
elif np.allclose(diff, numeric_cols[target_column], rtol=threshold):
relationships.append(f"{col1} - {col2} = {target_column}")
Para resolver seu problema, eu sugiro fortemente que você vetorize seus dados e use o mínimo possível de operações Pandas, já que muitas operações são necessárias e, consequentemente, quanto mais pudermos confiar somente no NumPy, mais rápido o código será executado (o núcleo do NumPy é escrito em C ).
Como há várias operações a serem consideradas (
+
,-
,*
,/
), precisamos calcular cada resultado e compará-lo comtarget_column
, mas podemos ser mais eficientes em termos de espaço usando uma máscara booleana (ou seja, um array NumPy ), que é uma coluna que representa, como um valor booleano, a expressãotarget_column == col1 operation col2
. Observe que, tendo um float possível emdf
, é melhor usarnumpy.isclose()
to , que podemos definir um limite para as operações de float.Seu código poderia ser algo assim (incluí um pequeno exemplo no final):
Saída:
Análise de complexidade
Gostaria de salientar que o código acima tem uma certa complexidade de tempo e pode ser lento quando o número de elementos é grande.
O código acima precisa passar por uma série de ciclos:
numerical_cols
, isto é(m choose 2) = m(m-1)/2 ~ O(m^2)
;target
, ou sejaO(m - 2) = O(m)
;numpy.isclose()
ciclo através de cada elementon
e, portanto, tem complexidade deO(n)
.Considerando esses ciclos, é fácil ver como o código tem complexidade de tempo de
O(m^2 * m * n) = O(n * m^3)
, então o tempo necessário aumentará cubicamente em relação ao número de colunas numéricas e linearmente em relação ao número de elementos em cada coluna.