Statement of Completion#8a8016d4
Intro to Pandas for Data Analysis
easy
Practicing filtering sorting with Pokemon
Resolution
Activities
Task 0 - Setup¶
There isn't much to do here, we'll provide the required imports and the read the pokemon CSV we'll be working with.
In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
In [2]:
df = pd.read_csv("pokemon.csv")
In [3]:
df.head()
Out[3]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | Bulbasaur | Grass | Poison | 318 | 45 | 49 | 49 | 65 | 65 | 45 | 1 | False |
1 | 2 | Ivysaur | Grass | Poison | 405 | 60 | 62 | 63 | 80 | 80 | 60 | 1 | False |
2 | 3 | Venusaur | Grass | Poison | 525 | 80 | 82 | 83 | 100 | 100 | 80 | 1 | False |
3 | 4 | Charmander | Fire | NaN | 309 | 39 | 52 | 43 | 60 | 50 | 65 | 1 | False |
4 | 5 | Charmeleon | Fire | NaN | 405 | 58 | 64 | 58 | 80 | 65 | 80 | 1 | False |
In [4]:
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 721 entries, 0 to 720 Data columns (total 13 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 # 721 non-null int64 1 Name 721 non-null object 2 Type 1 721 non-null object 3 Type 2 359 non-null object 4 Total 721 non-null int64 5 HP 721 non-null int64 6 Attack 721 non-null int64 7 Defense 721 non-null int64 8 Sp. Atk 721 non-null int64 9 Sp. Def 721 non-null int64 10 Speed 721 non-null int64 11 Generation 721 non-null int64 12 Legendary 721 non-null bool dtypes: bool(1), int64(9), object(3) memory usage: 68.4+ KB
In [5]:
df.describe()
Out[5]:
# | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | |
---|---|---|---|---|---|---|---|---|---|
count | 721.00000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 |
mean | 361.00000 | 417.945908 | 68.380028 | 75.124827 | 70.697642 | 68.848821 | 69.180305 | 65.714286 | 3.323162 |
std | 208.27906 | 109.663671 | 25.848272 | 29.070335 | 29.194941 | 28.898590 | 26.899364 | 27.277920 | 1.669873 |
min | 1.00000 | 180.000000 | 1.000000 | 5.000000 | 5.000000 | 10.000000 | 20.000000 | 5.000000 | 1.000000 |
25% | 181.00000 | 320.000000 | 50.000000 | 54.000000 | 50.000000 | 45.000000 | 50.000000 | 45.000000 | 2.000000 |
50% | 361.00000 | 424.000000 | 65.000000 | 75.000000 | 65.000000 | 65.000000 | 65.000000 | 65.000000 | 3.000000 |
75% | 541.00000 | 499.000000 | 80.000000 | 95.000000 | 85.000000 | 90.000000 | 85.000000 | 85.000000 | 5.000000 |
max | 721.00000 | 720.000000 | 255.000000 | 165.000000 | 230.000000 | 154.000000 | 230.000000 | 160.000000 | 6.000000 |
Distribution of Pokemon Types:¶
In [6]:
df['Type 1'].value_counts().plot(kind='pie', autopct='%1.1f%%', cmap='tab20c', figsize=(10, 8))
Out[6]:
<Axes: ylabel='count'>
Distribution of Pokemon Totals:¶
In [7]:
df['Total'].plot(kind='hist', figsize=(10, 8))
Out[7]:
<Axes: ylabel='Frequency'>
In [8]:
df['Total'].plot(kind='box', vert=False, figsize=(10, 5))
Out[8]:
<Axes: >
Distribution of Legendary Pokemons:¶
In [9]:
df['Legendary'].value_counts().plot(kind='pie', autopct='%1.1f%%', cmap='Set3', figsize=(10, 8))
Out[9]:
<Axes: ylabel='count'>
Basic filtering¶
Let's start with a few simple activities regarding filtering.
1. How many Pokemons exist with an Attack
value greater than 150?¶
Doing a little bit of visual exploration, we can have a sense of the most "powerful" pokemons (defined by their "Attack" feature). A boxplot is a great way to visualize this:
In [10]:
sns.boxplot(data=df, x='Attack')
Out[10]:
<Axes: xlabel='Attack'>
In [11]:
# Try your code here
df.loc[df['Attack'] > 150].shape
Out[11]:
(3, 13)
2. Select all pokemons with a Speed of 10
or less¶
In [ ]:
sns.boxplot(data=df, x='Speed')
In [12]:
slow_pokemons_df = df.loc[df['Speed'] <= 10]
slow_pokemons_df
Out[12]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
212 | 213 | Shuckle | Bug | Rock | 505 | 20 | 10 | 230 | 10 | 230 | 5 | 2 | False |
327 | 328 | Trapinch | Ground | NaN | 290 | 45 | 100 | 45 | 45 | 45 | 10 | 3 | False |
437 | 438 | Bonsly | Rock | NaN | 290 | 50 | 80 | 95 | 10 | 45 | 10 | 4 | False |
445 | 446 | Munchlax | Normal | NaN | 390 | 135 | 85 | 40 | 40 | 85 | 5 | 4 | False |
596 | 597 | Ferroseed | Grass | Steel | 305 | 44 | 50 | 91 | 24 | 86 | 10 | 5 | False |
3. How many Pokemons have a Sp. Def
value of 25 or less?¶
In [14]:
# Try your code here
df.loc[df['Sp. Def'] <= 25]
(df['Sp. Def'] <= 25).sum()
Out[14]:
17
4. Select all the Legendary pokemons¶
In [16]:
# Try your code here
legendary_df = df.loc[df['Legendary']]
legendary_df
Out[16]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
143 | 144 | Articuno | Ice | Flying | 580 | 90 | 85 | 100 | 95 | 125 | 85 | 1 | True |
144 | 145 | Zapdos | Electric | Flying | 580 | 90 | 90 | 85 | 125 | 90 | 100 | 1 | True |
145 | 146 | Moltres | Fire | Flying | 580 | 90 | 100 | 90 | 125 | 85 | 90 | 1 | True |
149 | 150 | Mewtwo | Psychic | Fighting | 680 | 106 | 110 | 90 | 154 | 90 | 130 | 1 | True |
242 | 243 | Raikou | Electric | NaN | 580 | 90 | 85 | 75 | 115 | 100 | 115 | 2 | True |
243 | 244 | Entei | Fire | NaN | 580 | 115 | 115 | 85 | 90 | 75 | 100 | 2 | True |
244 | 245 | Suicune | Water | NaN | 580 | 100 | 75 | 115 | 90 | 115 | 85 | 2 | True |
248 | 249 | Lugia | Psychic | Flying | 680 | 106 | 90 | 130 | 90 | 154 | 110 | 2 | True |
249 | 250 | Ho-oh | Fire | Flying | 680 | 106 | 130 | 90 | 110 | 154 | 90 | 2 | True |
376 | 377 | Regirock | Rock | NaN | 580 | 80 | 100 | 200 | 50 | 100 | 50 | 3 | True |
377 | 378 | Regice | Ice | NaN | 580 | 80 | 50 | 100 | 100 | 200 | 50 | 3 | True |
378 | 379 | Registeel | Steel | NaN | 580 | 80 | 75 | 150 | 75 | 150 | 50 | 3 | True |
379 | 380 | Latias | Dragon | Psychic | 600 | 80 | 80 | 90 | 110 | 130 | 110 | 3 | True |
380 | 381 | Latios | Dragon | Psychic | 600 | 80 | 90 | 80 | 130 | 110 | 110 | 3 | True |
381 | 382 | Kyogre | Water | NaN | 670 | 100 | 100 | 90 | 150 | 140 | 90 | 3 | True |
382 | 383 | Groudon | Ground | Fire | 670 | 100 | 150 | 140 | 100 | 90 | 90 | 3 | True |
383 | 384 | Rayquaza | Dragon | Flying | 680 | 105 | 150 | 90 | 150 | 90 | 95 | 3 | True |
384 | 385 | Jirachi | Steel | Psychic | 600 | 100 | 100 | 100 | 100 | 100 | 100 | 3 | True |
385 | 386 | DeoxysNormal Forme | Psychic | NaN | 600 | 50 | 150 | 50 | 150 | 50 | 150 | 3 | True |
479 | 480 | Uxie | Psychic | NaN | 580 | 75 | 75 | 130 | 75 | 130 | 95 | 4 | True |
480 | 481 | Mesprit | Psychic | NaN | 580 | 80 | 105 | 105 | 105 | 105 | 80 | 4 | True |
481 | 482 | Azelf | Psychic | NaN | 580 | 75 | 125 | 70 | 125 | 70 | 115 | 4 | True |
482 | 483 | Dialga | Steel | Dragon | 680 | 100 | 120 | 120 | 150 | 100 | 90 | 4 | True |
483 | 484 | Palkia | Water | Dragon | 680 | 90 | 120 | 100 | 150 | 120 | 100 | 4 | True |
484 | 485 | Heatran | Fire | Steel | 600 | 91 | 90 | 106 | 130 | 106 | 77 | 4 | True |
485 | 486 | Regigigas | Normal | NaN | 670 | 110 | 160 | 110 | 80 | 110 | 100 | 4 | True |
486 | 487 | GiratinaAltered Forme | Ghost | Dragon | 680 | 150 | 100 | 120 | 100 | 120 | 90 | 4 | True |
490 | 491 | Darkrai | Dark | NaN | 600 | 70 | 90 | 90 | 135 | 90 | 125 | 4 | True |
491 | 492 | ShayminLand Forme | Grass | Flying | 600 | 100 | 100 | 100 | 100 | 100 | 100 | 4 | True |
492 | 493 | Arceus | Normal | NaN | 720 | 120 | 120 | 120 | 120 | 120 | 120 | 4 | True |
493 | 494 | Victini | Psychic | Fire | 600 | 100 | 100 | 100 | 100 | 100 | 100 | 5 | True |
637 | 638 | Cobalion | Steel | Fighting | 580 | 91 | 90 | 129 | 90 | 72 | 108 | 5 | True |
638 | 639 | Terrakion | Rock | Fighting | 580 | 91 | 129 | 90 | 72 | 90 | 108 | 5 | True |
639 | 640 | Virizion | Grass | Fighting | 580 | 91 | 90 | 72 | 90 | 129 | 108 | 5 | True |
640 | 641 | TornadusIncarnate Forme | Flying | NaN | 580 | 79 | 115 | 70 | 125 | 80 | 111 | 5 | True |
641 | 642 | ThundurusIncarnate Forme | Electric | Flying | 580 | 79 | 115 | 70 | 125 | 80 | 111 | 5 | True |
642 | 643 | Reshiram | Dragon | Fire | 680 | 100 | 120 | 100 | 150 | 120 | 90 | 5 | True |
643 | 644 | Zekrom | Dragon | Electric | 680 | 100 | 150 | 120 | 120 | 100 | 90 | 5 | True |
644 | 645 | LandorusIncarnate Forme | Ground | Flying | 600 | 89 | 125 | 90 | 115 | 80 | 101 | 5 | True |
645 | 646 | Kyurem | Dragon | Ice | 660 | 125 | 130 | 90 | 130 | 90 | 95 | 5 | True |
715 | 716 | Xerneas | Fairy | NaN | 680 | 126 | 131 | 95 | 131 | 98 | 99 | 6 | True |
716 | 717 | Yveltal | Dark | Flying | 680 | 126 | 131 | 95 | 131 | 98 | 99 | 6 | True |
717 | 718 | Zygarde50% Forme | Dragon | Ground | 600 | 108 | 100 | 121 | 81 | 95 | 95 | 6 | True |
718 | 719 | Diancie | Rock | Fairy | 600 | 50 | 100 | 150 | 100 | 150 | 50 | 6 | True |
719 | 720 | HoopaHoopa Confined | Psychic | Ghost | 600 | 80 | 110 | 60 | 150 | 130 | 70 | 6 | True |
720 | 721 | Volcanion | Fire | Water | 600 | 80 | 110 | 120 | 130 | 90 | 70 | 6 | True |
5. Find the outlier¶
Find the pokemon that is clearly an outlier in terms of Attack / Defense:
In [18]:
ax = sns.scatterplot(data=df, x="Defense", y="Attack")
ax.annotate(
"Who's this guy?", xy=(228, 10), xytext=(150, 10), color='red',
arrowprops=dict(arrowstyle="->", color='red')
)
Out[18]:
Text(150, 10, "Who's this guy?")
In [19]:
# Try your code here
Name = df.loc[df['Defense'] == (df['Defense']).max(),"Name"]
Name
Out[19]:
212 Shuckle Name: Name, dtype: object
In [20]:
df.sort_values(by=['Defense','Attack'],ascending=[False,True]).head()
Out[20]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
212 | 213 | Shuckle | Bug | Rock | 505 | 20 | 10 | 230 | 10 | 230 | 5 | 2 | False |
207 | 208 | Steelix | Steel | Ground | 510 | 75 | 85 | 200 | 55 | 65 | 30 | 2 | False |
376 | 377 | Regirock | Rock | NaN | 580 | 80 | 100 | 200 | 50 | 100 | 50 | 3 | True |
712 | 713 | Avalugg | Ice | NaN | 514 | 95 | 117 | 184 | 44 | 46 | 28 | 6 | False |
90 | 91 | Cloyster | Water | Ice | 525 | 50 | 95 | 180 | 85 | 45 | 70 | 1 | False |
Advanced selection¶
Now let's use boolean operators to create more advanced expressions
6. How many Fire-Flying Pokemons are there?¶
In [25]:
# Try your code here
df.loc[(df['Type 1'] == 'Fire') & (df['Type 2'] == 'Flying')].shape[0]
Out[25]:
5
In [27]:
((df['Type 1'] == 'Fire') & (df['Type 2'] == 'Flying')).sum()
Out[27]:
5
In [33]:
df.query("`Type 1` == 'Fire' and `Type 2` == 'Flying'").shape
Out[33]:
(5, 13)
7. How many 'Poison' pokemons are across both types?¶
In [28]:
# Try your code here
((df['Type 1'] == 'Poison') | (df['Type 2'] == 'Poison')).sum()
Out[28]:
59
8. Name the pokemon of Type 1
Ice which has the strongest defense?¶
In [36]:
# Try your code here
df.loc[df['Type 1'] == 'Ice'].sort_values(by='Defense',ascending=False)
Out[36]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
712 | 713 | Avalugg | Ice | NaN | 514 | 95 | 117 | 184 | 44 | 46 | 28 | 6 | False |
470 | 471 | Glaceon | Ice | NaN | 525 | 65 | 60 | 110 | 130 | 95 | 65 | 4 | False |
143 | 144 | Articuno | Ice | Flying | 580 | 90 | 85 | 100 | 95 | 125 | 85 | 1 | True |
377 | 378 | Regice | Ice | NaN | 580 | 80 | 50 | 100 | 100 | 200 | 50 | 3 | True |
364 | 365 | Walrein | Ice | Water | 530 | 110 | 80 | 90 | 95 | 90 | 65 | 3 | False |
711 | 712 | Bergmite | Ice | NaN | 304 | 55 | 69 | 85 | 32 | 35 | 28 | 6 | False |
583 | 584 | Vanilluxe | Ice | NaN | 535 | 71 | 95 | 85 | 110 | 95 | 79 | 5 | False |
613 | 614 | Beartic | Ice | NaN | 485 | 95 | 110 | 80 | 70 | 80 | 50 | 5 | False |
220 | 221 | Piloswine | Ice | Ground | 450 | 100 | 100 | 80 | 60 | 60 | 50 | 2 | False |
472 | 473 | Mamoswine | Ice | Ground | 530 | 110 | 130 | 80 | 70 | 60 | 80 | 4 | False |
361 | 362 | Glalie | Ice | NaN | 480 | 80 | 80 | 80 | 80 | 80 | 80 | 3 | False |
477 | 478 | Froslass | Ice | Ghost | 480 | 70 | 80 | 70 | 80 | 70 | 110 | 4 | False |
363 | 364 | Sealeo | Ice | Water | 410 | 90 | 60 | 70 | 75 | 70 | 45 | 3 | False |
582 | 583 | Vanillish | Ice | NaN | 395 | 51 | 65 | 65 | 80 | 75 | 59 | 5 | False |
360 | 361 | Snorunt | Ice | NaN | 300 | 50 | 50 | 50 | 50 | 50 | 50 | 3 | False |
362 | 363 | Spheal | Ice | Water | 290 | 70 | 40 | 50 | 55 | 50 | 25 | 3 | False |
581 | 582 | Vanillite | Ice | NaN | 305 | 36 | 50 | 50 | 65 | 60 | 44 | 5 | False |
224 | 225 | Delibird | Ice | Flying | 330 | 45 | 55 | 45 | 65 | 45 | 75 | 2 | False |
219 | 220 | Swinub | Ice | Ground | 250 | 50 | 50 | 40 | 30 | 30 | 50 | 2 | False |
612 | 613 | Cubchoo | Ice | NaN | 305 | 55 | 70 | 40 | 60 | 40 | 40 | 5 | False |
123 | 124 | Jynx | Ice | Psychic | 455 | 65 | 50 | 35 | 115 | 95 | 95 | 1 | False |
614 | 615 | Cryogonal | Ice | NaN | 485 | 70 | 50 | 30 | 95 | 135 | 105 | 5 | False |
237 | 238 | Smoochum | Ice | Psychic | 305 | 45 | 30 | 15 | 85 | 65 | 65 | 2 | False |
In [37]:
df.loc[df['Type 1'] == 'Ice','Defense'].max()
Out[37]:
184
In [39]:
df.loc[
(df['Type 1'] == 'Ice') &
(df['Defense'] == df.loc[df['Type 1'] == 'Ice','Defense'].max())
,"Name"]
Out[39]:
712 Avalugg Name: Name, dtype: object
In [40]:
df.loc[
(df['Type 1'] == 'Ice') &
(df['Defense'] == df.loc[df['Type 1'] == 'Ice','Defense'].max())
].iloc[0,1]
Out[40]:
'Avalugg'
9. What's the most common type of Legendary Pokemons?¶
In [46]:
# Try your code here
df.loc[df['Legendary']]['Type 1'].mode()
Out[46]:
0 Psychic Name: Type 1, dtype: object
In [50]:
df.loc[df['Legendary']]['Type 1'].value_counts().plot(kind='bar');
10. What's the most powerful pokemon from the first 3 generations, of type water?¶
In [65]:
df['Generation'].value_counts(sort=False)
Out[65]:
Generation 1 151 2 100 3 135 4 107 5 156 6 72 Name: count, dtype: int64
In [67]:
df['Generation'].value_counts(sort=False).plot(kind='bar');
In [61]:
# Try your code here
df.loc[
(df['Type 1'] == 'Water') &
(df['Generation'] <=3 )
].sort_values(by='Total',ascending = False)
Out[61]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
381 | 382 | Kyogre | Water | NaN | 670 | 100 | 100 | 90 | 150 | 140 | 90 | 3 | True |
244 | 245 | Suicune | Water | NaN | 580 | 100 | 75 | 115 | 90 | 115 | 85 | 2 | True |
229 | 230 | Kingdra | Water | Dragon | 540 | 75 | 95 | 95 | 95 | 95 | 85 | 2 | False |
129 | 130 | Gyarados | Water | Flying | 540 | 95 | 125 | 79 | 60 | 100 | 81 | 1 | False |
349 | 350 | Milotic | Water | NaN | 540 | 95 | 60 | 79 | 100 | 125 | 81 | 3 | False |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
182 | 183 | Marill | Water | Fairy | 250 | 70 | 20 | 50 | 20 | 50 | 40 | 2 | False |
269 | 270 | Lotad | Water | Grass | 220 | 40 | 30 | 30 | 40 | 50 | 30 | 3 | False |
193 | 194 | Wooper | Water | Ground | 210 | 55 | 45 | 45 | 25 | 25 | 15 | 2 | False |
128 | 129 | Magikarp | Water | NaN | 200 | 20 | 10 | 55 | 15 | 20 | 80 | 1 | False |
348 | 349 | Feebas | Water | NaN | 200 | 20 | 15 | 20 | 10 | 55 | 80 | 3 | False |
70 rows × 13 columns
In [69]:
df.loc[
(df['Type 1'] == 'Water') &
(df['Generation'].isin([1,2,3]) )
].sort_values(by='Total',ascending = False).head()
Out[69]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
381 | 382 | Kyogre | Water | NaN | 670 | 100 | 100 | 90 | 150 | 140 | 90 | 3 | True |
244 | 245 | Suicune | Water | NaN | 580 | 100 | 75 | 115 | 90 | 115 | 85 | 2 | True |
229 | 230 | Kingdra | Water | Dragon | 540 | 75 | 95 | 95 | 95 | 95 | 85 | 2 | False |
129 | 130 | Gyarados | Water | Flying | 540 | 95 | 125 | 79 | 60 | 100 | 81 | 1 | False |
349 | 350 | Milotic | Water | NaN | 540 | 95 | 60 | 79 | 100 | 125 | 81 | 3 | False |
11. What's the most powerful Dragon from the last two generations?¶
In [80]:
# Try your code here
df.loc[
((df['Type 1'] == 'Dragon') | (df['Type 2'] == 'Dragon')) &
(df['Generation'].isin({5,6})) #here you can use list as well
].sort_values(by='Total',ascending = False)
Out[80]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
643 | 644 | Zekrom | Dragon | Electric | 680 | 100 | 150 | 120 | 120 | 100 | 90 | 5 | True |
642 | 643 | Reshiram | Dragon | Fire | 680 | 100 | 120 | 100 | 150 | 120 | 90 | 5 | True |
645 | 646 | Kyurem | Dragon | Ice | 660 | 125 | 130 | 90 | 130 | 90 | 95 | 5 | True |
705 | 706 | Goodra | Dragon | NaN | 600 | 90 | 100 | 70 | 110 | 150 | 80 | 6 | False |
717 | 718 | Zygarde50% Forme | Dragon | Ground | 600 | 108 | 100 | 121 | 81 | 95 | 95 | 6 | True |
634 | 635 | Hydreigon | Dark | Dragon | 600 | 92 | 105 | 90 | 125 | 90 | 98 | 5 | False |
611 | 612 | Haxorus | Dragon | NaN | 540 | 76 | 147 | 90 | 60 | 70 | 97 | 5 | False |
714 | 715 | Noivern | Flying | Dragon | 535 | 85 | 70 | 80 | 97 | 80 | 123 | 6 | False |
696 | 697 | Tyrantrum | Rock | Dragon | 521 | 82 | 121 | 119 | 69 | 59 | 71 | 6 | False |
690 | 691 | Dragalge | Poison | Dragon | 494 | 65 | 75 | 90 | 97 | 123 | 44 | 6 | False |
620 | 621 | Druddigon | Dragon | NaN | 485 | 77 | 120 | 90 | 60 | 90 | 48 | 5 | False |
704 | 705 | Sliggoo | Dragon | NaN | 452 | 68 | 75 | 53 | 83 | 113 | 60 | 6 | False |
633 | 634 | Zweilous | Dark | Dragon | 420 | 72 | 85 | 70 | 65 | 70 | 58 | 5 | False |
610 | 611 | Fraxure | Dragon | NaN | 410 | 66 | 117 | 70 | 40 | 50 | 67 | 5 | False |
695 | 696 | Tyrunt | Rock | Dragon | 362 | 58 | 89 | 77 | 45 | 45 | 48 | 6 | False |
609 | 610 | Axew | Dragon | NaN | 320 | 46 | 87 | 60 | 30 | 40 | 57 | 5 | False |
632 | 633 | Deino | Dark | Dragon | 300 | 52 | 65 | 50 | 45 | 50 | 38 | 5 | False |
703 | 704 | Goomy | Dragon | NaN | 300 | 45 | 50 | 35 | 55 | 75 | 40 | 6 | False |
713 | 714 | Noibat | Flying | Dragon | 245 | 40 | 30 | 35 | 45 | 40 | 55 | 6 | False |
12. Select most powerful Fire-type pokemons¶
In [86]:
# Try your code here
# you can also use query df.query("Attack > 100 and `Type 1` == 'Fire'")
powerful_fire_df = df.loc[(df['Attack'] > 100) & (df['Type 1'] == 'Fire')]
powerful_fire_df
Out[86]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
58 | 59 | Arcanine | Fire | NaN | 555 | 90 | 110 | 80 | 100 | 80 | 95 | 1 | False |
135 | 136 | Flareon | Fire | NaN | 525 | 65 | 130 | 60 | 95 | 110 | 65 | 1 | False |
243 | 244 | Entei | Fire | NaN | 580 | 115 | 115 | 85 | 90 | 75 | 100 | 2 | True |
249 | 250 | Ho-oh | Fire | Flying | 680 | 106 | 130 | 90 | 110 | 154 | 90 | 2 | True |
256 | 257 | Blaziken | Fire | Fighting | 530 | 80 | 120 | 70 | 110 | 70 | 80 | 3 | False |
391 | 392 | Infernape | Fire | Fighting | 534 | 76 | 104 | 71 | 104 | 71 | 108 | 4 | False |
499 | 500 | Emboar | Fire | Fighting | 528 | 110 | 123 | 65 | 100 | 65 | 65 | 5 | False |
554 | 555 | DarmanitanStandard Mode | Fire | Psychic | 480 | 105 | 140 | 55 | 30 | 55 | 95 | 5 | False |
720 | 721 | Volcanion | Fire | Water | 600 | 80 | 110 | 120 | 130 | 90 | 70 | 6 | True |
13. Select all Water-type, Flying-type pokemons¶
In [87]:
# Try your code here
water_flying_df = df.query("`Type 1` == 'Water' and `Type 2` == 'Flying'")
water_flying_df
Out[87]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
129 | 130 | Gyarados | Water | Flying | 540 | 95 | 125 | 79 | 60 | 100 | 81 | 1 | False |
225 | 226 | Mantine | Water | Flying | 465 | 65 | 40 | 70 | 80 | 140 | 70 | 2 | False |
277 | 278 | Wingull | Water | Flying | 270 | 40 | 30 | 30 | 55 | 30 | 85 | 3 | False |
278 | 279 | Pelipper | Water | Flying | 430 | 60 | 50 | 100 | 85 | 70 | 65 | 3 | False |
457 | 458 | Mantyke | Water | Flying | 345 | 45 | 20 | 50 | 60 | 120 | 50 | 4 | False |
579 | 580 | Ducklett | Water | Flying | 305 | 62 | 44 | 50 | 44 | 50 | 55 | 5 | False |
580 | 581 | Swanna | Water | Flying | 473 | 75 | 87 | 63 | 87 | 63 | 98 | 5 | False |
14. Select specific columns of Legendary pokemons of type Fire¶
In [95]:
# Try your code here
#df.query("`Type 1` == 'Fire' and Legendary")[["Name","Attack","Generation"]]
legendary_fire_df = df.loc[(df['Type 1'] == 'Fire') & df['Legendary'],["Name","Attack","Generation"]]
legendary_fire_df
Out[95]:
Name | Attack | Generation | |
---|---|---|---|
145 | Moltres | 100 | 1 |
243 | Entei | 115 | 2 |
249 | Ho-oh | 130 | 2 |
484 | Heatran | 90 | 4 |
720 | Volcanion | 110 | 6 |
In [96]:
df.query("`Type 1` == 'Fire' and Legendary")[["Name","Attack","Generation"]]
Out[96]:
Name | Attack | Generation | |
---|---|---|---|
145 | Moltres | 100 | 1 |
243 | Entei | 115 | 2 |
249 | Ho-oh | 130 | 2 |
484 | Heatran | 90 | 4 |
720 | Volcanion | 110 | 6 |
15. Select Slow and Fast pokemons¶
This is the distribution of speed of the pokemons. The red lines indicate those bottom 5% and top 5% pokemons by speed:
In [97]:
ax = df['Speed'].plot(kind='hist', figsize=(10, 5), bins=100)
ax.axvline(df['Speed'].quantile(.05), color='red')
ax.axvline(df['Speed'].quantile(.95), color='red')
Out[97]:
<matplotlib.lines.Line2D at 0x789208b93cd0>
In [102]:
df.describe(percentiles=[0.05, 0.95])
Out[102]:
# | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | |
---|---|---|---|---|---|---|---|---|---|
count | 721.00000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 | 721.000000 |
mean | 361.00000 | 417.945908 | 68.380028 | 75.124827 | 70.697642 | 68.848821 | 69.180305 | 65.714286 | 3.323162 |
std | 208.27906 | 109.663671 | 25.848272 | 29.070335 | 29.194941 | 28.898590 | 26.899364 | 27.277920 | 1.669873 |
min | 1.00000 | 180.000000 | 1.000000 | 5.000000 | 5.000000 | 10.000000 | 20.000000 | 5.000000 | 1.000000 |
5% | 37.00000 | 250.000000 | 35.000000 | 30.000000 | 35.000000 | 30.000000 | 30.000000 | 25.000000 | 1.000000 |
50% | 361.00000 | 424.000000 | 65.000000 | 75.000000 | 65.000000 | 65.000000 | 65.000000 | 65.000000 | 3.000000 |
95% | 685.00000 | 600.000000 | 110.000000 | 125.000000 | 125.000000 | 125.000000 | 120.000000 | 110.000000 | 6.000000 |
max | 721.00000 | 720.000000 | 255.000000 | 165.000000 | 230.000000 | 154.000000 | 230.000000 | 160.000000 | 6.000000 |
In [113]:
# you can use this code lines as well for this activity, this is another method
bottom_5 = df['Speed'].quantile(.05)
top_5 = df['Speed'].quantile(.95)
(bottom_5,top_5)
Out[113]:
(25.0, 110.0)
In [105]:
# Try your code here
slow_fast_df = df.loc[(df['Speed'] < 25) | (df['Speed'] > 110)]
slow_fast_df
Out[105]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
38 | 39 | Jigglypuff | Normal | Fairy | 270 | 115 | 45 | 20 | 45 | 25 | 20 | 1 | False |
50 | 51 | Dugtrio | Ground | NaN | 405 | 35 | 80 | 50 | 50 | 70 | 120 | 1 | False |
52 | 53 | Persian | Normal | NaN | 440 | 65 | 70 | 60 | 65 | 65 | 115 | 1 | False |
64 | 65 | Alakazam | Psychic | NaN | 500 | 55 | 50 | 45 | 135 | 95 | 120 | 1 | False |
73 | 74 | Geodude | Rock | Ground | 300 | 40 | 80 | 100 | 30 | 30 | 20 | 1 | False |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
657 | 658 | Greninja | Water | Dark | 530 | 72 | 95 | 67 | 103 | 71 | 122 | 6 | False |
662 | 663 | Talonflame | Fire | Flying | 499 | 78 | 81 | 71 | 74 | 69 | 126 | 6 | False |
681 | 682 | Spritzee | Fairy | NaN | 341 | 78 | 52 | 60 | 63 | 65 | 23 | 6 | False |
700 | 701 | Hawlucha | Fighting | Flying | 500 | 78 | 92 | 75 | 74 | 63 | 118 | 6 | False |
714 | 715 | Noivern | Flying | Dragon | 535 | 85 | 70 | 80 | 97 | 80 | 123 | 6 | False |
68 rows × 13 columns
In [115]:
#slow_fast_df = df.loc[(df['Speed'] < bottom_5) | (df['Speed'] > top_5)]
slow_fast_df = df.query("Speed < @bottom_5 or Speed > @top_5")
slow_fast_df
Out[115]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
38 | 39 | Jigglypuff | Normal | Fairy | 270 | 115 | 45 | 20 | 45 | 25 | 20 | 1 | False |
50 | 51 | Dugtrio | Ground | NaN | 405 | 35 | 80 | 50 | 50 | 70 | 120 | 1 | False |
52 | 53 | Persian | Normal | NaN | 440 | 65 | 70 | 60 | 65 | 65 | 115 | 1 | False |
64 | 65 | Alakazam | Psychic | NaN | 500 | 55 | 50 | 45 | 135 | 95 | 120 | 1 | False |
73 | 74 | Geodude | Rock | Ground | 300 | 40 | 80 | 100 | 30 | 30 | 20 | 1 | False |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
657 | 658 | Greninja | Water | Dark | 530 | 72 | 95 | 67 | 103 | 71 | 122 | 6 | False |
662 | 663 | Talonflame | Fire | Flying | 499 | 78 | 81 | 71 | 74 | 69 | 126 | 6 | False |
681 | 682 | Spritzee | Fairy | NaN | 341 | 78 | 52 | 60 | 63 | 65 | 23 | 6 | False |
700 | 701 | Hawlucha | Fighting | Flying | 500 | 78 | 92 | 75 | 74 | 63 | 118 | 6 | False |
714 | 715 | Noivern | Flying | Dragon | 535 | 85 | 70 | 80 | 97 | 80 | 123 | 6 | False |
68 rows × 13 columns
16. Find the Ultra Powerful Legendary Pokemon¶
In [116]:
fig, ax = plt.subplots(figsize=(14, 7))
sns.scatterplot(data=df, x="Defense", y="Attack", hue='Legendary', ax=ax)
ax.annotate(
"Who's this guy?", xy=(140, 150), xytext=(160, 150), color='red',
arrowprops=dict(arrowstyle="->", color='red')
)
Out[116]:
Text(160, 150, "Who's this guy?")
In [121]:
df.loc[
df['Legendary'] &
((df['Defense'] < 150) & (df['Defense'] > 100)) &
((df['Attack'] < 160) & (df['Attack'] > 140))
].sort_values(by=["Defense","Attack"],ascending=False)
Out[121]:
# | Name | Type 1 | Type 2 | Total | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
382 | 383 | Groudon | Ground | Fire | 670 | 100 | 150 | 140 | 100 | 90 | 90 | 3 | True |
643 | 644 | Zekrom | Dragon | Electric | 680 | 100 | 150 | 120 | 120 | 100 | 90 | 5 | True |
In [122]:
# Try your code here
# this is not a good approach because the below values directly taken from the scatter plot above code
df.query("Defense == 140 and Attack == 150")["Name"]
Out[122]:
382 Groudon Name: Name, dtype: object