Skip to content

Commit cd86810

Browse files
committed
Post-workshop edits
1 parent db49710 commit cd86810

2 files changed

Lines changed: 273 additions & 155 deletions

File tree

README.md

Lines changed: 120 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,11 @@ help(math) # user friendly
456456
```
457457
458458
``` python
459-
dir(math) # brief reminder, not user friendly
459+
print(dir(math)) # brief reminder, not user friendly
460+
```
461+
462+
``` python
463+
help(math.factorial)
460464
```
461465
462466
### (Optional) Import shortcuts
@@ -1102,23 +1106,23 @@ Introductory documentation: <https://numpy.org/doc/stable/user/quickstart.html>
11021106
import numpy as np
11031107
11041108
# Create an array of random numbers
1105-
m_rand = np.random.rand(3, 4)
1106-
print(m_rand)
1109+
mat = np.arange(12).reshape(3,4)
1110+
print(mat)
11071111
```
11081112
11091113
2. Arrays are indexed like lists
11101114
11111115
``` python
1112-
print(m_rand[0,0])
1116+
print(mat[0,0])
11131117
```
11141118
11151119
3. Arrays have attributes
11161120
11171121
``` python
1118-
print(m_rand.shape)
1119-
print(m_rand.size)
1120-
print(m_rand.ndim)
1121-
print(m_rand.T)
1122+
print(mat.shape)
1123+
print(mat.size)
1124+
print(mat.ndim)
1125+
print(mat.T)
11221126
```
11231127
11241128
4. Arrays are fast but inflexible - the entire array must be of a single type.
@@ -1151,18 +1155,7 @@ print(y)
11511155
print(np.dot(x, y))
11521156
```
11531157
1154-
3. You can rearrange the same array into different configurations
1155-
1156-
``` python
1157-
# Use method chaining to link actions together
1158-
x1 = x.reshape(3,3)
1159-
x2 = x.reshape(9,1)
1160-
1161-
print(x1)
1162-
print(x2)
1163-
```
1164-
1165-
4. (Optional) Matlab gotcha: 1-D arrays have no transpose
1158+
3. (Optional) Matlab gotcha: 1-D arrays have no transpose
11661159
11671160
``` python
11681161
print(x)
@@ -1398,7 +1391,7 @@ This is most common way to get data
13981391
3. If you want specific rows or columns, pass in a list
13991392
14001393
``` python
1401-
data.loc[['Italy','Poland'], :]
1394+
data.loc[['Italy','Poland'], ["1952","1962"]]
14021395
```
14031396
14041397
4. (Optional) `.iloc` follows list index conventions ("up to, but not including)", but `.loc` does the intuitive right thing ("A through B")
@@ -1451,6 +1444,25 @@ This is most common way to get data
14511444
print(subset.max(axis=None))
14521445
```
14531446
1447+
\*\*\*( Optional) Get x/y labels for the cell that matches a criterion
1448+
1449+
``` python
1450+
# Which values match the criterion?
1451+
subset == subset.max().max()
1452+
1453+
# Return value at position, code all other cells as NA
1454+
val = subset[subset == subset.max().max()]
1455+
1456+
# Drop rows where all values are NA, then drop columns where values are NA
1457+
val.dropna(how="all").dropna(axis=1)
1458+
1459+
# Putting it all together: Get index label and column label for last remaining cell
1460+
names = val.dropna(how="all").dropna(axis=1)
1461+
1462+
print(names.index[0])
1463+
print(names.columns[0])
1464+
```
1465+
14541466
### (Optional) Filter on label properties
14551467
14561468
1. `.filter()` always returns the same type as the original item, whereas `.loc` and `.iloc` might return a data frame or a series.
@@ -1738,7 +1750,37 @@ print(df3.shape)
17381750
print(df_join.head())
17391751
```
17401752
1741-
3. The resulting table loses its index because `surveys.record_id` is not being used in the join. To keep `record_id` as the index for the final table, we need to retain it as an explicit column.
1753+
3. Use the additional information in the joined data set to inform your analyses:
1754+
1755+
``` python
1756+
# Get mean weight for each taxa group
1757+
df_join.groupby("taxa")["weight"].mean()
1758+
```
1759+
1760+
``` python
1761+
# Get group means for multiple variables
1762+
df_join.groupby("taxa")[["weight", "hindfoot_length"]].mean()
1763+
```
1764+
1765+
``` python
1766+
# Get nested group means
1767+
df_join.groupby(["taxa", "genus"])[["weight", "hindfoot_length"]].mean()
1768+
```
1769+
1770+
4. Verify that weight data is missing for non-rodents. This works for `str` but not `obj`; if text data has been imported as `obj`, re-cast it to `str`.
1771+
1772+
``` python
1773+
# Convert column to type "str" if necessary
1774+
df_join["taxa"] = df_join["taxa"].astype("str")
1775+
1776+
# Verify that there aren't any "weight" values for Birds
1777+
df_bird = df_join[df_join["taxa"].str.startswith("Bird")]
1778+
1779+
print(df_bird["weight"].isna().sum())
1780+
print(df_bird["weight"].isna().all())
1781+
```
1782+
1783+
5. (Optional) The resulting table loses its index because `surveys.record_id` is not being used in the join. To keep `record_id` as the index for the final table, we need to retain it as an explicit column.
17421784
17431785
``` python
17441786
# Don't set record_id as index during initial import
@@ -1748,7 +1790,7 @@ print(df3.shape)
17481790
df_join.head()
17491791
```
17501792
1751-
4. Aside: Method chaining formatting options
1793+
6. Aside: Method chaining formatting options
17521794
17531795
``` python
17541796
# Python allows free line breaks inside parens
@@ -1770,7 +1812,7 @@ print(df3.shape)
17701812
.set_index("record_id")
17711813
```
17721814
1773-
5. Get the subset of species that match a criterion, and join on that subset. The "inner" join only includes rows where both tables match on the key column; it's a strategy for filtering the first table by the second table.
1815+
7. Get the subset of species that match a criterion, and join on that subset. The "inner" join only includes rows where both tables match on the key column; it's a strategy for filtering the first table by the second table.
17741816
17751817
``` python
17761818
# Get the taxa column, masking the rows based on which values match "Bird"
@@ -1783,7 +1825,7 @@ print(df3.shape)
17831825
print(df_inner.head())
17841826
```
17851827
1786-
6. Compare with the results of the left join
1828+
8. Compare with the results of the left join
17871829
17881830
``` python
17891831
df_surveys_left = surveys.merge(birds, on="species_id", how="left").set_index("record_id")
@@ -1827,7 +1869,7 @@ cf. <https://pandas.pydata.org/docs/user_guide/text.html>
18271869
print(dir(species["genus"].str))
18281870
```
18291871
1830-
3. Use string methods for filtering
1872+
3. Use string methods for filtering. This works for `str` but not `obj`; if text data has been imported as `obj`, re-cast it to `str`.
18311873
18321874
``` python
18331875
# Which species are in the taxa "Bird"?
@@ -2270,18 +2312,13 @@ Python steps through the branches of the conditional in order, testing each in t
22702312
Often, you want some combination of things to be true. You can combine relations within a conditional using `and` and `or`.
22712313
22722314
``` python
2273-
mass = [1, 2, 3, 4, 5]
2274-
velocity = [5, 4, 3, 2, 5]
2315+
mass = [1, 2, 3, 4]
2316+
velocity = [4, 3, 2, 1]
22752317
22762318
for m, v in zip(mass, velocity):
2277-
if m <= 3 and v <= 3:
2278-
print("Small and slow")
2279-
elif m <= 3 and v > 3:
2280-
print("Small and fast")
2281-
elif m > 3 and v <= 3:
2282-
print("Large and slow")
2283-
else:
2284-
print("Check data")
2319+
print(m, v)
2320+
if m < 2 or v > 2:
2321+
print("At least one of our critera is true")
22852322
```
22862323
22872324
- Use () to group subsets of conditions
@@ -2333,41 +2370,63 @@ print_greeting()
23332370
1. Positional arguments
23342371
23352372
``` python
2336-
def print_date(year, month, day):
2373+
def format_date(year, month, day):
23372374
"""Print the formatted date. This works with strings or integers."""
23382375
23392376
formatted_date = f"{year}/{month}/{day}"
23402377
print(formatted_date)
23412378
2342-
print_date(1871, 3, 19)
2379+
format_date(1871, 3, 19)
23432380
```
23442381
23452382
2. (Optional) Keyword arguments
23462383
23472384
``` python
2348-
print_date(month=3, day=19, year=1871)
2385+
format_date(month=3, day=19, year=1871)
23492386
```
23502387
23512388
### Functions may return a result to their caller using `return`
23522389
23532390
1. Use `return ...` to give a value back to the caller. `return` ends the function's execution and *returns* you to the code that originally called the function.
23542391
2392+
``` python
2393+
def format_date(year, month, day):
2394+
"""Print the formatted date. This works with strings or integers."""
2395+
2396+
formatted_date = f"{year}/{month}/{day}"
2397+
return formatted_date
2398+
2399+
d = format_date(1871, 3, 19)
2400+
print(d)
2401+
```
2402+
2403+
2. You should explicitly handle common problems. Start with a simple base function.
2404+
23552405
``` python
23562406
def average(values):
23572407
"""Return average of values."""
23582408
23592409
return sum(values) / len(values)
23602410
```
23612411
2412+
3. Test your function on inputs that should work.
2413+
23622414
``` python
2363-
a = average([1, 3, 4])
2415+
a = average([1, 2, 3, 4])
23642416
print(a)
23652417
```
23662418
2367-
2. You should explicitly handle common problems:
2419+
4. Test against edge cases and erroneous input.
2420+
2421+
``` python
2422+
test1 = []
2423+
test2 = ["a", "b", "c", "d"]
2424+
```
2425+
2426+
5. Revise based on test results.
23682427
23692428
``` python
2370-
print(average([]))
2429+
av1 = average(test1)
23712430
```
23722431
23732432
``` python
@@ -2380,7 +2439,25 @@ print_greeting()
23802439
return sum(values) / len(values)
23812440
```
23822441
2383-
3. Notes:
2442+
6. You can choose to handle errors within the function, or by validating input ahead of time. Either choice is defensible, just be consistent.
2443+
2444+
``` python
2445+
av2 = average(test2)
2446+
```
2447+
2448+
``` python
2449+
def average(values):
2450+
"""Return average of values, or None if no values are supplied."""
2451+
2452+
if len(values) == 0:
2453+
return None
2454+
elif all([type(x) == int for x in values]):
2455+
return sum(values) / len(values)
2456+
else:
2457+
return None
2458+
```
2459+
2460+
7. Notes:
23842461
23852462
1. `return` can occur anywhere in the function, but functions are easier to understand if return occurs:
23862463
1. At the start to handle special cases

0 commit comments

Comments
 (0)