首页
编程语言
数据库
网络开发
Algorithm算法
移动开发
系统相关
金融统计
人工智能
其他
首页
>
> 详细
辅导pandas-puzzles、讲解Python程序设计、辅导Cython留学生、讲解Python编程 辅导留学生 Statistics统计、
2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 1/26
100 pandas puzzles
Inspired by 100 Numpy exerises (https://github.com/rougier/numpy-100), here are 100* short puzzles for
testing your knowledge of pandas' (http://pandas.pydata.org/) power.
Since pandas is a large library with many different specialist features and functions, these excercises focus
mainly on the fundamentals of manipulating data (indexing, grouping, aggregating, cleaning), making use of the
core DataFrame and Series objects.
Many of the excerises here are stright-forward in that the solutions require no more than a few lines of code (in
pandas or NumPy... don't go using pure Python or Cython!). Choosing the right methods and following best
practices is the underlying goal.
The exercises are loosely divided in sections. Each section has a difficulty rating; these ratings are subjective,
of course, but should be a seen as a rough guide as to how inventive the required solution is.
If you're just starting out with pandas and you are looking for some other resources, the official documentation
is very extensive. In particular, some good places get a broader overview of pandas are...
10 minutes to pandas (http://pandas.pydata.org/pandas-docs/stable/10min.html)
pandas basics (http://pandas.pydata.org/pandas-docs/stable/basics.html)
tutorials (http://pandas.pydata.org/pandas-docs/stable/tutorials.html)
cookbook and idioms (http://pandas.pydata.org/pandas-docs/stable/cookbook.html#cookbook)
Enjoy the puzzles!
* the list of exercises is not yet complete! Pull requests or suggestions for additional exercises, corrections and
improvements are welcomed.
Importing pandas
Getting started and checking your pandas setup
Difficulty: easy
1. Import pandas under the name pd .
In[1]:
2. Print the version of pandas that has been imported.
import pandas as pd
import numpy as np2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 2/26
In[2]:
3. Print out all the version information of the libraries that are required by the pandas library.
Out[2]:
'0.23.4'
pd.__version__2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 3/26
In[3]:
DataFrame basics
INSTALLED VERSIONS
------------------
commit: None
python: 3.6.6.final.0
python-bits: 64
OS: Darwin
OS-release: 17.7.0
machine: x86_64
processor: i386
byteorder: little
LC_ALL: None
LANG: zh_CN.UTF-8
LOCALE: zh_CN.UTF-8
pandas: 0.23.4
pytest: None
pip: 18.1
setuptools: 39.1.0
Cython: None
numpy: 1.14.5
scipy: 1.1.0
pyarrow: None
xarray: None
IPython: 6.5.0
sphinx: None
patsy: None
dateutil: 2.7.3
pytz: 2018.5
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 2.2.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: 1.0.1
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: 2.10
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
pd.show_versions()2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 4/26
A few of the fundamental routines for selecting, sorting, adding and aggregating
data in DataFrames
Difficulty: easy
Note: remember to import numpy using:
import numpy as np
Consider the following Python dictionary data and Python list labels :
data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'ca
t', 'dog', 'dog'],
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'n
o', 'no']}
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
(This is just some meaningless data I made up with the theme of animals and trips to a vet.)
4. Create a DataFrame df from this dictionary data which has the index labels .
In[2]:
5. Display a summary of the basic information about this DataFrame and its data.
data = {'animal': ['cat', 'cat', 'snake', 'dog', 'dog', 'cat', 'snake', 'cat', 'dog
'age': [2.5, 3, 0.5, np.nan, 5, 2, 4.5, np.nan, 7, 3],
'visits': [1, 3, 2, 3, 2, 3, 1, 1, 2, 1],
'priority': ['yes', 'yes', 'no', 'yes', 'no', 'no', 'no', 'yes', 'no', 'no']
labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
df = pd.DataFrame(data, index=labels)2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 5/26
In[5]:
6. Return the first 3 rows of the DataFrame df .
In?[6]:
Index: 10 entries, a to j
Data columns (total 4 columns):
animal 10 non-null object
age 8 non-null float64
visits 10 non-null int64
priority 10 non-null object
dtypes: float64(1), int64(1), object(2)
memory usage: 400.0+ bytes
Out[5]:
age visits
count 8.000000 10.000000
mean 3.437500 1.900000
std 2.007797 0.875595
min 0.500000 1.000000
25% 2.375000 1.000000
50% 3.000000 2.000000
75% 4.625000 2.750000
max 7.000000 3.000000
Out[6]:
animal age visits priority
a cat 2.5 1 yes
b cat 3.0 3 yes
c snake 0.5 2 no
df.info()
# ...or...
df.describe()
df.iloc[:3]
# or equivalently
df.head(3)2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 6/26
7. Select just the 'animal' and 'age' columns from the DataFrame df .
In?[7]:
8. Select the data in rows [3, 4, 8] and in columns ['animal', 'age'] .
In?[3]:
9. Select only the rows where the number of visits is greater than 3.
Out[7]:
animal age
a cat 2.5
b cat 3.0
c snake 0.5
d dog NaN
e dog 5.0
f cat 2.0
g snake 4.5
h cat NaN
i dog 7.0
j dog 3.0
Out[3]:
animal age
d dog NaN
e dog 5.0
i dog 7.0
df.loc[:, ['animal', 'age']]
# or
df[['animal', 'age']]
df.loc[df.index[[3, 4, 8]], ['animal', 'age']]2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 7/26
In[4]:
10. Select the rows where the age is missing, i.e. is NaN .
In[5]:
11. Select the rows where the animal is a cat and the age is less than 3.
In[6]:
12. Select the rows the age is between 2 and 4 (inclusive).
Out[4]:
animal age visits priority
Out[5]:
animal age visits priority
d dog NaN 3 yes
h cat NaN 1 yes
Out[6]:
animal age visits priority
a cat 2.5 1 yes
f cat 2.0 3 no
df[df['visits'] > 3]
df[df['age'].isnull()]
df[(df['animal'] == 'cat') & (df['age'] < 3)]2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 8/26
In[7]:
13. Change the age in row 'f' to 1.5.
In[]:
14. Calculate the sum of all visits (the total number of visits).
In[]:
15. Calculate the mean age for each different animal in df .
In[8]:
16. Append a new row 'k' to df with your choice of values for each column. Then delete that row to return the
original DataFrame.
Out[7]:
animal age visits priority
a cat 2.5 1 yes
b cat 3.0 3 yes
f cat 2.0 3 no
j dog 3.0 1 no
Out[8]:
animal
cat 2.5
dog 5.0
snake 2.5
Name: age, dtype: float64
df[df['age'].between(2, 4)]
df.loc['f', 'age'] = 1.5
df['visits'].sum()
df.groupby('animal')['age'].mean()2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 9/26
In[]:
17. Count the number of each type of animal in df .
In[9]:
18. Sort df first by the values in the 'age' in decending order, then by the value in the 'visit' column in
ascending order.
In[10]:
19. The 'priority' column contains the values 'yes' and 'no'. Replace this column with a column of boolean
values: 'yes' should be True and 'no' should be False .
Out[9]:
cat 4
dog 4
snake 2
Name: animal, dtype: int64
Out[10]:
animal age visits priority
i dog 7.0 2 no
e dog 5.0 2 no
g snake 4.5 1 no
j dog 3.0 1 no
b cat 3.0 3 yes
a cat 2.5 1 yes
f cat 2.0 3 no
c snake 0.5 2 no
h cat NaN 1 yes
d dog NaN 3 yes
df.loc['k'] = [5.5, 'dog', 'no', 2]
# and then deleting the new row...
df = df.drop('k')
df['animal'].value_counts()
df.sort_values(by=['age', 'visits'], ascending=[False, True])2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 10/26
In?[?]:
20. In the 'animal' column, change the 'snake' entries to 'python'.
In?[14]:
21. For each animal type and each number of visits, find the mean age. In other words, each row is an animal,
each column is a number of visits and the values are the mean ages (hint: use a pivot table).
In[15]:
DataFrames: beyond the basics
Slightly trickier: you may need to combine two or more methods to get the right
answer
Difficulty: medium
The previous section was tour through some basic but essential DataFrame operations. Below are some ways
that you might need to cut your data, but for which there is no single "out of the box" method.
animal age visits priority
a cat 2.5 1 yes
b cat 3.0 3 yes
c python 0.5 2 no
d dog NaN 3 yes
e dog 5.0 2 no
f cat 2.0 3 no
g python 4.5 1 no
h cat NaN 1 yes
i dog 7.0 2 no
j dog 3.0 1 no
Out[15]:
visits 1 2 3
animal
cat 2.5 NaN 2.5
dog 3.0 6.0 NaN
python 4.5 0.5 NaN
df['priority'] = df['priority'].map({'yes': True, 'no': False})
df['animal'] = df['animal'].replace('snake', 'python')
print(df)
df.pivot_table(index='animal', columns='visits', values='age', aggfunc='mean')2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 11/26
22. You have a DataFrame df with a column 'A' of integers. For example:
df = pd.DataFrame({'A': [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7]})
How do you filter out rows which contain the same integer as the row immediately above?
In[16]:
23. Given a DataFrame of numeric values, say
df = pd.DataFrame(np.random.random(size=(5, 3))) # a 5x3 frame of float valu
es
how do you subtract the row mean from each element in the row?
In[]:
24. Suppose you have DataFrame with 10 columns of real numbers, for example:
df = pd.DataFrame(np.random.random(size=(5, 10)), columns=list('abcdefghij'
))
Which column of numbers has the smallest sum? (Find that column's label.)
Out[16]:
A
0 1
1 2
3 3
4 4
5 5
8 6
9 7
df = pd.DataFrame({'A': [1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7]})
df.loc[df['A'].shift() != df['A']]
# Alternatively, we could use drop_duplicates() here. Note
# that this removes *all* duplicates though, so it won't
# work as desired if A is [1, 1, 2, 2, 1, 1] for example.
df.drop_duplicates(subset='A')
df.sub(df.mean(axis=1), axis=0)2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 12/26
In[17]:
25. How do you count how many unique rows a DataFrame has (i.e. ignore all rows that are duplicates)?
In[]:
The next three puzzles are slightly harder...
26. You have a DataFrame that consists of 10 columns of floating--point numbers. Suppose that exactly 5
entries in each row are NaN values. For each row of the DataFrame, find the column which contains the third
NaN value.
(You should return a Series of column labels.)
In[]:
27. A DataFrame has a column of groups 'grps' and and column of numbers 'vals'. For example:
df = pd.DataFrame({'grps': list('aaabbcaabcccbbc'),
'vals': [12,345,3,1,45,14,4,52,54,23,235,21,57,3,87]})
For each group, find the sum of the three greatest values.
In?[?]:
28. A DataFrame has two integer columns 'A' and 'B'. The values in 'A' are between 1 and 100 (inclusive). For
each group of 10 consecutive integers in 'A' (i.e. (0, 10] , (10, 20] , ...), calculate the sum of the
corresponding values in column 'B'.
Out[17]:
'A'
df.sum().idxmin()
len(df) - df.duplicated(keep=False).sum()
# or perhaps more simply...
len(df.drop_duplicates(keep=False))
(df.isnull().cumsum(axis=1) == 3).idxmax(axis=1)
df.groupby('grp')['vals'].nlargest(3).sum(level=0)2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 13/26
In[]:
DataFrames: harder problems
These might require a bit of thinking outside the box...
...but all are solvable using just the usual pandas/NumPy methods (and so avoid using explicit for loops).
Difficulty: hard
29. Consider a DataFrame df where there is an integer column 'X':
df = pd.DataFrame({'X': [7, 2, 0, 3, 4, 2, 5, 0, 3, 4]})
For each value, count the difference back to the previous zero (or the start of the Series, whichever is closer).
These values should therefore be [1, 2, 0, 1, 2, 3, 4, 0, 1, 2] . Make this a new column 'Y'.
In[]:
Here's an alternative approach based on a cookbook recipe (http://pandas.pydata.org/pandasdocs/stable/cookbook.html#grouping):
In[]:
And another approach using a groupby:
In[]:
30. Consider a DataFrame containing rows and columns of purely numerical data. Create a list of the rowdf.groupby(pd.cut(df['A'],
np.arange(0, 101, 10)))['B'].sum()
izero = np.r_[-1, (df['X'] == 0).nonzero()[0]] # indices of zeros
idx = np.arange(len(df))
df['Y'] = idx - izero[np.searchsorted(izero - 1, idx) - 1]
# http://stackoverflow.com/questions/30730981/how-to-count-distance-to-the-previous-
# credit: Behzad Nouri
x = (df['X'] != 0).cumsum()
y = x != x.shift()
df['Y'] = y.groupby((y != y.shift()).cumsum()).cumsum()
df['Y'] = df.groupby((df['X'] == 0).cumsum()).cumcount()
# We're off by one before we reach the first zero.
first_zero_idx = (df['X'] == 0).idxmax()
df['Y'].iloc[0:first_zero_idx] += 12018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 14/26
column index locations of the 3 largest values.
In[]:
31. Given a DataFrame with a column of group IDs, 'grps', and a column of corresponding integer values,
'vals', replace any negative values in 'vals' with the group mean.
In[]:
32. Implement a rolling mean over groups with window size 3, which ignores NaN value. For example consider
the following DataFrame:
>>> df = pd.DataFrame({'group': list('aabbabbbabab'),
'value': [1, 2, 3, np.nan, 2, 3,
np.nan, 1, 7, 3, np.nan, 8]})
>>> df
group value
0 a 1.0
1 a 2.0
2 b 3.0
3 b NaN
4 a 2.0
5 b 3.0
6 b NaN
7 b 1.0
8 a 7.0
9 b 3.0
10 a NaN
11 b 8.0
The goal is to compute the Series:
df.unstack().sort_values()[-3:].index.tolist()
# http://stackoverflow.com/questions/14941261/index-and-column-for-the-max-value-in-
# credit: DSM
def replace(group):
mask = group<0
group[mask] = group[~mask].mean()
return group
df.groupby(['grps'])['vals'].transform(replace)
# http://stackoverflow.com/questions/14760757/replacing-values-with-groupby-means/
# credit: unutbu2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 15/26
0 1.000000
1 1.500000
2 3.000000
3 3.000000
4 1.666667
5 3.000000
6 3.000000
7 2.000000
8 3.666667
9 2.000000
10 4.500000
11 4.000000
E.g. the first window of size three for group 'b' has values 3.0, NaN and 3.0 and occurs at row index 5. Instead
of being NaN the value in the new column at this row index should be 3.0 (just the two non-NaN values are
used to compute the mean (3+3)/2)
In[]:
Series and DatetimeIndex
Exercises for creating and manipulating Series with datetime data
Difficulty: easy/medium
pandas is fantastic for working with dates and times. These puzzles explore some of this functionality.
33. Create a DatetimeIndex that contains each business day of 2015 and use it to index a Series of random
numbers. Let's call this Series s .
In?[?]:
34. Find the sum of the values in s for every Wednesday.
g1 = df.groupby(['group'])['value'] # group values
g2 = df.fillna(0).groupby(['group'])['value'] # fillna, then group values
s = g2.rolling(3, min_periods=1).sum() / g1.rolling(3, min_periods=1).count() # comp
s.reset_index(level=0, drop=True).sort_index() # drop/sort index
# http://stackoverflow.com/questions/36988123/pandas-groupby-and-rolling-apply-ignor
dti = pd.date_range(start='2015-01-01', end='2015-12-31', freq='B')
s = pd.Series(np.random.rand(len(dti)), index=dti)2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 16/26
In[]:
35. For each calendar month in s , find the mean of values.
In[]:
36. For each group of four consecutive calendar months in s , find the date on which the highest value
occurred.
In[]:
37. Create a DateTimeIndex consisting of the third Thursday in each month for the years 2015 and 2016.
In]:
Cleaning Data
Making a DataFrame easier to work with
Difficulty: easy/medium
It happens all the time: someone gives you data containing malformed strings, Python, lists and missing data.
How do you tidy it up so you can get on with the analysis?
Take this monstrosity as the DataFrame to use in the following puzzles:
df = pd.DataFrame({'From_To': ['LoNDon_paris', 'MAdrid_miLAN', 'londON_Stock
hOlm',
'Budapest_PaRis', 'Brussels_londOn'],
'FlightNumber': [10045, np.nan, 10065, np.nan, 10085],
'RecentDelays': [[23, 47], [], [24, 43, 87], [13], [67, 32]],
'Airline': ['KLM(!)', '
(12)', '(British Airw
ays. )',
'12. Air France', '"Swiss Air"']})
(It's some flight data I made up; it's not meant to be accurate in any way.)
38. Some values in the the FlightNumber column are missing. These numbers are meant to increase by 10 with
s[s.index.weekday == 2].sum()
s.resample('M').mean()
s.groupby(pd.TimeGrouper('4M')).idxmax()
pd.date_range('2015-01-01', '2016-12-31', freq='WOM-3THU')2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 17/26
each row so 10055 and 10075 need to be put in place. Fill in these missing numbers and make the column an
integer column (instead of a float column).
In[]:
39. The From_To column would be better as two separate columns! Split each string on the underscore
delimiter _ to give a new temporary DataFrame with the correct values. Assign the correct column names to
this temporary DataFrame.
In[]:
40. Notice how the capitalisation of the city names is all mixed up in this temporary DataFrame. Standardise
the strings so that only the first letter is uppercase (e.g. "londON" should become "London".)
In[]:
41. Delete the From_To column from df and attach the temporary DataFrame from the previous questions.
In[]:
42. In the Airline column, you can see some extra puctuation and symbols have appeared around the airline
names. Pull out just the airline name. E.g. '(British Airways. )' should become 'British
Airways' .
In[]:
43. In the RecentDelays column, the values have been entered into the DataFrame as a list. We would like each
first value in its own column, each second value in its own column, and so on. If there isn't an Nth value, the
value should be NaN.
Expand the Series of lists into a DataFrame named delays , rename the columns delay_1 , delay_2 ,
etc. and replace the unwanted RecentDelays column in df with delays .
df['FlightNumber'] = df['FlightNumber'].interpolate().astype(int)
temp = df.From_To.str.split('_', expand=True)
temp.columns = ['From', 'To']
temp['From'] = temp['From'].str.capitalize()
temp['To'] = temp['To'].str.capitalize()
df = df.drop('From_To', axis=1)
df = df.join(temp)
df['Airline'] = df['Airline'].str.extract('([a-zA-Z\s]+)', expand=False).str.strip()
# note: using .strip() gets rid of any leading/trailing spaces2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 18/26
In[]:
The DataFrame should look much better now.
Using MultiIndexes
Go beyond flat DataFrames with additional index levels
Difficulty: medium
Previous exercises have seen us analysing data from DataFrames equipped with a single index level. However,
pandas also gives you the possibilty of indexing your data using multiple levels. This is very much like adding
new dimensions to a Series or a DataFrame. For example, a Series is 1D, but by using a MultiIndex with 2
levels we gain of much the same functionality as a 2D DataFrame.
The set of puzzles below explores how you might use multiple index levels to enhance data analysis.
To warm up, we'll look make a Series with two index levels.
44. Given the lists letters = ['A', 'B', 'C'] and numbers = list(range(10)) , construct a
MultiIndex object from the product of the two lists. Use it to index a Series of random numbers. Call this Series
s .
In[]:
45. Check the index of s is lexicographically sorted (this is a necessary proprty for indexing to work correctly
with a MultiIndex).
In[]:
# there are several ways to do this, but the following approach is possibly the simp
delays = df['RecentDelays'].apply(pd.Series)
delays.columns = ['delay_{}'.format(n) for n in range(1, len(delays.columns)+1)]
df = df.drop('RecentDelays', axis=1).join(delays)
letters = ['A', 'B', 'C']
numbers = list(range(10))
mi = pd.MultiIndex.from_product([letters, numbers])
s = pd.Series(np.random.rand(30), index=mi)
s.index.is_lexsorted()
# or more verbosely...
s.index.lexsort_depth == s.index.nlevels2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 19/26
46. Select the labels 1 , 3 and 6 from the second level of the MultiIndexed Series.
In[]:
47. Slice the Series s ; slice up to label 'B' for the first level and from label 5 onwards for the second level.
In[]:
48. Sum the values in s for each label in the first level (you should have Series giving you a total for labels A,
B and C).
In[]:
49. Suppose that sum() (and other methods) did not accept a level keyword argument. How else could
you perform the equivalent of s.sum(level=1) ?
In[]:
50. Exchange the levels of the MultiIndex so we have an index of the form (letters, numbers). Is this new Series
properly lexsorted? If not, sort it.
In[]:
Minesweeper
s.loc[:, [1, 3, 6]]
s.loc[pd.IndexSlice[:'B', 5:]]
# or equivalently without IndexSlice...
s.loc[slice(None, 'B'), slice(5, None)]
s.sum(level=0)
# One way is to use .unstack()...
# This method should convince you that s is essentially
# just a regular DataFrame in disguise!
s.unstack().sum(axis=0)
new_s = s.swaplevel(0, 1)
# check
new_s.index.is_lexsorted()
# sort
new_s = new_s.sort_index()2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 20/26
Generate the numbers for safe squares in a Minesweeper grid
Difficulty: medium to hard
If you've ever used an older version of Windows, there's a good chance you've played with [Minesweeper]
(https://en.wikipedia.org/wiki/Minesweeper_(video_game)
(https://en.wikipedia.org/wiki/Minesweeper_(video_game)). If you're not familiar with the game, imagine a grid
of squares: some of these squares conceal a mine. If you click on a mine, you lose instantly. If you click on a
safe square, you reveal a number telling you how many mines are found in the squares that are immediately
adjacent. The aim of the game is to uncover all squares in the grid that do not contain a mine.
In this section, we'll make a DataFrame that contains the necessary data for a game of Minesweeper:
coordinates of the squares, whether the square contains a mine and the number of mines found on adjacent
squares.
51. Let's suppose we're playing Minesweeper on a 5 by 4 grid, i.e.
X = 5
Y = 4
To begin, generate a DataFrame df with two columns, 'x' and 'y' containing every coordinate for this
grid. That is, the DataFrame should start:
x y
0 0 0
1 0 1
2 0 2
In[]:
52. For this DataFrame df , create a new column of zeros (safe) and ones (mine). The probability of a mine
occuring at each location should be 0.4.
In[]:
53. Now create a new column for this DataFrame called 'adjacent' . This column should contain the
number of mines found on adjacent squares in the grid.
(E.g. for the first row, which is the entry for the coordinate (0, 0) , count how many mines are found on the
coordinates (0, 1) , (1, 0) and (1, 1) .)
p = pd.tools.util.cartesian_product([np.arange(X), np.arange(Y)])
df = pd.DataFrame(np.asarray(p).T, columns=['x', 'y'])
# One way is to draw samples from a binomial distribution.
df['mine'] = np.random.binomial(1, 0.4, X*Y)2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 21/26
In[]:
54. For rows of the DataFrame that contain a mine, set the value in the 'adjacent' column to NaN.
In[]:
55. Finally, convert the DataFrame to grid of the adjacent mine counts: columns are the x coordinate, rows
are the y coordinate.
In[]:
Plotting
Visualize trends and patterns in data
Difficulty: medium
To really get a good understanding of the data contained in your DataFrame, it is often essential to create plots:
if you're lucky, trends and anomalies will jump right out at you. This functionality is baked into pandas and the
puzzles below explore some of what's possible with the library.
# Here is one way to solve using merges.
# It's not necessary the optimal way, just
# the solution I thought of first...
df['adjacent'] = \
df.merge(df + [ 1, 1, 0], on=['x', 'y'], how='left')\
.merge(df + [ 1, -1, 0], on=['x', 'y'], how='left')\
.merge(df + [-1, 1, 0], on=['x', 'y'], how='left')\
.merge(df + [-1, -1, 0], on=['x', 'y'], how='left')\
.merge(df + [ 1, 0, 0], on=['x', 'y'], how='left')\
.merge(df + [-1, 0, 0], on=['x', 'y'], how='left')\
.merge(df + [ 0, 1, 0], on=['x', 'y'], how='left')\
.merge(df + [ 0, -1, 0], on=['x', 'y'], how='left')\
.iloc[:, 3:]\
.sum(axis=1)
# An alternative solution is to pivot the DataFrame
# to form the "actual" grid of mines and use convolution.
# See https://github.com/jakevdp/matplotlib_pydata2013/blob/master/examples/mineswee
from scipy.signal import convolve2d
mine_grid = df.pivot_table(columns='x', index='y', values='mine')
counts = convolve2d(mine_grid.astype(complex), np.ones((3, 3)), mode='same').real.as
df['adjacent'] = (counts - mine_grid).ravel('F')
df.loc[df['mine'] == 1, 'adjacent'] = np.nan
df.drop('mine', axis=1)\
.set_index(['y', 'x']).unstack()2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 22/26
56. Pandas is highly integrated with the plotting library matplotlib, and makes plotting DataFrames very userfriendly!
Plotting in a notebook environment usually makes use of the following boilerplate:
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
matplotlib is the plotting library which pandas' plotting functionality is built upon, and it is usually aliased to
plt .
%matplotlib inline tells the notebook to show plots inline, instead of creating them in a separate
window.
plt.style.use('ggplot') is a style theme that most people find agreeable, based upon the styling of
R's ggplot package.
For starters, make a scatter plot of this random data, but use black X's instead of the default markers.
df = pd.DataFrame({"xs":[1,5,2,8,1], "ys":[4,2,1,9,6]})
Consult the documentation (https://pandas.pydata.org/pandasdocs/stable/generated/pandas.DataFrame.plot.html)
if you get stuck!
In[]:
57. Columns in your DataFrame can also be used to modify colors and sizes. Bill has been keeping track of his
performance at work over time, as well as how good he was feeling that day, and whether he had a cup of
coffee in the morning. Make a plot which incorporates all four features of this DataFrame.
(Hint: If you're having trouble seeing the plot, try multiplying the Series which you choose to represent size by
10 or more)
The chart doesn't have to be pretty: this isn't a course in data viz!
df = pd.DataFrame({"productivity":[5,2,3,1,4,5,6,7,8,3,4,8,9],
"hours_in" :[1,9,6,5,3,9,2,9,1,7,4,2,2],
"happiness" :[2,1,3,2,3,1,2,3,1,2,2,1,3],
"caffienated" :[0,0,1,1,0,0,0,0,1,1,0,1,0]})
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
df = pd.DataFrame({"xs":[1,5,2,8,1], "ys":[4,2,1,9,6]})
df.plot.scatter("xs", "ys", color = "black", marker = "x")2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 23/26
In[]:
58. What if we want to plot multiple things? Pandas allows you to pass in a matplotlib Axis object for plots, and
plots will also return an Axis object.
Make a bar plot of monthly revenue with a line plot of monthly advertising spending (numbers in millions)
df = pd.DataFrame({"revenue":[57,68,63,71,72,90,80,62,59,51,47,52],
"advertising":[2.1,1.9,2.7,3.0,3.6,3.2,2.7,2.4,1.8,1.6,1.
3,1.9],
"month":range(12)
})
In[]:
Now we're finally ready to create a candlestick chart, which is a very common tool used to analyze stock price
data. A candlestick chart shows the opening, closing, highest, and lowest price for a stock during a time
window. The color of the "candle" (the thick part of the bar) is green if the stock closed above its opening price,
or red if below.
df = pd.DataFrame({"productivity":[5,2,3,1,4,5,6,7,8,3,4,8,9],
"hours_in" :[1,9,6,5,3,9,2,9,1,7,4,2,2],
"happiness" :[2,1,3,2,3,1,2,3,1,2,2,1,3],
"caffienated" :[0,0,1,1,0,0,0,0,1,1,0,1,0]})
df.plot.scatter("hours_in", "productivity", s = df.happiness * 30, c = df.caffienate
df = pd.DataFrame({"revenue":[57,68,63,71,72,90,80,62,59,51,47,52],
"advertising":[2.1,1.9,2.7,3.0,3.6,3.2,2.7,2.4,1.8,1.6,1.3,1.9],
"month":range(12)
})
ax = df.plot.bar("month", "revenue", color = "green")
df.plot.line("month", "advertising", secondary_y = True, ax = ax)
ax.set_xlim((-1,12))2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 24/26
This was initially designed to be a pandas plotting challenge, but it just so happens that this type of plot is just
not feasible using pandas' methods. If you are unfamiliar with matplotlib, we have provided a function that will
plot the chart for you so long as you can use pandas to get the data into the correct format.
Your first step should be to get the data in the correct format using pandas' time-series grouping function. We
would like each candle to represent an hour's worth of data. You can write your own aggregation function
which returns the open/high/low/close, but pandas has a built-in which also does this.
The below cell contains helper functions. Call day_stock_data() to generate a DataFrame containing the
prices a hypothetical stock sold for, and the time the sale occurred. Call plot_candlestick(df) on your
properly aggregated and formatted stock data to print the candlestick chart.2018/11/8 100-pandas-puzzles-with-solutions
http://localhost:8889/notebooks/100-pandas-puzzles-with-solutions.ipynb 25/26
In[]:
59. Generate a day's worth of random stock data, and aggregate / reformat it so that it has hourly summaries
of the opening, highest, lowest, and closing prices
In[]:
#This function is designed to create semi-interesting r
联系我们
QQ:99515681
邮箱:99515681@qq.com
工作时间:8:00-21:00
微信:codinghelp
热点文章
更多
辅导 comm2000 creating socia...
2026-01-08
讲解 isen1000 – introductio...
2026-01-08
讲解 cme213 radix sort讲解 c...
2026-01-08
辅导 csc370 database讲解 迭代
2026-01-08
讲解 ca2401 a list of colleg...
2026-01-08
讲解 nfe2140 midi scale play...
2026-01-08
讲解 ca2401 the universal li...
2026-01-08
辅导 engg7302 advanced compu...
2026-01-08
辅导 comp331/557 – class te...
2026-01-08
讲解 soft2412 comp9412 exam辅...
2026-01-08
讲解 scenario # 1 honesty讲解...
2026-01-08
讲解 002499 accounting infor...
2026-01-08
讲解 comp9313 2021t3 project...
2026-01-08
讲解 stat1201 analysis of sc...
2026-01-08
辅导 stat5611: statistical m...
2026-01-08
辅导 mth2010-mth2015 - multi...
2026-01-08
辅导 eeet2387 switched mode ...
2026-01-08
讲解 an online payment servi...
2026-01-08
讲解 textfilter辅导 r语言
2026-01-08
讲解 rutgers ece 434 linux o...
2026-01-08
热点标签
mktg2509
csci 2600
38170
lng302
csse3010
phas3226
77938
arch1162
engn4536/engn6536
acx5903
comp151101
phl245
cse12
comp9312
stat3016/6016
phas0038
comp2140
6qqmb312
xjco3011
rest0005
ematm0051
5qqmn219
lubs5062m
eee8155
cege0100
eap033
artd1109
mat246
etc3430
ecmm462
mis102
inft6800
ddes9903
comp6521
comp9517
comp3331/9331
comp4337
comp6008
comp9414
bu.231.790.81
man00150m
csb352h
math1041
eengm4100
isys1002
08
6057cem
mktg3504
mthm036
mtrx1701
mth3241
eeee3086
cmp-7038b
cmp-7000a
ints4010
econ2151
infs5710
fins5516
fin3309
fins5510
gsoe9340
math2007
math2036
soee5010
mark3088
infs3605
elec9714
comp2271
ma214
comp2211
infs3604
600426
sit254
acct3091
bbt405
msin0116
com107/com113
mark5826
sit120
comp9021
eco2101
eeen40700
cs253
ece3114
ecmm447
chns3000
math377
itd102
comp9444
comp(2041|9044)
econ0060
econ7230
mgt001371
ecs-323
cs6250
mgdi60012
mdia2012
comm221001
comm5000
ma1008
engl642
econ241
com333
math367
mis201
nbs-7041x
meek16104
econ2003
comm1190
mbas902
comp-1027
dpst1091
comp7315
eppd1033
m06
ee3025
msci231
bb113/bbs1063
fc709
comp3425
comp9417
econ42915
cb9101
math1102e
chme0017
fc307
mkt60104
5522usst
litr1-uc6201.200
ee1102
cosc2803
math39512
omp9727
int2067/int5051
bsb151
mgt253
fc021
babs2202
mis2002s
phya21
18-213
cege0012
mdia1002
math38032
mech5125
07
cisc102
mgx3110
cs240
11175
fin3020s
eco3420
ictten622
comp9727
cpt111
de114102d
mgm320h5s
bafi1019
math21112
efim20036
mn-3503
fins5568
110.807
bcpm000028
info6030
bma0092
bcpm0054
math20212
ce335
cs365
cenv6141
ftec5580
math2010
ec3450
comm1170
ecmt1010
csci-ua.0480-003
econ12-200
ib3960
ectb60h3f
cs247—assignment
tk3163
ics3u
ib3j80
comp20008
comp9334
eppd1063
acct2343
cct109
isys1055/3412
math350-real
math2014
eec180
stat141b
econ2101
msinm014/msing014/msing014b
fit2004
comp643
bu1002
cm2030
联系我们
- QQ: 99515681 微信:codinghelp
© 2024
www.7daixie.com
站长地图
程序辅导网!