2 votes

Pandas Appliquer - Retourner plusieurs lignes

J'ai deux dataframes et j'ai besoin de comparer toutes les combinaisons de lignes et retourner celles qui satisfont un critère. Cela s'avère trop intensif pour notre petit cluster avec Spark (en utilisant une jointure croisée) donc j'expérimente cette approche et je verrai éventuellement si Dask peut améliorer cela.

Si la table A et B sont

a=pd.DataFrame(np.array([[1,2,3],[4,5,6]]), columns=['a','b','c'])

b=pd.DataFrame(np.array([[4,7,4],[6,5,1],[8,6,0]]), columns=['d','e','f'])

Alors toutes les combinaisons ressemblent à ça, où A-D est calculé. Disons que je veux garder seulement les lignes où A-D >=-3

A   B   C   D   E   F   A-D
1   2   3   4   7   4   -3
1   2   3   6   5   1   -5
1   2   3   8   6   0   -7
4   5   6   4   7   4   0
4   5   6   6   5   1   -2
4   5   6   8   6   0   -4

J'ai essayé de le faire avec un apply mais il semble que je ne peux pas retourner un dataframe multi-lignes à partir de la fonction (la fonction crée toutes les combinaisons de la seule ligne de 'A' et de toute la table de 'B' et retourne les lignes qui satisfont le critère.

Voici la fonction que j'ai testée:

def return_prox_branches(a, B, cutthresh):

    aa=a['a']-B['d']

    keep_B = B.copy().loc[(aa.values >= cutthresh),:]

    keep_B['A']=a['a']

    keep_B['B']=a['b']

    keep_B['C']=a['c']

    keep_B['A-D']=a['a']-keep_B['d']

    print(keep_B)

    return(keep_B)

a.apply(return_prox_branches, axis=1, args=(b,-3))

ValueError: cannot copy sequence with size 7 to array axis with dimension 1

En réalité, ces deux tables ont des millions de lignes.

Y a-t-il un moyen pour faire fonctionner cela efficacement dans pandas?

5voto

piRSquared Points 159

Amusant!

Déballer de cette manière est devenu possible en Python 3.5
https://www.python.org/dev/peps/pep-0448/#rationale

i, j = np.where(np.subtract.outer(a.a, b.d) >= -3)
pd.DataFrame({**a.iloc[i].to_dict('l'), **b.iloc[j].to_dict('l')})

   a  b  c  d  e  f
0  1  2  3  4  7  4
1  4  5  6  4  7  4
2  4  5  6  6  5  1

Similaire mais moins confus

i, j = np.where(np.subtract.outer(a.a, b.d) >= -3)
a_ = a.values[i]
b_ = b.values[j]

d = pd.DataFrame(
    np.column_stack([a_, b_]),
    columns=a.columns.append(b.columns)
)

d

   a  b  c  d  e  f
0  1  2  3  4  7  4
1  4  5  6  4  7  4
2  4  5  6  6  5  1

Dans les deux cas, nous dépendons d'une soustraction externe de b.d de a.a. Cela crée un tableau 2D de toutes les soustractions possibles des valeurs b.d des valeurs de a.a. np.where trouve les coordonnées où cette différence est >= -3. Je peux utiliser ces résultats pour trancher les cadres de données originaux et les placer ensemble.


Pur(ou presque) Pandas

J'ai des doutes que vous puissiez l'utiliser avec dask

def gen_pseudo(d_):
    def pseudo(d):
        cols = d.columns.append(d_.columns)
        return d_.assign(**d.squeeze()).query('a - d >= -3')[cols]
    return pseudo

a.groupby(level=0).apply(gen_pseudo(b))

     a  b  c  d  e  f
0 0  1  2  3  4  7  4
1 0  4  5  6  4  7  4
  1  4  5  6  6  5  1

Alternative sans fermeture

def pseudo(d, d_):
    cols = d.columns.append(d_.columns)
    return d_.assign(**d.squeeze()).query('a - d >= -3')[cols]

a.groupby(level=0).apply(pseudo, d_=b)

Compréhension

ja = a.columns.get_loc('a')
jb = b.columns.get_loc('d')

pd.DataFrame([
    np.append(ra, rb)
    for ra in a.values
    for rb in b.values
    if ra[ja] - rb[jb] >= -3
], columns=a.columns.append(b.columns))

   a  b  c  d  e  f
0  1  2  3  4  7  4
1  4  5  6  4  7  4
2  4  5  6  6  5  1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X