1
votes

Mélanger / Combiner deux dataframes semi-complètes de pandas

J'ai deux Pandas DataFrames qui ont des données similaires mais incomplètes. Il s'agit principalement de données relatives aux pays, voici donc quelques exemples de fausses données Population (millions) :

Tableau A

| Country | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 |
|--------:|------|------|------|------|------|------|
| USA     | 319  | 321  | 323  | 325  | 328  | 330  |
| UK      | 58   | 60   | nan  | 63   | 65   | 68   |
| India   | 780  | 810  | 820  | nan  | 1100 | 1300 |
| China   | nan  | nan  | 1100 | 1200 | 1300 | nan  |
| Nigeria | 90   | 100  | 105  | nan  | nan  | 110  |
  • Parfois, lorsque deux df ont une entrée pour une valeur (ex: Inde 2016), ce sera différent
  • Parfois, certaines entrées sont manquantes dans les deux df (ex: UK 2016)
  • Parfois, des lignes existent dans une table mais pas dans l'autre (ex: Nigéria, Chine)
  • Parfois, des colonnes existent dans un tableau mais pas dans l'autre (ex: 2018 dans le tableau A, 2019 dans le tableau B)

Je veux donc les combiner de telle sorte que les nan soient remplis à partir du tableau B s'ils existent, et des colonnes et des lignes sont ajoutées si elles ne sont pas là. S'il y a un conflit, je me fiche de celui qui est utilisé (les différences ne sont pas assez significatives).

En gros, j'aimerais qu'un résultat ressemble à ceci (dans ce cas, les valeurs de la table B sont utilisé en cas d'égalité):

Table A union Table B

| Country | 2014 | 2015 | 2016 | 2017 | 2018 |
|--------:|------|------|------|------|------|
| USA     | nan  | nan  | 323  | 325  | 328  |
| UK      | nan  | nan  | nan  | 63   | 65   |
| India   | nan  | nan  | 800  | nan  | 1100 |
| China   | nan  | nan  | 1100 | 1200 | 1300 |

Intuitivement, je veux juste le tableau le plus complet possible . Existe-t-il un moyen de le faire sans avoir à exécuter une boucle for? La table est grande et je ne veux pas avoir à écrire une longue boucle.


0 commentaires

3 Réponses :


2
votes

Vous pouvez utiliser concat et groupby:

   Country   2014   2015    2016    2017    2018    2019
0      USA  319.0  321.0   323.0   325.0   328.0   330.0
1       UK   58.0   60.0     NaN    63.0    65.0    68.0
2    India  780.0  810.0   800.0     NaN  1100.0  1300.0
3    China    NaN    NaN  1100.0  1200.0  1300.0     NaN
4  Nigeria   90.0  100.0   105.0     NaN     NaN   110.0

Output:

(pd.concat([df1,df2], sort=False)
   .groupby('Country', sort=False,as_index=False)
   .agg('first')
)


3 commentaires

J'ai vu des réponses comme ça, mais qu'en est-il des lignes manquantes du tableau A comme le Nigeria?


De plus, cela ne résout pas le problème où le tableau A a également des colonnes manquantes (comme 2019), il ne remplit que le tableau A.


@QuantumHoneybees désolé, n'a pas remarqué cette partie. Actualisé



3
votes

Utiliser :

df_join=( df2.merge(df1,how='outer')
           .groupby('Country')
           .apply(lambda x: x.ffill().bfill())
           .drop_duplicates('Country') )
print(df_join)

   Country   2014   2015    2016    2017    2019    2018
0      USA  319.0  321.0   324.0   325.0   330.0   328.0
1       UK   58.0   60.0     NaN    63.0    68.0    65.0
2    India  780.0  810.0   820.0     NaN  1300.0  1100.0
3  Nigeria   90.0  100.0   105.0     NaN   110.0     NaN
7    China    NaN    NaN  1100.0  1200.0     NaN  1300.0


0 commentaires

0
votes

Vous pouvez faire:

Year      2014   2015    2016    2017    2018    2019
Country                                              
China      NaN    NaN  1100.0  1200.0  1300.0     NaN
India    780.0  810.0   810.0     NaN  1100.0  1300.0
Nigeria   90.0  100.0   105.0     NaN     NaN   110.0
UK        58.0   60.0     NaN    63.0    65.0    68.0
USA      319.0  321.0   323.5   325.0   328.0   330.0

Sortie

result = pd.concat([A.melt(id_vars='Country', var_name='Year', value_name='Population'),
                    B.melt(id_vars='Country', var_name='Year', value_name='Population')]).dropna()

print(pd.crosstab(index=result.Country, columns=result.Year, values=result.Population, aggfunc='mean'))


0 commentaires