J'ai ce code:

for index, row in df.iterrows():
  for index1, row1 in df1.iterrows():
    if df['budget'].iloc[index] == 0:
        if df['production_companies'].iloc[index] == df1['production_companies'].iloc[index1]
            and df['release_date'].iloc[index].year == df1['release_year'].iloc[index1] :
                df['budget'].iloc[index] = df1['mean'].iloc[index1]

Cela fonctionne, mais il faudrait trop de temps pour terminer. Comment puis-je le faire fonctionner plus rapidement? J'ai aussi essayé:

df.where((df['budget'] != 0 and df['production_companies'] != df1['production_companies']
    and df['release_date'] != df1['release_year']),
        other = pd.replace(to_replace = df['budget'],
            value = df1['mean'],  inplace = True))

Ça devrait être plus rapide mais ça ne marche pas. Comment puis-je y parvenir? Je vous remercie!

df ressemble à ceci:

budget; production_companies;   release_date    ;title    
0;  Villealfa Filmproduction Oy ;10/21/1988;    Ariel    
0;  Villealfa Filmproduction Oy ;10/16/1986;    Shadows in Paradise   
4000000;    Miramax Films;  12/25/1995; Four Rooms   
0;  Universal Pictures; 10/15/1993; Judgment Night   
42000;  inLoops ;1/1/2006;  Life in Loops (A Megacities RMX)   
...          

Et df1:

production_companies;   release_year;   mean;
Metro-Goldwyn-Mayer (MGM);  1998;   17500000    
Metro-Goldwyn-Mayer (MGM);  1999;   12500000   
Metro-Goldwyn-Mayer (MGM);  2000;   12000000   
Metro-Goldwyn-Mayer (MGM)   ;2001   ;43500000  
Metro-Goldwyn-Mayer (MGM);  2002    ;12000000  
Metro-Goldwyn-Mayer (MGM)   ;2003;  36000000  
Metro-Goldwyn-Mayer (MGM);  2004    ;27500000   
...   

Je veux remplacer la valeur 0 de df par la valeur "moyenne" de df1 si l'année et la société de production sont les mêmes.

1
Relu Morosan 14 avril 2018 à 18:35

3 réponses

Meilleure réponse

N'utilisez pas de boucles pour cette tâche

Le principal avantage des pandas est la fonctionnalité vectorisée.

Une façon de vectoriser votre calcul consiste à aligner les indices puis à utiliser pd.DataFrame.index.map. Pour extraire l'année, vous devez d'abord convertir en datetime.

Données de @ALollz.

# convert release_date to datetime and calculate year
df['release_date'] = pd.to_datetime(df['release_date'])
df['year'] = df['release_date'].dt.year

# create mapping from df1
s = df1.set_index(['production_companies', 'release_year'])['mean']

# use map on selected condition
mask = df['budget'] == 0
df.loc[mask, 'budget'] = df[mask].set_index(['production_company', 'year']).index.map(s.get)

print(df)

#      budget           production_company release_date title  year
# 0   1000000  Villealfa Filmproduction Oy   1988-10-21   AAA  1988
# 1       100  Villealfa Filmproduction Oy   1986-10-18   BBB  1986
# 2  30000000  Villealfa Filmproduction Oy   1955-12-25   CCC  1955
# 3      1000                Miramax Films   2006-01-01   DDD  2006
# 4   5000000                Miramax Films   2017-04-13   EEE  2017
1
jpp 14 avril 2018 à 18:07

Vous pouvez supprimer rapidement un cycle en utilisant votre instruction if plus tôt:

for index, row in df.iterrows():
  if df['budget'].iloc[index] == 0:
      for index1, row1 in df1.iterrows():
        if df['production_companies'].iloc[index] == df1['production_companies'].iloc[index1] and df['release_date'].iloc[index].year == df1['release_year'].iloc[index1] :
            df['budget'].iloc[index] = df1['mean'].iloc[index1]
-1
Nathan 14 avril 2018 à 15:45

Débarrassez-vous de toutes les boucles, vous pouvez accomplir cela efficacement avec une fusion. Ici, j'ai fourni quelques exemples de données, car aucune des données que vous avez fournies ne fusionnera réellement. Vous voulez vous assurer que release_date dans df est une date / heure, si ce n'est pas déjà fait.

import pandas as pd
import numpy as np
df = pd.DataFrame({'budget': [0, 100, 0, 1000, 0],
                   'production_company': ['Villealfa Filmproduction Oy', 'Villealfa Filmproduction Oy',
                                      'Villealfa Filmproduction Oy', 'Miramax Films', 'Miramax Films'],
                   'release_date': ['10/21/1988', '10/18/1986', '12/25/1955', '1/1/2006', '4/13/2017'],
                   'title': ['AAA', 'BBB', 'CCC', 'DDD', 'EEE']})

df1 = pd.DataFrame({'production_companies': ['Villealfa Filmproduction Oy', 'Villealfa Filmproduction Oy', 
    'Villealfa Filmproduction Oy', 'Miramax Films', 'Miramax Films'],
                'release_year': [1988, 1986, 1955, 2006, 2017],
                   'mean': [1000000, 2000000, 30000000, 4000000, 5000000]})

df['release_date'] = pd.to_datetime(df.release_date, format='%m/%d/%Y')

#   budget           production_company release_date title
#0       0  Villealfa Filmproduction Oy   1988-10-21   AAA
#1     100  Villealfa Filmproduction Oy   1986-10-18   BBB
#2       0  Villealfa Filmproduction Oy   1955-12-25   CCC
#3    1000                Miramax Films   2006-01-01   DDD
#4       0                Miramax Films   2017-04-13   EEE

Ensuite, vous souhaitez remplacer le budget où il est 0 par la moyenne si la société de production et l'année correspondent. Donc, comme fusion, c'est:

df.loc[df.budget==0, 'budget'] = (df.merge(df1, left_on=['production_company', 
    df.release_date.dt.year], right_on=['production_companies', 'release_year'], how='left')
    .loc[df.budget==0, 'mean'])

#     budget           production_company release_date title
#0   1000000  Villealfa Filmproduction Oy   1988-10-21   AAA
#1       100  Villealfa Filmproduction Oy   1986-10-18   BBB
#2  30000000  Villealfa Filmproduction Oy   1955-12-25   CCC
#3      1000                Miramax Films   2006-01-01   DDD
#4   5000000                Miramax Films   2017-04-13   EEE

Si vous ne disposez pas de données mean pour une société de production et une année données, les 0 dans budget seront remplacés par np.NaN, vous pouvez donc les laisser ou remplacez-les à 0 si vous le souhaitez.

1
ALollz 14 avril 2018 à 17:37