J'ai deux tables et j'aimerais les ajouter afin que seules les données de la table A soient conservées et que les données de la table B ne soient ajoutées que si sa clé est unique (Les valeurs de clé sont uniques dans les tables A et B; La clé apparaîtra dans les tableaux A et B).
Je pense que la manière de procéder implique une sorte de jointure de filtrage (anti-jointure) pour obtenir des valeurs dans le tableau B qui ne figurent pas dans le tableau A, puis ajouter les deux tableaux.
Je connais R et c’est le code que j’utiliserais pour le faire en R.
library("dplyr")
## Filtering join to remove values already in "TableA" from "TableB"
FilteredTableB <- anti_join(TableB,TableA, by = "Key")
## Append "FilteredTableB" to "TableA"
CombinedTable <- bind_rows(TableA,FilteredTableB)
Comment pourrais-je y parvenir en python?
Considérons les dataframes suivants
TableA = pd.DataFrame(np.random.Rand(4, 3),
pd.Index(list('abcd'), name='Key'),
['A', 'B', 'C']).reset_index()
TableB = pd.DataFrame(np.random.Rand(4, 3),
pd.Index(list('aecf'), name='Key'),
['A', 'B', 'C']).reset_index()
TableA
TableB
C'est une façon de faire ce que tu veux
# Identify what values are in TableB and not in TableA
key_diff = set(TableB.Key).difference(TableA.Key)
where_diff = TableB.Key.isin(key_diff)
# Slice TableB accordingly and append to TableA
TableA.append(TableB[where_diff], ignore_index=True)
rows = []
for i, row in TableB.iterrows():
if row.Key not in TableA.Key.values:
rows.append(row)
pd.concat([TableA.T] + rows, axis=1).T
4 lignes avec 2 chevauchements
La méthode 1 est beaucoup plus rapide
10 000 lignes 5 000 chevauchements
les boucles sont mauvaises
J'ai eu le même problème. Cette réponse utilisant how='outer'
et indicator=True
de fusion m'a inspiré pour proposer cette solution:
import pandas as pd
import numpy as np
TableA = pd.DataFrame(np.random.Rand(4, 3),
pd.Index(list('abcd'), name='Key'),
['A', 'B', 'C']).reset_index()
TableB = pd.DataFrame(np.random.Rand(4, 3),
pd.Index(list('aecf'), name='Key'),
['A', 'B', 'C']).reset_index()
print('TableA', TableA, sep='\n')
print('TableB', TableB, sep='\n')
TableB_only = pd.merge(
TableA, TableB,
how='outer', on='Key', indicator=True, suffixes=('_foo','')).query(
'_merge == "right_only"')
print('TableB_only', TableB_only, sep='\n')
Table_concatenated = pd.concat((TableA, TableB_only), join='inner')
print('Table_concatenated', Table_concatenated, sep='\n')
Qui imprime cette sortie:
TableA
Key A B C
0 a 0.035548 0.344711 0.860918
1 b 0.640194 0.212250 0.277359
2 c 0.592234 0.113492 0.037444
3 d 0.112271 0.205245 0.227157
TableB
Key A B C
0 a 0.754538 0.692902 0.537704
1 e 0.499092 0.864145 0.004559
2 c 0.082087 0.682573 0.421654
3 f 0.768914 0.281617 0.924693
TableB_only
Key A_foo B_foo C_foo A B C _merge
4 e NaN NaN NaN 0.499092 0.864145 0.004559 right_only
5 f NaN NaN NaN 0.768914 0.281617 0.924693 right_only
Table_concatenated
Key A B C
0 a 0.035548 0.344711 0.860918
1 b 0.640194 0.212250 0.277359
2 c 0.592234 0.113492 0.037444
3 d 0.112271 0.205245 0.227157
4 e 0.499092 0.864145 0.004559
5 f 0.768914 0.281617 0.924693
Réponse la plus simple que l'on puisse imaginer:
tableB = pd.concat([tableB, pd.Series(1)], axis=1)
mergedTable = tableA.merge(tableB, how="left" on="key")
answer = mergedTable[mergedTable.iloc[:,-1].isnull()][tableA.columns.tolist()]
Devrait être le plus rapide proposé aussi bien.
Vous aurez les deux tables TableA
et TableB
telles que les deux objets DataFrame
aient des colonnes avec des valeurs uniques dans leurs tables respectives, mais certaines colonnes peuvent avoir des valeurs qui apparaissent simultanément (ont les mêmes valeurs pour une ligne) dans les deux tables.
Ensuite, nous voulons fusionner les lignes dans TableA
avec les lignes dans TableB
qui ne correspondent à aucune dans TableA
pour une colonne 'Clé'. Le concept est de l’imaginer en comparant deux séries de longueur variable et en combinant les lignes d’une série sA
avec l’autre sB
si les valeurs de sB
ne correspondent pas à celles de sA
. Le code suivant résout cet exercice:
import pandas as pd
TableA = pd.DataFrame([[2, 3, 4], [5, 6, 7], [8, 9, 10]])
TableB = pd.DataFrame([[1, 3, 4], [5, 7, 8], [9, 10, 0]])
removeTheseIndexes = []
keyColumnA = TableA.iloc[:,1] # your 'Key' column here
keyColumnB = TableB.iloc[:,1] # same
for i in range(0, len(keyColumnA)):
firstValue = keyColumnA[i]
for j in range(0, len(keyColumnB)):
copycat = keyColumnB[j]
if firstValue == copycat:
removeTheseIndexes.append(j)
TableB.drop(removeTheseIndexes, inplace = True)
TableA = TableA.append(TableB)
TableA = TableA.reset_index(drop=True)
Notez que cela affecte également les données de TableB
. Vous pouvez utiliser inplace=False
et le réaffecter à une newTable
, puis à TableA.append(newTable)
alternativement.
# Table A
0 1 2
0 2 3 4
1 5 6 7
2 8 9 10
# Table B
0 1 2
0 1 3 4
1 5 7 8
2 9 10 0
# Set 'Key' column = 1
# Run the script after the loop
# Table A
0 1 2
0 2 3 4
1 5 6 7
2 8 9 10
3 5 7 8
4 9 10 0
# Table B
0 1 2
1 5 7 8
2 9 10 0
Sur la base d’une des autres suggestions, voici une fonction qui devrait le faire. Utilisant uniquement des fonctions de pandas, pas de bouclage. Vous pouvez également utiliser plusieurs colonnes comme clé. Si vous modifiez la ligne output = merged.loc[merged.dummy_col.isna(),tableA.columns.tolist()]
en output = merged.loc[~merged.dummy_col.isna(),tableA.columns.tolist()]
, vous avez un semi-joint.
def anti_join(tableA,tableB,on):
#if joining on index, make it into a column
if tableB.index.name is not None:
dummy = tableB.reset_index()[on]
else:
dummy = tableB[on]
#create a dummy columns of 1s
if isinstance(dummy, pd.Series):
dummy = dummy.to_frame()
dummy.loc[:,'dummy_col'] = 1
#preserve the index of tableA if it has one
if tableA.index.name is not None:
idx_name = tableA.index.name
tableA = tableA.reset_index(drop = False)
else:
idx_name = None
#do a left-join
merged = tableA.merge(dummy,on=on,how='left')
#keep only the non-matches
output = merged.loc[merged.dummy_col.isna(),tableA.columns.tolist()]
#reset the index (if applicable)
if idx_name is not None:
output = output.set_index(idx_name)
return(output)