realed 2026.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
realed-2026.8/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Roman Yasinovskyy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
realed-2026.8/PKG-INFO ADDED
@@ -0,0 +1,443 @@
1
+ Metadata-Version: 2.4
2
+ Name: realed
3
+ Version: 2026.8
4
+ Summary: Relational Algebra for Educational purposes
5
+ Author: Roman Yasinovskyy
6
+ Author-email: Roman Yasinovskyy <yasinovskyy@gmail.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Education
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Topic :: Education
16
+ Requires-Dist: numpy>=2.5.0
17
+ Requires-Dist: pandas>=3.0.5
18
+ Requires-Python: >=3.12
19
+ Project-URL: Homepage, https://github.com/yasinovskyy/realed
20
+ Project-URL: Issues, https://github.com/yasinovskyy/realed/issues
21
+ Description-Content-Type: text/markdown
22
+
23
+ # *ReAlEd*: Relational Algebra for Education
24
+
25
+ A simple wrapper around `pandas` to demonstrate common relational algebra operations:
26
+
27
+ - Selection (`select`)
28
+ - Projection (`project`)
29
+ - Renaming (`rename`)
30
+ - Extending (`extend`)
31
+ - Sorting (`sort`)
32
+ - Grouping (`groupby`)
33
+ - Cartesian product (`product`)
34
+ - Concatenation (`union`)
35
+ - Natural join (`njoin`)
36
+ - Equijoin (`ejoin`)
37
+ - Semijoin (`sjoin`)
38
+ - Antijoin (`ajoin`)
39
+ - Outer join (`ojoin`)
40
+
41
+ This implementation is a thin layer above the underlying `DataFrame` with some error handling and data cleaning added to make the resulting operations match those of the relational algebra.
42
+
43
+ Each operation returns a new relation without modifying the original.
44
+ Operations can be chained in various combinations.
45
+
46
+ It is a rewrite of [Brad Miller's reframe](https://github.com/bnmnetp/reframe) with the following major differences:
47
+
48
+ - expanded list of operations (various joins)
49
+ - the more recent version of `pandas` as a dependency
50
+ - composition used instead of inheritance
51
+
52
+ ## Initialization
53
+
54
+ A new relation can be created from a CSV file, a `DataFrame`, or another `Relation`.
55
+ Some arguments can be passed to the constructor in order to override defaults used by `pandas`:
56
+
57
+ ```python
58
+ penguins = Relation("palmerpenguins.csv")
59
+ penguins = Relation("palmerpenguins.csv", sep=",")
60
+ ```
61
+
62
+ Test data includes [Palmer penguins](https://allisonhorst.github.io/palmerpenguins/) and information about a couple Palmer islands to demonstrate multi-relation operations.
63
+
64
+ ```python
65
+ >>> from realed import Relation
66
+ >>> penguins = Relation("palmerpenguins.csv")
67
+ >>> penguins
68
+ rowid species island bill_length_mm ... flipper_length_mm body_mass_g sex year
69
+ 0 1 Adelie Torgersen 39.1 ... 181.0 3750.0 male 2007
70
+ 1 2 Adelie Torgersen 39.5 ... 186.0 3800.0 female 2007
71
+ 2 3 Adelie Torgersen 40.3 ... 195.0 3250.0 female 2007
72
+ 3 4 Adelie Torgersen NaN ... NaN NaN NaN 2007
73
+ 4 5 Adelie Torgersen 36.7 ... 193.0 3450.0 female 2007
74
+ .. ... ... ... ... ... ... ... ... ...
75
+ 339 340 Chinstrap Dream 55.8 ... 207.0 4000.0 male 2009
76
+ 340 341 Chinstrap Dream 43.5 ... 202.0 3400.0 female 2009
77
+ 341 342 Chinstrap Dream 49.6 ... 193.0 3775.0 male 2009
78
+ 342 343 Chinstrap Dream 50.8 ... 210.0 4100.0 male 2009
79
+ 343 344 Chinstrap Dream 50.2 ... 198.0 3775.0 female 2009
80
+ >>> islands = Relation("palmerislands.csv")
81
+ >>> islands
82
+ id island explored expedition name_origin
83
+ 0 1 Amsler 1955 Falkland Islands Dependencies Survey Margaret Amsler
84
+ 1 2 Anvers 1832 Southern Ocean Expedition Antwerp province
85
+ 2 3 Biscoe 1832 Southern Ocean Expedition John Biscoe
86
+ 3 4 Christiania 1898 Belgian Antarctic Expedition Oslo
87
+ 4 5 Dream 1956 British Naval Hydrographic Survey Unit Natural features
88
+ 5 6 Torgersen 1955 Falkland Islands Dependencies Survey Torstein Torgersen
89
+ >>>
90
+ ```
91
+
92
+ Certain helper methods and properties are available:
93
+
94
+ - property `data`: internal `DataFrame`
95
+ - property `columns`: names of the attributes
96
+ - property `dim`: dimensions of the relation (rows, columns)
97
+ - property `one`: the first record of the relation as a dictionary
98
+ - method `head`: return the first couple of records
99
+ - method `tail`: return the last couple of records
100
+ - method `to_csv`: export the `data` to a csv file
101
+ - method `copy`: deep copy of the `data`
102
+ - method `cleanup`: removal of empty records
103
+ - method `equals`: comparison of two relations
104
+ - method `minus`: difference between two relations
105
+ - method `intersection`: intersection of two relations
106
+
107
+ ## Selection (`select`)
108
+
109
+ Selection is a simplified version of the `query` method available in `pandas.DataFrame`.
110
+ It only takes one argument, the query expression.
111
+
112
+ ```python
113
+ >>> islands.select("expedition == 'Southern Ocean Expedition'")
114
+ id island explored expedition name_origin
115
+ 1 2 Anvers 1832 Southern Ocean Expedition Antwerp province
116
+ 2 3 Biscoe 1832 Southern Ocean Expedition John Biscoe
117
+ >>>
118
+ ```
119
+
120
+ ```python
121
+ >>> penguins.select("species == 'Adelie' and island == 'Torgersen' and year == 2009 and body_mass_g >= 4000")
122
+ rowid species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
123
+ 125 126 Adelie Torgersen 40.6 19.0 199.0 4000.0 male 2009
124
+ 127 128 Adelie Torgersen 41.5 18.3 195.0 4300.0 male 2009
125
+ 129 130 Adelie Torgersen 44.1 18.0 210.0 4000.0 male 2009
126
+ ```
127
+
128
+ Since each operation returns a `Relation`, operations can be chained:
129
+
130
+ ```python
131
+ >>> penguins.select("species == 'Adelie'").select("island == 'Torgersen'").select("year == 2009").select("body_mass_g >= 4000")
132
+ rowid species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
133
+ 125 126 Adelie Torgersen 40.6 19.0 199.0 4000.0 male 2009
134
+ 127 128 Adelie Torgersen 41.5 18.3 195.0 4300.0 male 2009
135
+ 129 130 Adelie Torgersen 44.1 18.0 210.0 4000.0 male 2009
136
+ ```
137
+
138
+ A separate method,`query`, is also available.
139
+ It passes all provided named arguments and keyword arguments to the `query` method of the `pandas.DataFrame`.
140
+
141
+ ## Projection (`project`)
142
+
143
+ For the sake of consistency names of attributes must be a list of strings, even if a single attribute is being projected.
144
+
145
+ ```python
146
+ >>> penguins.project(["island"])
147
+ island
148
+ 0 Torgersen
149
+ 20 Biscoe
150
+ 30 Dream
151
+ >>> penguins.project(["species", "island"])
152
+ species island
153
+ 0 Adelie Torgersen
154
+ 20 Adelie Biscoe
155
+ 30 Adelie Dream
156
+ 152 Gentoo Biscoe
157
+ 276 Chinstrap Dream
158
+ >>>
159
+ ```
160
+
161
+ ## Renaming (`rename`)
162
+
163
+ If the old name is not among the attributes or the new name is already there, a `ValueError` is raised.
164
+
165
+ ```python
166
+ >>> penguins.rename("island", "location").project(["species", "location"])
167
+ species location
168
+ 0 Adelie Torgersen
169
+ 20 Adelie Biscoe
170
+ 30 Adelie Dream
171
+ 152 Gentoo Biscoe
172
+ 276 Chinstrap Dream
173
+ >>>
174
+ ```
175
+
176
+ ## Sorting (`sort`)
177
+
178
+ ```python
179
+ >>> islands.sort(["explored"])
180
+ id island explored expedition name_origin
181
+ 1 2 Anvers 1832 Southern Ocean Expedition Antwerp province
182
+ 2 3 Biscoe 1832 Southern Ocean Expedition John Biscoe
183
+ 3 4 Christiania 1898 Belgian Antarctic Expedition Oslo
184
+ 0 1 Amsler 1955 Falkland Islands Dependencies Survey Margaret Amsler
185
+ 5 6 Torgersen 1955 Falkland Islands Dependencies Survey Torstein Torgersen
186
+ 4 5 Dream 1956 British Naval Hydrographic Survey Unit Natural features
187
+ >>> islands.sort(["explored"], ascending=False)
188
+ id island explored expedition name_origin
189
+ 4 5 Dream 1956 British Naval Hydrographic Survey Unit Natural features
190
+ 0 1 Amsler 1955 Falkland Islands Dependencies Survey Margaret Amsler
191
+ 5 6 Torgersen 1955 Falkland Islands Dependencies Survey Torstein Torgersen
192
+ 3 4 Christiania 1898 Belgian Antarctic Expedition Oslo
193
+ 1 2 Anvers 1832 Southern Ocean Expedition Antwerp province
194
+ 2 3 Biscoe 1832 Southern Ocean Expedition John Biscoe
195
+ ```
196
+
197
+ ```python
198
+ >>> penguins.sort(["species", "rowid"]).head(3)
199
+ rowid species island bill_length_mm ... flipper_length_mm body_mass_g sex year
200
+ 0 1 Adelie Torgersen 39.1 ... 181.0 3750.0 male 2007
201
+ 1 2 Adelie Torgersen 39.5 ... 186.0 3800.0 female 2007
202
+ 2 3 Adelie Torgersen 40.3 ... 195.0 3250.0 female 2007
203
+ ```
204
+
205
+ Be mindful of the order of sorting operations.
206
+
207
+ ```python
208
+ >>> penguins.sort(["body_mass_g"], ascending=False).sort(["species"]).head(3)
209
+ rowid species island bill_length_mm ... flipper_length_mm body_mass_g sex year
210
+ 111 112 Adelie Biscoe 45.6 ... 191.0 4600.0 male 2009
211
+ 76 77 Adelie Torgersen 40.9 ... 191.0 3700.0 female 2008
212
+ 14 15 Adelie Torgersen 34.6 ... 198.0 4400.0 male 2007
213
+ >>> penguins.sort(["species"]).sort(["body_mass_g"], ascending=False).head(3)
214
+ rowid species island bill_length_mm ... flipper_length_mm body_mass_g sex year
215
+ 169 170 Gentoo Biscoe 49.2 ... 221.0 6300.0 male 2007
216
+ 185 186 Gentoo Biscoe 59.6 ... 230.0 6050.0 male 2007
217
+ 269 270 Gentoo Biscoe 48.8 ... 222.0 6000.0 male 2009
218
+ ```
219
+
220
+ ## Extending (`extend`)
221
+
222
+ The new name cannot match the name of an existing attribute.
223
+ New data must be a of type `pandas.Series`.
224
+
225
+ ```python
226
+ >>> penguins.extend("years_since_study", 2026-penguins["year"])
227
+ rowid species island bill_length_mm ... body_mass_g sex year years_since_study
228
+ 0 1 Adelie Torgersen 39.1 ... 3750.0 male 2007 19
229
+ 1 2 Adelie Torgersen 39.5 ... 3800.0 female 2007 19
230
+ 2 3 Adelie Torgersen 40.3 ... 3250.0 female 2007 19
231
+ 3 4 Adelie Torgersen NaN ... NaN NaN 2007 19
232
+ 4 5 Adelie Torgersen 36.7 ... 3450.0 female 2007 19
233
+ .. ... ... ... ... ... ... ... ... ...
234
+ 339 340 Chinstrap Dream 55.8 ... 4000.0 male 2009 17
235
+ 340 341 Chinstrap Dream 43.5 ... 3400.0 female 2009 17
236
+ 341 342 Chinstrap Dream 49.6 ... 3775.0 male 2009 17
237
+ 342 343 Chinstrap Dream 50.8 ... 4100.0 male 2009 17
238
+ 343 344 Chinstrap Dream 50.2 ... 3775.0 female 2009 17
239
+ >>>
240
+ ```
241
+
242
+ ## Grouping (`groupby`) and aggregation
243
+
244
+ Grouping without an aggregate function eliminates duplicates in the chosen categories.
245
+
246
+ ```python
247
+ >>> penguins.groupby(["species"])
248
+ species
249
+ 0 Adelie
250
+ 1 Chinstrap
251
+ 2 Gentoo
252
+ ```
253
+
254
+ Typically, grouping is followed by an aggregate function `count`, `sum`, `min`, `max`, `mean` (`avg`), or `median`.
255
+ The aggregate function is added as a prefix to the name of the resulting column.
256
+
257
+ ```python
258
+ >>> penguins.groupby(["species"]).count("rowid")
259
+ species count_rowid
260
+ 0 Adelie 152
261
+ 1 Chinstrap 68
262
+ 2 Gentoo 124
263
+ >>> penguins.groupby(["island"]).count("rowid")
264
+ island count_rowid
265
+ 0 Biscoe 168
266
+ 1 Dream 124
267
+ 2 Torgersen 52
268
+ >>> penguins.groupby(["species", "island"]).count("rowid")
269
+ species island count_rowid
270
+ 0 Adelie Biscoe 44
271
+ 1 Adelie Dream 56
272
+ 2 Adelie Torgersen 52
273
+ 3 Chinstrap Dream 68
274
+ 4 Gentoo Biscoe 124
275
+ >>> penguins.groupby(["island"]).sum("body_mass_g")
276
+ island sum_body_mass_g
277
+ 0 Biscoe 787575.0
278
+ 1 Dream 460400.0
279
+ 2 Torgersen 189025.0
280
+ >>> penguins.groupby(["island"]).min("body_mass_g")
281
+ island min_body_mass_g
282
+ 0 Biscoe 2850.0
283
+ 1 Dream 2700.0
284
+ 2 Torgersen 2900.0
285
+ >>> penguins.groupby(["island"]).max("body_mass_g")
286
+ island max_body_mass_g
287
+ 0 Biscoe 6300.0
288
+ 1 Dream 4800.0
289
+ 2 Torgersen 4700.0
290
+ >>> penguins.groupby(["island"]).mean("body_mass_g")
291
+ island mean_body_mass_g
292
+ 0 Biscoe 4716.017964
293
+ 1 Dream 3712.903226
294
+ 2 Torgersen 3706.372549
295
+ >>> penguins.groupby(["island"]).avg("body_mass_g")
296
+ island avg_body_mass_g
297
+ 0 Biscoe 4716.017964
298
+ 1 Dream 3712.903226
299
+ 2 Torgersen 3706.372549
300
+ >>> penguins.groupby(["island"]).median("body_mass_g")
301
+ island median_body_mass_g
302
+ 0 Biscoe 4775.0
303
+ 1 Dream 3687.5
304
+ 2 Torgersen 3700.0
305
+ ```
306
+
307
+ ## Cartesian product (`product`)
308
+
309
+ Two relations must have disjoint attributes for this operation to work.
310
+
311
+ ```python
312
+ >>> penguins.product(islands.rename("island", "name"))
313
+ rowid species ... expedition name_origin
314
+ 0 1 Adelie ... Falkland Islands Dependencies Survey Margaret Amsler
315
+ 1 1 Adelie ... Southern Ocean Expedition Antwerp province
316
+ 2 1 Adelie ... Southern Ocean Expedition John Biscoe
317
+ 3 1 Adelie ... Belgian Antarctic Expedition Oslo
318
+ 4 1 Adelie ... British Naval Hydrographic Survey Unit Natural features
319
+ ... ... ... ... ... ...
320
+ 2059 344 Chinstrap ... Southern Ocean Expedition Antwerp province
321
+ 2060 344 Chinstrap ... Southern Ocean Expedition John Biscoe
322
+ 2061 344 Chinstrap ... Belgian Antarctic Expedition Oslo
323
+ 2062 344 Chinstrap ... British Naval Hydrographic Survey Unit Natural features
324
+ 2063 344 Chinstrap ... Falkland Islands Dependencies Survey Torstein Torgersen
325
+ ```
326
+
327
+ ## Concatenation (`union`)
328
+
329
+ Attributes of both relations must be the same.
330
+
331
+ ```python
332
+ >>> penguins.select("species == 'Adelie'").union(penguins.select("species == 'Gentoo'"))
333
+ rowid species island bill_length_mm ... flipper_length_mm body_mass_g sex year
334
+ 0 1 Adelie Torgersen 39.1 ... 181.0 3750.0 male 2007
335
+ 1 2 Adelie Torgersen 39.5 ... 186.0 3800.0 female 2007
336
+ 2 3 Adelie Torgersen 40.3 ... 195.0 3250.0 female 2007
337
+ 3 4 Adelie Torgersen NaN ... NaN NaN NaN 2007
338
+ 4 5 Adelie Torgersen 36.7 ... 193.0 3450.0 female 2007
339
+ .. ... ... ... ... ... ... ... ... ...
340
+ 271 272 Gentoo Biscoe NaN ... NaN NaN NaN 2009
341
+ 272 273 Gentoo Biscoe 46.8 ... 215.0 4850.0 female 2009
342
+ 273 274 Gentoo Biscoe 50.4 ... 222.0 5750.0 male 2009
343
+ 274 275 Gentoo Biscoe 45.2 ... 212.0 5200.0 female 2009
344
+ 275 276 Gentoo Biscoe 49.9 ... 213.0 5400.0 male 2009
345
+ ```
346
+
347
+ ## Natural join (`naturaljoin` or `njoin`)
348
+
349
+ There must be at least one common attribute in both relations.
350
+
351
+ ```python
352
+ >>> penguins.njoin(islands)
353
+ rowid species island ... explored expedition name_origin
354
+ 0 1 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
355
+ 1 2 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
356
+ 2 3 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
357
+ 3 4 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
358
+ 4 5 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
359
+ .. ... ... ... ... ... ... ...
360
+ 339 340 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
361
+ 340 341 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
362
+ 341 342 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
363
+ 342 343 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
364
+ 343 344 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
365
+ ```
366
+
367
+ ## Equijoin (`equijoin` or `ejoin`)
368
+
369
+ A simple version of the theta-join that checks two attributes for equality.
370
+ Both left and right attributes must be strings.
371
+
372
+ ```python
373
+ >>> penguins.ejoin(islands, "island", "island")
374
+ rowid species island ... explored expedition name_origin
375
+ 0 1 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
376
+ 1 2 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
377
+ 2 3 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
378
+ 3 4 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
379
+ 4 5 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
380
+ .. ... ... ... ... ... ... ...
381
+ 339 340 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
382
+ 340 341 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
383
+ 341 342 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
384
+ 342 343 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
385
+ 343 344 Chinstrap Dream ... 1956 British Naval Hydrographic Survey Unit Natural features
386
+ ```
387
+
388
+ ## Semijoin (`semijoin` or `sjoin`)
389
+
390
+ Both left and right attributes must be strings.
391
+
392
+ ```python
393
+ >>> islands.sjoin(penguins, "island", "island")
394
+ id island explored expedition name_origin
395
+ 2 3 Biscoe 1832 Southern Ocean Expedition John Biscoe
396
+ 4 5 Dream 1956 British Naval Hydrographic Survey Unit Natural features
397
+ 5 6 Torgersen 1955 Falkland Islands Dependencies Survey Torstein Torgersen
398
+ ```
399
+
400
+ ## Antijoin (`antijoin` or `ajoin`)
401
+
402
+ Both left and right attributes must be strings.
403
+
404
+ ```python
405
+ >>> islands.ajoin(penguins, "island", "island")
406
+ id island explored expedition name_origin
407
+ 0 1 Amsler 1955 Falkland Islands Dependencies Survey Margaret Amsler
408
+ 1 2 Anvers 1832 Southern Ocean Expedition Antwerp province
409
+ 3 4 Christiania 1898 Belgian Antarctic Expedition Oslo
410
+ ```
411
+
412
+ ## Outer join (`outerjoin` or `ojoin`)
413
+
414
+ Full outer join.
415
+
416
+ ```python
417
+ >>> islands.ojoin(penguins)
418
+ id island explored ... body_mass_g sex year
419
+ 0 1 Amsler 1955 ... NaN NaN NaN
420
+ 1 2 Anvers 1832 ... NaN NaN NaN
421
+ 2 3 Biscoe 1832 ... 3400.0 female 2007.0
422
+ 3 3 Biscoe 1832 ... 3600.0 male 2007.0
423
+ 4 3 Biscoe 1832 ... 3800.0 female 2007.0
424
+ .. .. ... ... ... ... ... ...
425
+ 342 6 Torgersen 1955 ... 4300.0 male 2009.0
426
+ 343 6 Torgersen 1955 ... 3050.0 female 2009.0
427
+ 344 6 Torgersen 1955 ... 4000.0 male 2009.0
428
+ 345 6 Torgersen 1955 ... 3325.0 female 2009.0
429
+ 346 6 Torgersen 1955 ... 3500.0 male 2009.0
430
+ >>> penguins.ojoin(islands)
431
+ rowid species island ... explored expedition name_origin
432
+ 0 NaN NaN Amsler ... 1955 Falkland Islands Dependencies Survey Margaret Amsler
433
+ 1 NaN NaN Anvers ... 1832 Southern Ocean Expedition Antwerp province
434
+ 2 21.0 Adelie Biscoe ... 1832 Southern Ocean Expedition John Biscoe
435
+ 3 22.0 Adelie Biscoe ... 1832 Southern Ocean Expedition John Biscoe
436
+ 4 23.0 Adelie Biscoe ... 1832 Southern Ocean Expedition John Biscoe
437
+ .. ... ... ... ... ... ... ...
438
+ 342 128.0 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
439
+ 343 129.0 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
440
+ 344 130.0 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
441
+ 345 131.0 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
442
+ 346 132.0 Adelie Torgersen ... 1955 Falkland Islands Dependencies Survey Torstein Torgersen
443
+ ```