Cursus
Heb je ooit een Kaggle-challenge geprobeerd op te lossen? Zo ja, dan is je misschien opgevallen dat in de meeste challenges de data over meerdere bestanden is verdeeld, waarbij sommige kolommen in meer dan één bestand voorkomen. Wat is dan het eerste waar je aan denkt? Samenvoegen natuurlijk!
In deze tutorial oefen je een paar standaardtechnieken voor joins in pandas. Concreet leer je:
- DataFrames concateneren over rijen en kolommen.
- DataFrames mergen op specifieke sleutels met verschillende joinlogica zoals left join, inner join, enz.
- DataFrames joinen op index.
- Time-series-vriendelijke merges in pandas
Onderweg leer je ook een paar trucjes die je vóór en na het joinen nodig hebt.
TL;DR
- Gebruik
pd.concat()om DataFrames verticaal (rijen) of horizontaal (kolommen) te stapelen - Gebruik
pd.merge()om DataFrames op gemeenschappelijke kolommen te joinen, vergelijkbaar met SQL-joins - Specificeer het jointype met de parameter
how:'inner','outer','left'of'right' - Gebruik
.join()voor indexgebaseerde joins van DataFrames - Gebruik
pd.merge_asof()voor tijdreeksdata waarbij je de dichtstbijzijnde sleutelmatch nodig hebt
pandas-joins
Het joinen en mergen van DataFrames is de kernstap om te starten met data-analyse en machine learning-taken. Het is een van de gereedschappen die elke Data Analyst of Data Scientist moet beheersen, omdat data in vrijwel alle gevallen uit meerdere bronnen en bestanden komt. Je moet vaak alle data op één plek samenbrengen met een bepaalde joinlogica en dan je analyse starten. Wie met SQL-joins werkt, kent het belang van deze taak. Ook als je machine learning-modellen op data wilt bouwen, moet je mogelijk meerdere csv-bestanden samenvoegen in één DataFrame.
Gelukkig is er de populairste bibliotheek in Python, pandas, om je te helpen! pandas biedt allerlei mogelijkheden om Series en DataFrames eenvoudig te combineren met verschillende soorten setlogica voor de indexen en functionaliteit voor relationele algebra bij join-/merge-achtige operaties.
Voer de code uit deze tutorial online uit en pas 'm aan.
Code uitvoerenpandas Concatenate
Begin met het importeren van de bibliotheek die je in de hele tutorial gebruikt: pandas
import pandas as pd
Alle bewerkingen in deze tutorial voer je uit op dummy-DataFrames die je zelf maakt. Om een DataFrame te maken, kun je een Python-dictionary gebruiken zoals:
dummy_data1 = {
'id': ['1', '2', '3', '4', '5'],
'Feature1': ['A', 'C', 'E', 'G', 'I'],
'Feature2': ['B', 'D', 'F', 'H', 'J']}
Hier zijn de keys van de dictionary dummy_data1 de kolomnamen, en de waardelijsten zijn de data die bij elke observatie of rij horen. Om dit om te zetten naar een pandas DataFrame gebruik je de DataFrame()-functie van pandas, samen met het argument columns om je kolommen te benoemen:
df1 = pd.DataFrame(dummy_data1, columns = ['id', 'Feature1', 'Feature2'])
df1
| id | Feature1 | Feature2 | |
|---|---|---|---|
| 0 | 1 | A | B |
| 1 | 2 | C | D |
| 2 | 3 | E | F |
| 3 | 4 | G | H |
| 4 | 5 | I | J |
Zoals je ziet heb je nu een DataFrame met drie kolommen id, Feature1 en Feature2. Er is een extra naamloze kolom die pandas intrinsiek aanmaakt als rijlables. Net als het vorige DataFrame df1 maak je nog twee DataFrames df2 en df3:
dummy_data2 = {
'id': ['1', '2', '6', '7', '8'],
'Feature1': ['K', 'M', 'O', 'Q', 'S'],
'Feature2': ['L', 'N', 'P', 'R', 'T']}
df2 = pd.DataFrame(dummy_data2, columns = ['id', 'Feature1', 'Feature2'])
df2
| id | Feature1 | Feature2 | |
|---|---|---|---|
| 0 | 1 | K | L |
| 1 | 2 | M | N |
| 2 | 6 | O | P |
| 3 | 7 | Q | R |
| 4 | 8 | S | T |
dummy_data3 = {
'id': ['1', '2', '3', '4', '5', '7', '8', '9', '10', '11'],
'Feature3': [12, 13, 14, 15, 16, 17, 15, 12, 13, 23]}
df3 = pd.DataFrame(dummy_data3, columns = ['id', 'Feature3'])
df3
| id | Feature3 | |
|---|---|---|
| 0 | 1 | 12 |
| 1 | 2 | 13 |
| 2 | 3 | 14 |
| 3 | 4 | 15 |
| 4 | 5 | 16 |
| 5 | 7 | 17 |
| 6 | 8 | 15 |
| 7 | 9 | 12 |
| 8 | 10 | 13 |
| 9 | 11 | 23 |
concat()
Om DataFrames simpelweg over de rij te concateneren, kun je de functie concat() in pandas gebruiken. Je moet de namen van de DataFrames in een lijst meegeven als argument aan de functie concat():
df_row = pd.concat([df1, df2])
df_row
| id | Feature1 | Feature2 | |
|---|---|---|---|
| 0 | 1 | A | B |
| 1 | 2 | C | D |
| 2 | 3 | E | F |
| 3 | 4 | G | H |
| 4 | 5 | I | J |
| 0 | 1 | K | L |
| 1 | 2 | M | N |
| 2 | 6 | O | P |
| 3 | 7 | Q | R |
| 4 | 8 | S | T |
Je ziet dat de twee DataFrames df1 en df2 nu langs de rijen zijn geconcateneerd tot één DataFrame df_row. De rijlables lijken echter niet te kloppen. Als je wilt dat de rijlables automatisch worden aangepast aan de join, moet je het argument ignore_index op True zetten bij het aanroepen van concat():
df_row_reindex = pd.concat([df1, df2], ignore_index=True)
df_row_reindex
| id | Feature1 | Feature2 | |
|---|---|---|---|
| 0 | 1 | A | B |
| 1 | 2 | C | D |
| 2 | 3 | E | F |
| 3 | 4 | G | H |
| 4 | 5 | I | J |
| 5 | 1 | K | L |
| 6 | 2 | M | N |
| 7 | 6 | O | P |
| 8 | 7 | Q | R |
| 9 | 8 | S | T |
Nu kloppen de rijlables wel!
pandas biedt ook de mogelijkheid om na het concateneren de DataFrames te labelen met een key, zodat je weet welke data uit welk DataFrame komt. Dat doe je door het extra argument keys mee te geven met de labelnamen van de DataFrames in een lijst. Hier voer je dezelfde concatenatie uit met de keys x en y voor respectievelijk df1 en df2.
frames = [df1,df2]
df_keys = pd.concat(frames, keys=['x', 'y'])
df_keys
| id | Feature1 | Feature2 | ||
|---|---|---|---|---|
| x | 0 | 1 | A | B |
| 1 | 2 | C | D | |
| 2 | 3 | E | F | |
| 3 | 4 | G | H | |
| 4 | 5 | I | J | |
| y | 0 | 1 | K | L |
| 1 | 2 | M | N | |
| 2 | 6 | O | P | |
| 3 | 7 | Q | R | |
| 4 | 8 | S | T |
Door keys te vermelden kun je ook makkelijk data ophalen die bij een bepaald DataFrame hoort. Je kunt de data van DataFrame df2, dat het label y had, opvragen met de methode loc:
df_keys.loc['y']
| id | Feature1 | Feature2 | |
|---|---|---|---|
| 0 | 1 | K | L |
| 1 | 2 | M | N |
| 2 | 6 | O | P |
| 3 | 7 | Q | R |
| 4 | 8 | S | T |
Je kunt ook een dictionary doorgeven aan concat(); in dat geval worden de dictionary-keys gebruikt voor het keys-argument (tenzij je andere keys opgeeft):
pieces = {'x': df1, 'y': df2}
df_piece = pd.concat(pieces)
df_piece
| id | Feature1 | Feature2 | ||
|---|---|---|---|---|
| x | 0 | 1 | A | B |
| 1 | 2 | C | D | |
| 2 | 3 | E | F | |
| 3 | 4 | G | H | |
| 4 | 5 | I | J | |
| y | 0 | 1 | K | L |
| 1 | 2 | M | N | |
| 2 | 6 | O | P | |
| 3 | 7 | Q | R | |
| 4 | 8 | S | T |
Het is goed om te weten dat concat() een volledige kopie van de data maakt, en herhaald gebruik kan een flinke prestatie-impact hebben. Voor grootschalige databewerkingen kun je overwegen om pandas 2.0 vs polars voor high-performance datamanipulatie te verkennen. Als je de operatie over meerdere datasets moet gebruiken, gebruik dan een list comprehension.
frames = [ process_your_file(f) for f in files ]
result = pd.concat(frames)
Om DataFrames over kolommen te concateneren, kun je de parameter axis op 1 zetten:
df_col = pd.concat([df1,df2], axis=1)
df_col
| id | Feature1 | Feature2 | id | Feature1 | Feature2 | |
|---|---|---|---|---|---|---|
| 0 | 1 | A | B | 1 | K | L |
| 1 | 2 | C | D | 2 | M | N |
| 2 | 3 | E | F | 6 | O | P |
| 3 | 4 | G | H | 7 | Q | R |
| 4 | 5 | I | J | 8 | S | T |
pandas Merge DataFrames
Een andere alomtegenwoordige bewerking voor DataFrames is mergen. Twee DataFrames kunnen verschillende soorten informatie over dezelfde entiteit bevatten en gekoppeld zijn door een gemeenschappelijke feature/kolom. Om deze DataFrames te joinen, biedt pandas meerdere functies zoals concat(), merge(), join(), enz. In deze sectie oefen je met de functie merge() van pandas.
Je kunt de DataFrames df_row (dat je maakte door df1 en df2 over de rijen te concateneren) en df3 joinen op de gemeenschappelijke kolom (of sleutel) id. Geef hiervoor de namen van de DataFrames en een extra argument on met de naam van de gemeenschappelijke kolom, hier id, mee aan de functie merge():
df_merge_col = pd.merge(df_row, df3, on='id')
df_merge_col
| id | Feature1 | Feature2 | Feature3 | |
|---|---|---|---|---|
| 0 | 1 | A | B | 12 |
| 1 | 1 | K | L | 12 |
| 2 | 2 | C | D | 13 |
| 3 | 2 | M | N | 13 |
| 4 | 3 | E | F | 14 |
| 5 | 4 | G | H | 15 |
| 6 | 5 | I | J | 16 |
| 7 | 7 | Q | R | 17 |
| 8 | 8 | S | T | 15 |
Je ziet dat de DataFrames nu zijn samengevoegd tot één DataFrame op basis van de gemeenschappelijke waarden in de id-kolom van beide DataFrames. Zo kwam de id-waarde 1 zowel met A, B als met K, L in df_row voor; daarom komt deze id twee keer terug in het uiteindelijke DataFrame df_merge_col met de herhaalde waarde 12 van Feature3 die uit df3 komt.
Het kan gebeuren dat de kolom waarop je de DataFrames wilt mergen verschillende namen heeft (anders dan in dit geval). Voor zulke merges moet je de argumenten left_on als de kolomnaam van het linker DataFrame en right_on als die van het rechter DataFrame opgeven, zoals:
df_merge_difkey = pd.merge(df_row, df3, left_on='id', right_on='id')
df_merge_difkey
| id | Feature1 | Feature2 | Feature3 | |
|---|---|---|---|---|
| 0 | 1 | A | B | 12 |
| 1 | 1 | K | L | 12 |
| 2 | 2 | C | D | 13 |
| 3 | 2 | M | N | 13 |
| 4 | 3 | E | F | 14 |
| 5 | 4 | G | H | 15 |
| 6 | 5 | I | J | 16 |
| 7 | 7 | Q | R | 17 |
| 8 | 8 | S | T | 15 |
Je kunt ook rijen aan een DataFrame toevoegen met pd.concat(). Maak eerst een nieuw DataFrame met de rijdata en concateneer dit daarna met het oorspronkelijke DataFrame:
add_row = pd.DataFrame([['10', 'X1', 'X2', 'X3']],
columns=['id', 'Feature1', 'Feature2', 'Feature3'])
df_add_row = pd.concat([df_merge_col, add_row], ignore_index=True)
df_add_row
| id | Feature1 | Feature2 | Feature3 | |
|---|---|---|---|---|
| 0 | 1 | A | B | 12 |
| 1 | 1 | K | L | 12 |
| 2 | 2 | C | D | 13 |
| 3 | 2 | M | N | 13 |
| 4 | 3 | E | F | 14 |
| 5 | 4 | G | H | 15 |
| 6 | 5 | I | J | 16 |
| 7 | 7 | Q | R | 17 |
| 8 | 8 | S | T | 15 |
| 9 | 10 | X1 | X2 | X3 |
Types of pandas Join
In deze sectie oefen je de verschillende joinlogica's die beschikbaar zijn om pandas DataFrames te mergen op basis van een gemeenschappelijke kolom/sleutel. De logica achter deze joins is vrijwel hetzelfde als in SQL wanneer je tabellen joint. Als je bekend bent met inner vs outer joins in SQL, komen deze concepten je bekend voor.
| Join Type | SQL Equivalent | Result | Use Case |
|---|---|---|---|
inner |
INNER JOIN | Alleen rijen die in beide DataFrames matchen | Wanneer je alleen records wilt die in beide tabellen bestaan |
left |
LEFT OUTER JOIN | Alle rijen van links + matches van rechts | Behoud alle records uit het primaire DataFrame |
right |
RIGHT OUTER JOIN | Alle rijen van rechts + matches van links | Behoud alle records uit het secundaire DataFrame |
outer |
FULL OUTER JOIN | Alle rijen uit beide DataFrames | Wanneer je een volledige unie van beide tabellen nodig hebt |
Full Outer Join
De FULL OUTER JOIN combineert de resultaten van zowel de left als de right outer join. Het gejoinde DataFrame bevat alle records uit beide DataFrames en vult NaN-waarden in voor ontbrekende matches aan weerszijden. Je kunt een full outer join uitvoeren door het argument how als outer op te geven in de functie merge():
df_outer = pd.merge(df1, df2, on='id', how='outer')
df_outer
| id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
|---|---|---|---|---|---|
| 0 | 1 | A | B | K | L |
| 1 | 2 | C | D | M | N |
| 2 | 3 | E | F | NaN | NaN |
| 3 | 4 | G | H | NaN | NaN |
| 4 | 5 | I | J | NaN | NaN |
| 5 | 6 | NaN | NaN | O | P |
| 6 | 7 | NaN | NaN | Q | R |
| 7 | 8 | NaN | NaN | S | T |
Je ziet dat het resulterende DataFrame alle entries uit beide tabellen bevat, met NaN-waarden voor ontbrekende matches aan weerszijden. Let ook op het suffix dat aan de kolomnamen is toegevoegd om aan te geven uit welk DataFrame de kolom komt. De standaard-suffixen zijn x en y, maar je kunt ze aanpassen door het argument suffixes op te geven in merge():
df_suffix = pd.merge(df1, df2, left_on='id',right_on='id',how='outer',suffixes=('_left','_right'))
df_suffix
| id | Feature1_left | Feature2_left | Feature1_right | Feature2_right | |
|---|---|---|---|---|---|
| 0 | 1 | A | B | K | L |
| 1 | 2 | C | D | M | N |
| 2 | 3 | E | F | NaN | NaN |
| 3 | 4 | G | H | NaN | NaN |
| 4 | 5 | I | J | NaN | NaN |
| 5 | 6 | NaN | NaN | O | P |
| 6 | 7 | NaN | NaN | Q | R |
| 7 | 8 | NaN | NaN | S | T |
Inner Join
De INNER JOIN produceert alleen de set records die in zowel DataFrame A als DataFrame B matchen. Je moet inner doorgeven in het how-argument van merge() om een inner join te doen:
df_inner = pd.merge(df1, df2, on='id', how='inner')
df_inner
| id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
|---|---|---|---|---|---|
| 0 | 1 | A | B | K | L |
| 1 | 2 | C | D | M | N |
Right Join
De RIGHT JOIN produceert een complete set records uit DataFrame B (rechter DataFrame), met de matchende records (waar beschikbaar) in DataFrame A (linker DataFrame). Als er geen match is, bevat de rechterkant null. Je moet right doorgeven in het how-argument van merge() om een right join te doen:
df_right = pd.merge(df1, df2, on='id', how='right')
df_right
| id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
|---|---|---|---|---|---|
| 0 | 1 | A | B | K | L |
| 1 | 2 | C | D | M | N |
| 2 | 6 | NaN | NaN | O | P |
| 3 | 7 | NaN | NaN | Q | R |
| 4 | 8 | NaN | NaN | S | T |
Left Join
De LEFT JOIN produceert een complete set records uit DataFrame A (linker DataFrame), met de matchende records (waar beschikbaar) in DataFrame B (rechter DataFrame). Als er geen match is, bevat de linkerkant null. Je moet left doorgeven in het how-argument van merge() om een left join te doen:
df_left = pd.merge(df1, df2, on='id', how='left')
df_left
| id | Feature1_x | Feature2_x | Feature1_y | Feature2_y | |
|---|---|---|---|---|---|
| 0 | 1 | A | B | K | L |
| 1 | 2 | C | D | M | N |
| 2 | 3 | E | F | NaN | NaN |
| 3 | 4 | G | H | NaN | NaN |
| 4 | 5 | I | J | NaN | NaN |
Joinen op index
Soms moet je de join uitvoeren op de indexen of rijlables. Hiervoor moet je right_index (voor de indexen van het rechter DataFrame) en left_index (voor de indexen van het linker DataFrame) op True zetten:
df_index = pd.merge(df1, df2, right_index=True, left_index=True)
df_index
| id_x | Feature1_x | Feature2_x | id_y | Feature1_y | Feature2_y | |
|---|---|---|---|---|---|---|
| 0 | 1 | A | B | 1 | K | L |
| 1 | 2 | C | D | 2 | M | N |
| 2 | 3 | E | F | 6 | O | P |
| 3 | 4 | G | H | 7 | Q | R |
| 4 | 5 | I | J | 8 | S | T |
pandas Join
De pandas-methode DataFrame.join() wordt gebruikt voor het joinen van DataFrames op unieke indexen. Je kunt het optionele argument `on` gebruiken om kolom(men) te joinen op de index, en met het argument how bepaal je de operatie tussen de twee objecten. Standaard wordt een inner join gebruikt.
pandas Twee DataFrames joinen
Laten we twee dataframes joinen met .join. We geven `lsuffix` en `rsuffix` mee om te voorkomen dat een fout optreedt bij overlappende kolommen. Er wordt op de index gejoint, niet op de kolom, dus we moeten ofwel de ‘id’-kolom aanpassen of een suffix meegeven.
df2.join(df3, lsuffix='_left', rsuffix='_right')
| id_left | Feature1 | Feature2 | id_right | Feature3 | |
|---|---|---|---|---|---|
| 0 | 1 | K | L | 1 | 12 |
| 1 | 2 | M | N | 2 | 13 |
| 2 | 6 | O | P | 3 | 14 |
| 3 | 7 | Q | R | 4 | 15 |
| 4 | 8 | S | T | 5 | 16 |
We kunnen ook kolommen op de index joinen met het argument `on`. Om de join goed toe te passen, moeten we in df3 de ‘id’-kolom naar de index verplaatsen en het argument `on` de ‘id’-kolom meegeven. Standaard wordt een left join gebruikt.
df2.join(df3.set_index('id'), on='id')
| id | Feature1 | Feature2 | Feature3 | |
|---|---|---|---|---|
| 0 | 1 | K | L | 12.0 |
| 1 | 2 | M | N | 13.0 |
| 2 | 6 | O | P | NaN |
| 3 | 7 | Q | R | 17.0 |
| 4 | 8 | S | T | 15.0 |
Net als bij merge kunnen we de joinoperatie wijzigen door een `how`-argument op te geven. In ons geval gebruiken we een inner join.
df2.join(df3.set_index('id'), on='id', how = "inner")
| id_left | Feature1 | Feature2 | Feature3 | |
|---|---|---|---|---|
| 0 | 1 | K | L | 12 |
| 1 | 2 | M | N | 13 |
| 3 | 7 | Q | R | 17 |
| 4 | 8 | S | T | 15 |
Time-series-vriendelijke merges
pandas biedt speciale functies voor het mergen van tijdreeks-DataFrames. Misschien wel de meest bruikbare en populaire is merge_asof(). De merge_asof() lijkt op een geordende left join, behalve dat je matcht op de dichtstbijzijnde sleutel in plaats van gelijke sleutels. Voor elke rij in het linker DataFrame selecteer je de laatste rij in het rechter DataFrame waarvan de on-sleutel kleiner is dan de sleutel van links. Beide DataFrames moeten gesorteerd zijn op de sleutel.
Optioneel kan een asof-merge een groepsgewijze merge uitvoeren. Dit matcht de by-sleutel exact, naast de dichtstbijzijnde match op de on-sleutel.
Stel dat je trades en quotes hebt, en je wilt een asof-merge uitvoeren. Hier wordt het linker DataFrame gekozen als trades en het rechter DataFrame als quotes. Ze worden asof ge-merged op sleutel time en groepsgewijs ge-merged op hun tickersymbool.
trades = pd.DataFrame({
'time': pd.to_datetime(['20160525 13:30:00.023',
'20160525 13:30:00.038',
'20160525 13:30:00.048',
'20160525 13:30:00.048',
'20160525 13:30:00.048']),
'ticker': ['MSFT', 'MSFT','GOOG', 'GOOG', 'AAPL'],
'price': [51.95, 51.95,720.77, 720.92, 98.00],
'quantity': [75, 155,100, 100, 100]},
columns=['time', 'ticker', 'price', 'quantity'])
quotes = pd.DataFrame({
'time': pd.to_datetime(['20160525 13:30:00.023',
'20160525 13:30:00.023',
'20160525 13:30:00.030',
'20160525 13:30:00.041',
'20160525 13:30:00.048',
'20160525 13:30:00.049',
'20160525 13:30:00.072',
'20160525 13:30:00.075']),
'ticker': ['GOOG', 'MSFT', 'MSFT','MSFT', 'GOOG', 'AAPL', 'GOOG','MSFT'],
'bid': [720.50, 51.95, 51.97, 51.99,720.50, 97.99, 720.50, 52.01],
'ask': [720.93, 51.96, 51.98, 52.00,720.93, 98.01, 720.88, 52.03]},
columns=['time', 'ticker', 'bid', 'ask'])
trades
| time | ticker | price | quantity | |
|---|---|---|---|---|
| 0 | 2016-05-25 13:30:00.023 | MSFT | 51.95 | 75 |
| 1 | 2016-05-25 13:30:00.038 | MSFT | 51.95 | 155 |
| 2 | 2016-05-25 13:30:00.048 | GOOG | 720.77 | 100 |
| 3 | 2016-05-25 13:30:00.048 | GOOG | 720.92 | 100 |
| 4 | 2016-05-25 13:30:00.048 | AAPL | 98.00 | 100 |
quotes
| time | ticker | bid | ask | |
|---|---|---|---|---|
| 0 | 2016-05-25 13:30:00.023 | GOOG | 720.50 | 720.93 |
| 1 | 2016-05-25 13:30:00.023 | MSFT | 51.95 | 51.96 |
| 2 | 2016-05-25 13:30:00.030 | MSFT | 51.97 | 51.98 |
| 3 | 2016-05-25 13:30:00.041 | MSFT | 51.99 | 52.00 |
| 4 | 2016-05-25 13:30:00.048 | GOOG | 720.50 | 720.93 |
| 5 | 2016-05-25 13:30:00.049 | AAPL | 97.99 | 98.01 |
| 6 | 2016-05-25 13:30:00.072 | GOOG | 720.50 | 720.88 |
| 7 | 2016-05-25 13:30:00.075 | MSFT | 52.01 | 52.03 |
df_merge_asof = pd.merge_asof(trades, quotes,
on='time',
by='ticker')
df_merge_asof
| time | ticker | price | quantity | bid | ask | |
|---|---|---|---|---|---|---|
| 0 | 2016-05-25 13:30:00.023 | MSFT | 51.95 | 75 | 51.95 | 51.96 |
| 1 | 2016-05-25 13:30:00.038 | MSFT | 51.95 | 155 | 51.97 | 51.98 |
| 2 | 2016-05-25 13:30:00.048 | GOOG | 720.77 | 100 | 720.50 | 720.93 |
| 3 | 2016-05-25 13:30:00.048 | GOOG | 720.92 | 100 | 720.50 | 720.93 |
| 4 | 2016-05-25 13:30:00.048 | AAPL | 98.00 | 100 | NaN | NaN |
Als je goed kijkt, zie je waarom er NaN verschijnt in de rij met de AAPL-ticker. Omdat het rechter DataFrame quotes geen tijdwaarde kleiner dan 13:30:00.048 (de tijd in de linkertabel) voor de AAPL-ticker had, zijn in de kolommen bid en ask NaN's ingevoerd.
Je kunt ook een vooraf ingestelde tolerantie voor de tijdkolom opgeven. Stel dat je alleen een asof-merge wilt binnen 2 ms tussen de quote-tijd en de trade-tijd; dan moet je het argument tolerance opgeven:
df_merge_asof_tolerance = pd.merge_asof(trades, quotes,
on='time',
by='ticker',
tolerance=pd.Timedelta('2ms'))
df_merge_asof_tolerance
| time | ticker | price | quantity | bid | ask | |
|---|---|---|---|---|---|---|
| 0 | 2016-05-25 13:30:00.023 | MSFT | 51.95 | 75 | 51.95 | 51.96 |
| 1 | 2016-05-25 13:30:00.038 | MSFT | 51.95 | 155 | NaN | NaN |
| 2 | 2016-05-25 13:30:00.048 | GOOG | 720.77 | 100 | 720.50 | 720.93 |
| 3 | 2016-05-25 13:30:00.048 | GOOG | 720.92 | 100 | 720.50 | 720.93 |
| 4 | 2016-05-25 13:30:00.048 | AAPL | 98.00 | 100 | NaN | NaN |
Let op het verschil met het vorige resultaat. Rijen worden niet gemerged als de tijdtolerantie niet binnen 2 ms valt.
Conclusie
In deze tutorial heb je geleerd om DataFrames te concateneren en te mergen op basis van verschillende logica's met de functies concat() en merge() van de pandas-bibliotheek. Aan het eind heb je ook geoefend met de speciale functie merge_asof() voor het mergen van tijdreeks-DataFrames. Onderweg heb je ook geleerd te werken met DataFrame-indexen. Er zijn nog veel meer opties die je kunt verkennen voor het joinen van DataFrames in pandas, en ik raad je aan de fantastische documentatie te bekijken. Veel plezier met ontdekken!
Voor het schrijven van deze tutorial is gebruikgemaakt van deze pandas-documentatie.
Wil je meer leren over pandas? Volg dan de DataCamp-cursus Data Manipulation with pandas en bekijk onze DataFrames in Python Pandas Tutorial.
DataCamp heeft ook verschillende andere handige pandas-tutorials, waaronder:
- CSV-data importeren in pandas
- Kolommen toevoegen in pandas
- Waarden sorteren in pandas
- Duplicaten verwijderen in pandas met
drop_duplicates - Data groeperen met pandas groupby
- DataFrame-indexen resetten in pandas
Veel leerplezier!
FAQs
Wat is het verschil tussen merge() en join() in pandas?
merge() is flexibeler en kan DataFrames joinen op willekeurige kolom(men), vergelijkbaar met SQL-joins. join() is primair bedoeld voor joins op indexen en is een gemaksmethode die intern merge() aanroept. Gebruik merge() wanneer je op kolommen joint, en join() wanneer je joinkeys al als index zijn ingesteld.
Hoe merge ik DataFrames op meerdere kolommen in pandas?
Geef een lijst met kolomnamen door aan de parameter on: pd.merge(df1, df2, on=['col1', 'col2']). Als de kolomnamen tussen DataFrames verschillen, gebruik dan left_on en right_on met lijsten: pd.merge(df1, df2, left_on=['a', 'b'], right_on=['c', 'd']).
Wat gebeurt er met missende waarden bij het mergen van DataFrames?
Het gedrag hangt af van het jointype. Bij een inner join worden rijen zonder match uitgesloten. Bij left, right of outer joins blijven niet-gematchte rijen behouden en worden ze gevuld met NaN-waarden in de kolommen van het andere DataFrame. Je kunt deze afhandelen met fillna() of dropna() na het mergen.
Wanneer moet ik concat() versus merge() gebruiken in pandas?
Gebruik concat() om DataFrames verticaal (rijen toevoegen) of horizontaal (kolommen toevoegen) te stapelen op basis van indexuitlijning. Gebruik merge() wanneer je DataFrames wilt combineren op basis van gemeenschappelijke kolomwaarden, vergelijkbaar met SQL-joins. Zie concat() als het "aan elkaar lijmen" van DataFrames, terwijl merge() bedoeld is voor relationele joins.
Hoe ga ik om met dubbele kolomnamen na een pandas-merge?
Standaard voegt pandas de suffixen _x en _y toe aan dubbele kolomnamen. Pas dit aan met de parameter suffixes: pd.merge(df1, df2, on='id', suffixes=('_left', '_right')). Na het mergen kun je kolommen hernoemen met df.rename(columns={'old': 'new'}) of duplicaten verwijderen met df.drop(columns=['col_y']).
Wat is het verschil tussen merge() en join() in pandas?
merge() is flexibeler en kan DataFrames joinen op willekeurige kolom(men), vergelijkbaar met SQL-joins. join() is primair bedoeld voor joins op indexen en is een gemaksmethode die intern merge() aanroept. Gebruik merge() wanneer je op kolommen joint, en join() wanneer je joinkeys al als index zijn ingesteld.
Hoe merge ik DataFrames op meerdere kolommen in pandas?
Geef een lijst met kolomnamen door aan de parameter on: pd.merge(df1, df2, on=['col1', 'col2']). Als de kolomnamen tussen DataFrames verschillen, gebruik dan left_on en right_on met lijsten: pd.merge(df1, df2, left_on=['a', 'b'], right_on=['c', 'd']).
Wat gebeurt er met missende waarden bij het mergen van DataFrames?
Het gedrag hangt af van het jointype. Bij een inner join worden rijen zonder match uitgesloten. Bij left, right of outer joins blijven niet-gematchte rijen behouden en worden ze gevuld met NaN-waarden in de kolommen van het andere DataFrame. Je kunt deze afhandelen met fillna() of dropna() na het mergen.
Wanneer moet ik concat() versus merge() gebruiken in pandas?
Gebruik concat() om DataFrames verticaal (rijen toevoegen) of horizontaal (kolommen toevoegen) te stapelen op basis van indexuitlijning. Gebruik merge() wanneer je DataFrames wilt combineren op basis van gemeenschappelijke kolomwaarden, vergelijkbaar met SQL-joins. Zie concat() als het "aan elkaar lijmen" van DataFrames, terwijl merge() bedoeld is voor relationele joins.
Hoe ga ik om met dubbele kolomnamen na een pandas-merge?
Standaard voegt pandas de suffixen _x en _y toe aan dubbele kolomnamen. Pas dit aan met de parameter suffixes: pd.merge(df1, df2, on='id', suffixes=('_left', '_right')). Na het mergen kun je kolommen hernoemen met df.rename(columns={'old': 'new'}) of duplicaten verwijderen met df.drop(columns=['col_y']).
