Loop através de 2 dataframes e modo de tomada de colunas específicas

Aug 27 2020

Dado é df1 (que contém a maioria e os produtos menos vendidos de cada loja):

id   most_sold_A  most_sold_B  most_sold_C  least_sold_A  least_sold_B  least_sold_C
1     1             0           0             0            1             1
2     0             1           0             1            0             0
3     0             1           1             1            0             0

e df2 (que contém a distância entre 2 lojas) também é fornecido:

id1   id2   distance 
1     2      0.5
1     3      3.0
2     3      0.2

O dataframe resultante deve

  1. verifique quais shop_ids estão a 1k de distância de cada shopid
  2. use o modo do most_sold_product sobre todos os concorrentes em 1k
  3. use o modo do least_sold_product sobre todos os concorrentes em 1k

df resultante:

id   most_sold_A  most_sold_B  most_sold_C  least_sold_A  least_sold_B  least_sold_C    /
1     1             0           0             0            1             1
2     0             1           0             1            0             0
3     0             1           1             1            0             0

most_sold_competition_within_1k   least_sold_competition_within_1k
B                                    A
[A,B,C]                              [A,B,C]
B                                    A

EDITAR

df1 = pd.DataFrame([[1,1,0,0,0,1,1],
[2,0,1,0,1,0,0],
[3,0,1,1,1,0,0]],columns = ["id","most_sold_A","most_sold_B","most_sold_C","least_sold_A","least_sold_B","least_sold_C"])
df2 = pd.DataFrame([[1,2,0.5],
[1,3,3.0],
[2,3,0.2]], columns = ["id1","id2","distance"])

Respostas

OmriKaduri Aug 27 2020 at 10:20

Parece que a parte "complicada" é encontrar os concorrentes relevantes para cada loja. Tenho certeza de que existem soluções mais elegantes, mas uma simples é:

def find_competitors(x, df2):
    shops = np.unique(df2[(df2.id1==x.id) | (df2.id2 == x.id)][['id1','id2']])
    competitors = np.delete(shops, np.argwhere(shops == x.id))
    return competitors

df2 = df2[df2.distance<=1]
df1['competitors'] = df1.apply(lambda x: find_competitors(x, df2),axis=1)

Agora, para cada loja, vocês são concorrentes relevantes e podem encontrar a resposta para suas 2 outras perguntas (produtos mais vendidos e menos vendidos dos concorrentes), simplesmente iterando sobre o concorrente de cada loja. Espero que tenha sido claro o suficiente.

ATUALIZAR

Para encontrar menos / mais produtos concorrentes, você pode usar:

most_cols = [col for col in df1.columns if 'most' in col]

def find_competitors_by_metric(x, metric_cols):
    competitors_metric = df1[df1.id.isin(x.competitors)][metric_cols]
    return competitors_metric.T[competitors_metric.any()].T.columns

most_for_competitors = df1.apply(lambda x: find_competitors_by_metric(x,most_cols),axis=1)

Agora você pode enviar a essa função as métricas que deseja calcular para os concorrentes da loja (assumindo que essas métricas existam no dataframe).

2 Let'stry Aug 27 2020 at 10:21

Eu descobri algo, mas acho que pode ser otimizado ainda mais. A ideia seria primeiro filtrar os concorrentes no intervalo, depois juntar e depois calcular o resultado com um .apply():

import numpy as np
import pandas as pd

df1 = pd.DataFrame([[1,1,0,0,0,1,1],
[2,0,1,0,1,0,0],
[3,0,1,1,1,0,0]],columns = ["id","most_sold_A","most_sold_B","most_sold_C","least_sold_A","least_sold_B","least_sold_C"])
df2 = pd.DataFrame([[1,2,0.5],
[1,3,3.0],
[2,3,0.2]], columns = ["id1","id2","distance"])

df2 = pd.concat([df2,df2[["id2","id1","distance"]].rename(columns = {"id2":"id1","id1":"id2"})]).reset_index()[["id1","id2","distance"]]
df2["id2"] = df2["id2"].astype(str)
df2 = df2[df2["distance"]<1][["id1","id2"]].groupby("id1").agg({'id2': ','.join}).reset_index()

df3 = pd.merge(df1,df2,how = 'left',left_on="id", right_on="id1")

most_cols = [col for col in df3.columns if 'most' in col]
least_cols = [col for col in df3.columns if 'least' in col]

df3["most_sold_competition_within_1k"] = df3.apply(lambda x: [df3[df3["id"]==int(elem)][most_cols].columns[[df3[df3["id"]==int(elem)][most_cols].values == 1][0][0]] for elem in x["id2"].split(",")],axis = 1)
df3["least_sold_competition_within_1k"] = df3.apply(lambda x: [df3[df3["id"]==int(elem)][least_cols].columns[[df3[df3["id"]==int(elem)][least_cols].values == 1][0][0]] for elem in x["id2"].split(",")],axis = 1)

df3 = df3[["id"]+most_cols+least_cols+["most_sold_competition_within_1k","least_sold_competition_within_1k"]]

df3

Resultado:

    id  most_sold_A most_sold_B most_sold_C least_sold_A    least_sold_B    least_sold_C    most_sold_competition_within_1k   least_sold_competition_within_1k
0   1   1           0           0           0               1               1              [[most_sold_B]]              [[least_sold_A]]
1   2   0           1           0           1               0               0    [[most_sold_B, most_sold_C], [most_sold_A]  [[least_sold_A], [least_sold_B, least_sold_C]]
2   3   0           1           1           1               0               0      [[most_sold_B]]                            [[least_sold_A]]