上节课,我们利用numpy和pandas分析了一维数据。在这节课中,你将学到这两种库的更多特性。并用它们来分析
二维数据,这节课后,你将能够使用pandas重新编写你在第一节课中编写的许多代码。
数据:纽约地铁数据
至少提五个问题:
总体来说,我比较感兴趣的是有哪些变量与地铁客流量的高低相关,
如果我是纽约地铁的工作人员,该信息会有助于我们安排地铁班次。我很好奇,
与地铁客流量有关的变量有很多,例如哪个车站的乘客数量最多?
各车站之间的差异有多大?
我还想知道一段时间内的客流量模式。
我会看到客流高峰期的变化吗?工作日和周末又有什么不同。
该数据包含五月的客流情况,其中涉及阵亡将士纪念日,我想知道纪念日当天的客流量是否与周末类似。
我还想知道天气对地铁客流量的影响。在下雨或天气炎热时,乘坐地铁的人数会增加还是减少。
我还可以在不考虑地铁的情况下,单独研究纽约的天气模式。
例如五月之后是夏季,那么在该月中,气温是否会稳步升高。
纽约市各地区的天气又有何不同。
上节课,我们接触了很多一维数据。本节课,我们将使用二维数据。这些数据既有行也有列。在没有任何库的python库中。
你可能会利用列表的列表来表示这些数据。也就是将每一行数据列成一个表,然后再将这些表列入另一个表。
在numpy中,我们不创建数组的数组。而是创建一个二维数组。
在pandas 中,二维数据有一个不同的数据结构,叫做DataFrame.
与上节课相同,我更喜欢使用pandas,因为它有额外的功能。
但这次我要从比较简单的numpy入手。
那么,在numpy中创建一个二维数组,和创建一个由数组构成的一维数组,有什么不同呢?
1.两者间的一个主要差异在于,numpy的运行方式使得创建一个二维数组更节约内存。
2.此外,获取元素的语法也有些不同。—假如你要获取一行三列的这个元素,你将使用a[1,3],而不是在数组
构成的数组中使用的a[1][3].你可以利用上节课中学习的冒号,将行位置,列位置,或两者都表示为slice. 而不是
一个单独的数字。
3.还有一个不同点是你在上节课中学到的函数。例如算术平均值和标准偏差等函数。在二维数组中,这些函数将在整个数组上运行。在这种情况下,算术平均值将计算所有值的平均值。而不考虑其所处的行和列。你无法在数组的数组中计算平均值。但你可以计算每一行的平均值。
import numpy as np
# Subway ridership for 5 stations on 10 different days
ridership = np.array([
[ 0, 0, 2, 5, 0],
[1478, 3877, 3674, 2328, 2539],
[1613, 4088, 3991, 6461, 2691],
[1560, 3392, 3826, 4787, 2613],
[1608, 4802, 3932, 4477, 2705],
[1576, 3933, 3909, 4979, 2685],
[ 95, 229, 255, 496, 201],
[ 2, 0, 1, 27, 0],
[1438, 3785, 3589, 4174, 2215],
[1342, 4043, 4009, 4665, 3033]
])
# Accessing elements
if True:
print(ridership[1, 3])
print(ridership[1:3, 3:5])
print(ridership[1, :])
2328
[[2328 2539]
[6461 2691]]
[1478 3877 3674 2328 2539]
# Vectorized operations on rows or columns--行或者列上的向量运算
if True:
print(ridership[0, :] + ridership[1, :])
print(ridership[:, 0] + ridership[:, 1])
[1478 3877 3676 2333 2539]
[ 0 5355 5701 4952 6410 5509 324 2 5223 5385]
# Vectorized operations on entire arrays---全部数组的向量运算
if True:
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])
print(a + b)
[[ 2 3 4]
[ 6 7 8]
[10 11 12]]
def mean_riders_for_max_station(ridership):
'''
Fill in this function to find the station with the maximum riders on the
first day, then return the mean riders per day for that station. Also
return the mean ridership overall for comparsion.
Hint: NumPy's argmax() function might be useful:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.argmax.html
'''
max_station = ridership[0,:].argmax()
mean_for_max = ridership[:,max_station].mean()
overall_mean = ridership.mean()
return (overall_mean, mean_for_max)
max_station = ridership[0,:].argmax()
print(max_station)
3
mean_riders_for_max_station(ridership)
##也就是说,第一天乘客数量最高的车站,其总客流量也高于平均值。当然这不代表它的总客流量高于其他所有车站。
(2342.6, 3239.9)
首先,我们要找出第一天,乘客数量最多的车站。第一天是数组的第0行。我可以通过0来表示行位置,用冒号表示列位置,
即所有列,通过检验,我发现结果正确,它成功输出了第一行。现在,我要使用max函数来找出最大值。
事实上,我所需要的是拥有最大值的车站。因此,我将使用argmax函数。它能够返回最大值的位置。我们可以看到,它的位置是3,而数组的第三列确实为最大值。我将这个值命名为max_station
#max_station = ridership[0,:].argmax()
#print(max_station)
3
接下来,我想找出这个车站每天的平均乘客数。
首先,我需要该车站的客流数据,所以,我要选择所有行以及max_station列,可以看到,它输出了客流数据的正确一列。
然后我要取这些值的平均值。我将其命名为mean_for_max也就是最大客流量车站的平均值。
#mean_for_max = ridership[:,max_station].mean()
#print(mean_for_max)
3239.9
最后,我需要求出总平均值以进行比较。
为此,我只需利用ridership.mean
#overall_mean = ridership.mean()
(None, None)
大家刚刚看到的是平均值等numpy函数在数组中的整体运行,但在许多情况中,你可能需要以行或列为单位进行计算。
比如,我们刚刚讨论的地铁乘客数组,这里的每一个列和行分别代表一个车站和日期。我们刚才计算了所有地铁每天的平均客流量。有时,我们还需要计算,每个车站和日期的平均客流量。因此numpy中的大多数函数都将数轴作为参数之一。
其值通常为0或1,若数轴为0,则函数计算每一列的平均值。
若数轴为1,则函数计算每一行的平均值。
我觉得计算行和列所需的数轴值很难记,所以,我在使用数轴参数前,通常会试验一下这两个值。
通过例子来学习:
找出每个地铁站每天的客流平均值---n多天的数据平均,然后在所有地铁站中,找出每天的最高和最低客流量
import numpy as np
# Change False to True for this block of code to see what it does
# NumPy axis argument
if True:
a = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
print(a.sum())
print(a.sum(axis=0))
print(a.sum(axis=1))
45
[12 15 18]
[ 6 15 24]
# Subway ridership for 5 stations on 10 different days
ridership = np.array([
[ 0, 0, 2, 5, 0],
[1478, 3877, 3674, 2328, 2539],
[1613, 4088, 3991, 6461, 2691],
[1560, 3392, 3826, 4787, 2613],
[1608, 4802, 3932, 4477, 2705],
[1576, 3933, 3909, 4979, 2685],
[ 95, 229, 255, 496, 201],
[ 2, 0, 1, 27, 0],
[1438, 3785, 3589, 4174, 2215],
[1342, 4043, 4009, 4665, 3033]
])
def min_and_max_riders_per_day(ridership):
'''
Fill in this function. First, for each subway station, calculate the
mean ridership per day. Then, out of all the subway stations, return the
maximum and minimum of these values. That is, find the maximum
mean-ridership-per-day and the minimum mean-ridership-per-day for any
subway station.
'''
station_riders = ridership.mean(axis = 0)##首先,找出各地铁站每天的平均客流量,由于每一列代表一个车站,
##我可以用数轴0的mean函数解决这个问题。结果输出了5个值,每个值对应这个数组中的一个车站
max_daily_ridership = station_riders.max() # 接下来在每日平均客流量中找出最大和最小客流量。
min_daily_ridership = station_riders.min() # Replace this with your code
return (max_daily_ridership, min_daily_ridership)
min_and_max_riders_per_day(ridership)
##从输出结果可见,每天客流量最大的车站约有3200名乘客。而客流量最小的车站约有1000名乘客。
##这个最大值与我们上次看到的,第一天最大客流车站的平均客流量相同,这说明,在这种情况下,第一天客流量
##最大的车站所拥有的乘客数也最多。
##而最低值低于我们之前计算的总平均值,这样比较合理。
(3239.9, 1071.2)
station_riders = ridership.mean(axis = 0)
print(station_riders)
[1071.2 2814.9 2718.8 3239.9 1868.2]
在上节课中,我们看到numpy数组有一个dtype,即数组中每一个元素的类型。比如,这个数组的dtype是int32
import numpy as np
np.array([1,2,3,4,5]).dtype
dtype('int32')
int32–表示32位的整数。这也适用与二维数组。数组中的每一个元素都应属于同一类型。这不便
于我们利用未转换的numpy二维数组来表现csv文件的内容。
来表示第一节课中的学生的课程注册数据,我在这里还原了一部分相关数据,尽管在创建数组时,我输入的整数和
布尔值没有加引号,但每一个元素仍被转换成了一个字符串。它的dtype仍是s14,即字符串最长为14位。
计算cancelled等字符串的平均值显然没有任何意义。
当存在非值的值时,它便无法计算平均值。这就是pandas dataframe 优于numpy二维数组的地方。
dataframe 也是二维数据结构,但每一列可为不同类型。,
dataframe的另一个优点是拥有类似pandas的series索引。每一行都有一个索引值,每一列都有一个名称。
因此,我要利用该数据创建一个pandas dataframe
为此,我可以输入一个字典,使列名称映射其值列表。字典中的关键字之一是 account_key.
列表为account_key列的所有值。同样,其他列可以类推。
列名称位于顶端,行索引值为从0开始的整数。创建dataframe的方式有很多–稍后看
计算dataframe的平均值,它会取每一列值的平均值并忽略其他值。
pandas 并没有计算整个dataframe的平均值。而是计算了各列的平均值。由于每一列可能属于不同类型。
所以,pandas这样的做法更合理。
你还可以利用数轴参数来计算各行的平均值,但由于每一行都包含非值数据,所以这种做法在这里是不可行的。
1.按照索引和位置来获取行
2.获取行列
3.获取列
4…values不包含列名称和行索引
获取dataframe的某一行类似于获取一组数中的某一元素。你可以利用.loc按照索引来获取相应的一行。
比如:iloc[0,3]就是第0行和第三列的元素。
同样的道理,我可以用.loc指定一个日期和单元。并得到相应的值。
仅含有dataframe中值的numpy二维数组。
当然,在这种情况下,你需要注意数据的类型。你这样做可能是希望计算所有值的平均值。
而不仅仅是每一行或每一列的平均值。
pandas dataframe并不支持这一做法。但你可以在numpy数组上利用.values调用.mean.
import pandas as pd
# Subway ridership for 5 stations on 10 different days
ridership_df = pd.DataFrame(
data=[[ 0, 0, 2, 5, 0],
[1478, 3877, 3674, 2328, 2539],
[1613, 4088, 3991, 6461, 2691],
[1560, 3392, 3826, 4787, 2613],
[1608, 4802, 3932, 4477, 2705],
[1576, 3933, 3909, 4979, 2685],
[ 95, 229, 255, 496, 201],
[ 2, 0, 1, 27, 0],
[1438, 3785, 3589, 4174, 2215],
[1342, 4043, 4009, 4665, 3033]],
index=['05-01-11', '05-02-11', '05-03-11', '05-04-11', '05-05-11',
'05-06-11', '05-07-11', '05-08-11', '05-09-11', '05-10-11'],
columns=['R003', 'R004', 'R005', 'R006', 'R007']
)
# Change False to True for each block of code to see what it does
# DataFrame creation
if True:
# You can create a DataFrame out of a dictionary mapping column names to values 创建方法一:字典映射列名--值
df_1 = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5]})
print(df_1)
# You can also use a list of lists or a 2D NumPy array 创建方法2:使用列表的列表或者二维数组
df_2 = pd.DataFrame([[0, 1, 2], [3, 4, 5]], columns=['A', 'B', 'C'])
print(df_2)
A B
0 0 3
1 1 4
2 2 5
A B C
0 0 1 2
1 3 4 5
# Accessing elements--获取元素
if True:
print(ridership_df.iloc[0]) ##获取0行
print(ridership_df.loc['05-05-11'])## 获取 05-05-11行
print(ridership_df['R003'])## 获取R003列
print(ridership_df.iloc[1, 3])##获取1行3列---中间有冒号,说明是单独获取行,如果中间是逗号,则说明获取行列,就是dataframe中第三中
##获取值的方式,行列交互获取
R003 0
R004 0
R005 2
R006 5
R007 0
Name: 05-01-11, dtype: int64
R003 1608
R004 4802
R005 3932
R006 4477
R007 2705
Name: 05-05-11, dtype: int64
05-01-11 0
05-02-11 1478
05-03-11 1613
05-04-11 1560
05-05-11 1608
05-06-11 1576
05-07-11 95
05-08-11 2
05-09-11 1438
05-10-11 1342
Name: R003, dtype: int64
2328
# Accessing multiple rows## 获取多行
if True:
print(ridership_df.iloc[1:4])
R003 R004 R005 R006 R007
05-02-11 1478 3877 3674 2328 2539
05-03-11 1613 4088 3991 6461 2691
05-04-11 1560 3392 3826 4787 2613
# Accessing multiple columns## 通过中括号获取多列
if True:
print(ridership_df[['R003', 'R005']])
# Pandas axis## Pandas轴
if True:
df = pd.DataFrame({'A': [0, 1, 2], 'B': [3, 4, 5]})
print(df.sum())## 是针对每列进行汇总求和
print(df.sum(axis=1))## 针对每行汇总求和
print(df.values.sum())## 针对所有进行汇总计算
A 3
B 12
dtype: int64
0 3
1 5
2 7
dtype: int64
15
def mean_riders_for_max_station(ridership):
'''
Fill in this function to find the station with the maximum riders on the
first day, then return the mean riders per day for that station. Also
return the mean ridership overall for comparsion.
This is the same as a previous exercise, but this time the
input is a Pandas DataFrame rather than a 2D NumPy array.
'''
max_station = ridership.iloc[0].argmax()## 获取第一行中最大值的列名
mean_for_max = ridership[max_station].mean()## 获取该列--对应该火车站每日平均值
overall_mean = ridership.values.mean()# Replace this with your code
return (overall_mean, mean_for_max)
## 如果写成这样 :ridership_df[0,:].argmax()
## 运行后会报错。
##第一天中乘客最多的站
ridership_df.iloc[0].argmax()
对于numpy array 而言,argmax函数返回的是位置。
但是对于pandas series,argmax 函数返回的是这列数的索引值
或在这种情况下,它返回的是dataframe的列名—ridership_df.iloc[0].argmax()
dataframe是能够有效表示csv文件内容的一种数据结构,它是允许每一列属于不同类型的二维数据结构。
我们所需的csv通常就是这样的。pandas 有一个名为read_csv的函数。
它接收CSV文件的文件名作为参数,并且将文件内容加载为dataframe
head 函数可以打印加载数据的前几行,自己自定义。返回一个较小的dataframe
也可以使用describle函数,来查看每一列的统计数据,如平均值,和标准偏差
接下来要写出一个计算两个变量之间相关度的函数。它也被称为皮尔逊积矩相关系数。
在上节课中,我们使用了粗糙启发式算法来确定两个变量间的相关度。我们研究了每一对值是否高于或低于其平均值,
或是否有一个值高于其平均值,而另一个值低于其平均值。
皮尔逊积矩相关系数的道理于此相似。
首先,将各变量标准化,也就是将其转换成低于或高于平均值的标准偏差。
然后,将每一对值相乘并计算乘积的平均值。
也就是说 r 等于标准单位的x 乘以 标准单位的y的平均值
我们看一下它的作用是什么,首先,通过标准化,可将两个变量都转换为相同的比例。
例如,如果变量在y维度上,比其在x维度上更为分散。
那么标准化会使变量在x维度上的分布也更为分散。而由于每个数据点都减去了平均值。这个空间被分成了四个部分
若两个值均高于平均值,则标准化的x和y值均为正值。那么乘积也为正值。
若两个值均低于平均值,则标准化的x和y坐标值均为负值。那么乘积同样是正值。
因此,若皮尔逊积矩相关系数为正数,那么一个变量会随着另一个变量的增加而增加。
但若一个变量低于平均值,而另一个变量高于平均值,则乘积为负值。所以,若皮尔逊积矩相关系数为负数,
则一个变量会随着另一个变量的增加而减少。
皮尔逊积矩相关系数比我们之前使用的启发式算法更精确。因为除了数据点所处的象限以外。它还会考虑到很多其他信息。
所以他对皮尔逊积矩相关系数的贡献很小。而另一个数据点与平均值的距离较远。因此,他对皮尔逊积矩相关系数的贡献较大。
皮尔逊积矩相关系数位于-1至+1之间。若它接近0,则意味着变量的相关度较低。
import pandas as pd
filename = r'C:\My documents\Learning file\Udacity\Introductory course for Data analysis\project 2\two dimentional data\nyc-subway-weather.csv'
subway_df = pd.read_csv(filename)
def correlation(x, y):
'''
Fill in this function to compute the correlation between the two
input variables. Each input is either a NumPy array or a Pandas
Series.
correlation = average of (x in standard units) times (y in standard units)
Remember to pass the argument "ddof=0" to the Pandas std() function!
'''
##首先将x,y标准化
std_x = (x - x.mean()) / x.std(ddof=0)## 使用ddof从而取得未更正的标准偏差。
std_y = (y - y.mean()) / y.std(ddof=0) ## 需要注意小括号的使用
## 然后将每一对值相乘,使用向量化乘法,然后用mean函数来取乘积的平均值。
return (std_x * std_y).mean()
## 事实上numpy有一个函数,可以帮你计算皮尔逊积矩相关系数
entries = subway_df['ENTRIESn_hourly']
cum_entries = subway_df['ENTRIESn']
rain = subway_df['meanprecipi']
temp = subway_df['meantempi']
##接下来用此函数计算地铁数据中部分变量的相关度
print(correlation(entries, rain))
print(correlation(entries, temp))
print(correlation(rain, temp))
print(correlation(entries, cum_entries))
0.03564851577223041
-0.026693348321569912
-0.22903432340833663
0.5858954707662182
与numpy一样,许多pandas函数也使用数轴参数。
你可以使数轴等于0或1,比如在numpy中。
但你也可以使数轴等于索引值或列。
这样来看,好像相应的数轴参数值很好记。但事实上,这个比较容易混淆。
在数轴等于列的情况下计算平均值时,其实不是计算每一列的平均值,而是计算每一行的平均值。因为你是沿着某一列取平均值。
同样的,若数轴等于索引值,你是沿着索引或某一行取平均值。
dataframe的向量化运算与numpy二维数组的运行方式相似。
与pandas series 类似,它根据索引和列名,而不是根据位置将元素配对。
import pandas as pd
# Examples of vectorized operations on DataFrames:
# Change False to True for each block of code to see what it does
# Adding DataFrames with the column names 列名相加
if True:
df1 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]})
df2 = pd.DataFrame({'a': [10, 20, 30], 'b': [40, 50, 60], 'c': [70, 80, 90]})
print(df1 + df2)
a b c
0 11 44 77
1 22 55 88
2 33 66 99
# Adding DataFrames with overlapping column names 重叠列名相加
if True:
df1 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]})
df2 = pd.DataFrame({'d': [10, 20, 30], 'c': [40, 50, 60], 'b': [70, 80, 90]})
print(df1 + df2)
a b c d
0 NaN 74 47 NaN
1 NaN 85 58 NaN
2 NaN 96 69 NaN
# Adding DataFrames with overlapping row indexes 重叠行名 相加
if True:
df1 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]},
index=['row1', 'row2', 'row3'])
df2 = pd.DataFrame({'a': [10, 20, 30], 'b': [40, 50, 60], 'c': [70, 80, 90]},
index=['row4', 'row3', 'row2'])
print(df1 + df2)
a b c
row1 NaN NaN NaN
row2 32.0 65.0 98.0
row3 23.0 56.0 89.0
row4 NaN NaN NaN
# --- Quiz ---
# Cumulative entries and exits for one station for a few hours.
## 下边的数据是每小时的总的入站人数与总的出站人数
entries_and_exits = pd.DataFrame({
'ENTRIESn': [3144312, 3144335, 3144353, 3144424, 3144594,
3144808, 3144895, 3144905, 3144941, 3145094],
'EXITSn': [1088151, 1088159, 1088177, 1088231, 1088275,
1088317, 1088328, 1088331, 1088420, 1088753]
})
def get_hourly_entries_and_exits(entries_and_exits):
'''
Fill in this function to take a DataFrame with cumulative entries
and exits (entries in the first column, exits in the second) and
return a DataFrame with hourly entries and exits (entries in the
first column, exits in the second).
'''
## 为了计算每小时的出入站人数,我要用dataframe中的每个值减去前一行的值
## 因此 我要用向量运算和位移函数,这里,我把dataframe中的每个值,减去位移1的dataframe
##这样我就得到了前一行
return entries_and_exits - entries_and_exits.shift(1)
get_hourly_entries_and_exits(entries_and_exits)
ENTRIESn | EXITSn | |
---|---|---|
0 | NaN | NaN |
1 | 23.0 | 8.0 |
2 | 18.0 | 18.0 |
3 | 71.0 | 54.0 |
4 | 170.0 | 44.0 |
5 | 214.0 | 42.0 |
6 | 87.0 | 11.0 |
7 | 10.0 | 3.0 |
8 | 36.0 | 89.0 |
9 | 153.0 | 333.0 |
与pandas series一样,有时你可能无法通过内置函数或算法来完成,你需要在dataframe中进行的计算。
与series相同,你可以写出一个函数f.使其从dataframe中取出一个元素并返回一个新元素。
然后,你可以对原dataframe中的每个元素,调用(apply)这个函数f,从而获得新的dataframe
我们经常会对DataFrame对象中的某些行或列,或者对DataFrame对象中的所有元素进行某种运算或操作,我们无需利用低效笨拙的循环,DataFrame给我们分别提供了相应的直接而简单的方法,apply()和applymap()。其中apply()方法是针对某些行或列进行操作的,而applymap()方法则是针对所有元素进行操作的。
在下个视频会了解到调用在dataframe中的作用有些不同。
import pandas as pd
# Change False to True for this block of code to see what it does
# DataFrame applymap()
if True:
df = pd.DataFrame({
'a': [1, 2, 3],
'b': [10, 20, 30],
'c': [5, 10, 15]
})
def add_one(x):
return x + 1
print(df.applymap(add_one))
a b c
0 2 11 6
1 3 21 11
2 4 31 16
grades_df = pd.DataFrame(
data={'exam1': [43, 81, 78, 75, 89, 70, 91, 65, 98, 87],
'exam2': [24, 63, 56, 56, 67, 51, 79, 46, 72, 60]},
index=['Andre', 'Barry', 'Chris', 'Dan', 'Emilio',
'Fred', 'Greta', 'Humbert', 'Ivan', 'James']
)
def convert_grade(grades):
'''
Fill in this function to convert the given DataFrame of numerical
grades to letter grades. Return a new DataFrame with the converted
grade.
The conversion rule is:
90-100 -> A
80-89 -> B
70-79 -> C
60-69 -> D
0-59 -> F
'''
if grades >= 90:
return "A"
elif grades >= 80:
return "B"
elif grades >= 70:
return "C"
elif grades >= 60:
return "D"
else:
return "F"
def convert_grades(grades):
return grades.applymap(convert_grade)##用applymap函数,在dataframe的每一个元素上调用convert_grade函数。
convert_grades(grades_df)
exam1 | exam2 | |
---|---|---|
Andre | F | F |
Barry | B | D |
Chris | C | F |
Dan | C | F |
Emilio | B | D |
Fred | C | F |
Greta | A | C |
Humbert | D | F |
Ivan | A | C |
James | B | D |
我在上一个视频中提到dataframe还有apply函数,它是干什么用的呢?从某种意义上说,dataframe 的apply就是直接对
series中apply的模拟。
它取决与你对dataframe的定义,你可以把一列数据视为一条dataframe,而不只是一个单独的元素。
你输入调用的这个函数f,载入pandasseries,也就是dataframe的全部列。
然后返回一个新的pandasseries即dataframe的新列。
之后在调用df.apply(f)时,apply函数在dataframe的每一列上调用你的函数f.
你可能会问,为社么要这样做,而不使用applymap呢?
这是因为,你想针对dataframe各元素进行的运算,可能取决与整个列。
思考一下对分数进行等级划分的例子,假设我想给予最高成绩中前20%的学生A,其次的30%为B,再其次的30%和2个10%分别是C,D,F.我可以像之前那样存储dataframe中的数字分数。其每列为一个科目,每行为一个学生。但这次我不能用applymap.
在已知某科目一个分数,而不知道其他分数的情况下,我无法确定它相应的字母成绩。
例如,70分属于A吗?如果该科目的其他分数都比它高,那70就不是A.
但如果该科目难度较高,其他分数都比它低,那70就可能是A.
我要做的是写一个函数,使其载入某一科的分数后,返回其转换后的字母分数。
然后,我要调用df.apply(f)在整个dataframe中调用该函数。
apply函数还有访问参数,因此,如有需要,你还可以写一个每次仅进行一行运算的函数。
上节课中,我们写了标准化单个pandasseries的函数,也就是,将每个值转换为高于或低于平均值的标准偏差值。
现在,我需要你通过apply函数对dataframe的每一列进行标准化。
import pandas as pd
grades_df = pd.DataFrame(
data={'exam1': [43, 81, 78, 75, 89, 70, 91, 65, 98, 87],
'exam2': [24, 63, 56, 56, 67, 51, 79, 46, 72, 60]},
index=['Andre', 'Barry', 'Chris', 'Dan', 'Emilio',
'Fred', 'Greta', 'Humbert', 'Ivan', 'James']
)
# Change False to True for this block of code to see what it does
# DataFrame apply()--qcut函数
if True:
def convert_grades_curve(exam_grades):
# Pandas has a bult-in function that will perform this calculation
# This will give the bottom 0% to 10% of students the grade 'F',
# 10% to 20% the grade 'D', and so on. You can read more about
# the qcut() function here:
## http://www.mamicode.com/info-detail-2391484.html
# http://pandas.pydata.org/pandas-docs/stable/generated/pandas.qcut.html
return pd.qcut(exam_grades,
[0, 0.1, 0.2, 0.5, 0.8, 1],
labels=['F', 'D', 'C', 'B', 'A'])
# qcut() operates on a list, array, or Series. This is the
# result of running the function on a single column of the
# DataFrame.
print(convert_grades_curve(grades_df['exam1']))
# qcut() does not work on DataFrames, but we can use apply()
# to call the function on each column separately
print(grades_df.apply(convert_grades_curve))
## 要写出标准化函数,我首先要写出标准化dadtframe单列的函数,之后,我要在dataframe的每一列上调用该函数。
## 我把适用与单列的函数称为standardardized_column
def standardize_column(column):
return(column - column.mean()) / column.std()
##我要在成绩dataframe的单列上调用该函数,以对其进行测试。
print(standardize_column(grades_df["exam1"]))
##然后我要调用df.apply并输入standardized_column函数
##从而对dataframe各列进行标准化。
def standardize(df):
'''
Fill in this function to standardize each column of the given
DataFrame. To standardize a variable, convert each value to the
number of standard deviations it is above or below the mean.
'''
return df.apply(standardize_column)
standardize(grades_df)
Andre F
Barry B
Chris C
Dan C
Emilio B
Fred C
Greta A
Humbert D
Ivan A
James B
Name: exam1, dtype: category
Categories (5, object): [F < D < C < B < A]
exam1 exam2
Andre F F
Barry B B
Chris C C
Dan C C
Emilio B B
Fred C C
Greta A A
Humbert D D
Ivan A A
James B B
Andre -2.196525
Barry 0.208891
Chris 0.018990
Dan -0.170911
Emilio 0.715295
Fred -0.487413
Greta 0.841896
Humbert -0.803916
Ivan 1.284999
James 0.588694
Name: exam1, dtype: float64
exam1 | exam2 | |
---|---|---|
Andre | -2.196525 | -2.186335 |
Barry | 0.208891 | 0.366571 |
Chris | 0.018990 | -0.091643 |
Dan | -0.170911 | -0.091643 |
Emilio | 0.715295 | 0.628408 |
Fred | -0.487413 | -0.418938 |
Greta | 0.841896 | 1.413917 |
Humbert | -0.803916 | -0.746234 |
Ivan | 1.284999 | 0.955703 |
James | 0.588694 | 0.170194 |
还有另一种在dataframe上使用apply函数的方法,这次,我们不将某列数据转换为新的一列,函数f,还可以将一列数据转换为单个值,在这种情况下,apply函数不会创建新的dataframe而是创建一个新的series。
dataframe的每一列均被转换成一个单值。
例如,如果我想找到每一列的最大值,我可以调用df.apply(np.max),从而在dataframe 的每一列上调用numpy的最大值函数
它的结果是一样的,这个内置函数叫做df.max
所以,在这种情况下,使用内置函数比较简单。
但在没有满足你需要的内置函数时,apply函数就非常有用了。
例如,如果你想要找出每一列的第二大值。那就需要使用apply
import numpy as np
import pandas as pd
df = pd.DataFrame({
'a': [4, 5, 3, 1, 2],
'b': [20, 10, 40, 50, 30],
'c': [25, 20, 5, 15, 10]
})
# Change False to True for this block of code to see what it does
# DataFrame apply() - use case 2
if True:
print(df.apply(np.mean))
print(df.apply(np.max))
# 首先写出在单列上运算的函数。
## 想要在一列中找出第二大值,方法很多,我们使用:将该列按照降序排列---搜索引擎查找 pandas排序函数
## sort_values--inplace默认是原来的series,ascending 是升序排列
## 用iloc来获取第二个值,
def second_largest_in_column(column):
sorted_column = column.sort_values(ascending = False)
return sorted_column.iloc[1]
print(second_largest_in_column(df["a"]))
def second_largest(df):
'''
Fill in this function to return the second-largest value of each
column of the input DataFrame.
'''
return df.apply(second_largest_in_column)
print(second_largest(df))
a 3.0
b 30.0
c 15.0
dtype: float64
a 5
b 50
c 25
dtype: int64
4
a 4
b 40
c 20
dtype: int64
我们已经知道,可以用向量运算把两个dataframe相加。
这与把两个series相加是一个道理。
我们还可以在pandas中把dataframe和series相加,你认为结果是什么:
总体来说,将dataframe和series相加,就是将dataframe的每一列与series的每一个值相加。
它根据series的索引值和dataframe的列名,匹配series和dataframe
import pandas as pd
# Change False to True for each block of code to see what it does
# Adding a Series to a square DataFrame series + 方形dataframe
if True:
s = pd.Series([1, 2, 3, 4])
df = pd.DataFrame({
0: [10, 20, 30, 40],
1: [50, 60, 70, 80],
2: [90, 100, 110, 120],
3: [130, 140, 150, 160]
})
print(s)
print(df)
print('') # Create a blank line between outputs)
print(df + s)
0 1
1 2
2 3
3 4
dtype: int64
0 1 2 3
0 10 50 90 130
1 20 60 100 140
2 30 70 110 150
3 40 80 120 160
0 1 2 3
0 11 52 93 134
1 21 62 103 144
2 31 72 113 154
3 41 82 123 164
# Adding a Series to a one-row DataFrame
if True:
s = pd.Series([1, 2, 3, 4])
df = pd.DataFrame({0: [10], 1: [20], 2: [30], 3: [40]})
print(s)
print(df)
print('') # Create a blank line between outputs
print(df + s)
0 1
1 2
2 3
3 4
dtype: int64
0 1 2 3
0 10 20 30 40
0 1 2 3
0 11 22 33 44
# Adding a Series to a one-column DataFrame
if True:
s = pd.Series([1, 2, 3, 4])
df = pd.DataFrame({0: [10, 20, 30, 40]})
print(s)
print(df)
print( '') # Create a blank line between outputs
print(df + s)##----df.add(s) 通常与df+s相同,使用这个函数的好处是可以使用数轴参数。
## df.add(s,axis = "index")--series 的每一个值与dataframe的各行相加
## df.add(s,axis = "column")--结果于此相同
print(df.add(s,axis = "index"))
0 1
1 2
2 3
3 4
dtype: int64
0
0 10
1 20
2 30
3 40
0 1 2 3
0 11 NaN NaN NaN
1 21 NaN NaN NaN
2 31 NaN NaN NaN
3 41 NaN NaN NaN
0
0 11
1 22
2 33
3 44
# Adding when DataFrame column names match Series index
if True:
s = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
df = pd.DataFrame({
'a': [10, 20, 30, 40],
'b': [50, 60, 70, 80],
'c': [90, 100, 110, 120],
'd': [130, 140, 150, 160]
})
print(s)
print(df)
print('') # Create a blank line between outputs
print(df + s)
a 1
b 2
c 3
d 4
dtype: int64
a b c d
0 10 50 90 130
1 20 60 100 140
2 30 70 110 150
3 40 80 120 160
a b c d
0 11 52 93 134
1 21 62 103 144
2 31 72 113 154
3 41 82 123 164
# Adding when DataFrame column names don't match Series index
if True:
s = pd.Series([1, 2, 3, 4])
df = pd.DataFrame({
'a': [10, 20, 30, 40],
'b': [50, 60, 70, 80],
'c': [90, 100, 110, 120],
'd': [130, 140, 150, 160]
})
print(s)
print(df)
print('') # Create a blank line between outputs
print(df + s)
0 1
1 2
2 3
3 4
dtype: int64
a b c d
0 10 50 90 130
1 20 60 100 140
2 30 70 110 150
3 40 80 120 160
a b c d 0 1 2 3
0 NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN
此前,你使用过调用(apply)函数,现在我希望大家能利用刚刚学到的知识再次编写这个代码。
但这次不要借助,调用函数。而只使用向量算法。
这里增加了难道,请尝试对dataframe的每一行进行标准化。同样也不需要使用调用函数
import pandas as pd
# Adding using +
if True:
s = pd.Series([1, 2, 3, 4])
df = pd.DataFrame({
0: [10, 20, 30, 40],
1: [50, 60, 70, 80],
2: [90, 100, 110, 120],
3: [130, 140, 150, 160]
})
print(df)
print('') # Create a blank line between outputs
print(df + s)
0 1 2 3
0 10 50 90 130
1 20 60 100 140
2 30 70 110 150
3 40 80 120 160
0 1 2 3
0 11 52 93 134
1 21 62 103 144
2 31 72 113 154
3 41 82 123 164
# Adding with axis='index'
if True:
s = pd.Series([1, 2, 3, 4])
df = pd.DataFrame({
0: [10, 20, 30, 40],
1: [50, 60, 70, 80],
2: [90, 100, 110, 120],
3: [130, 140, 150, 160]
})
print(df)
print('') # Create a blank line between outputs
print(df.add(s, axis='index'))
# The functions sub(), mul(), and div() work similarly to add()
## ## df.add(s,axis = "index")--series 的每一个值与dataframe的各行相加
0 1 2 3
0 10 50 90 130
1 20 60 100 140
2 30 70 110 150
3 40 80 120 160
0 1 2 3
0 11 51 91 131
1 22 62 102 142
2 33 73 113 153
3 44 84 124 164
# Adding with axis='columns'
if True:
s = pd.Series([1, 2, 3, 4])
df = pd.DataFrame({
0: [10, 20, 30, 40],
1: [50, 60, 70, 80],
2: [90, 100, 110, 120],
3: [130, 140, 150, 160]
})
print(df)
print('') # Create a blank line between outputs
print(df.add(s, axis='columns'))
# The functions sub(), mul(), and div() work similarly to add()
0 1 2 3
0 10 50 90 130
1 20 60 100 140
2 30 70 110 150
3 40 80 120 160
0 1 2 3
0 11 52 93 134
1 21 62 103 144
2 31 72 113 154
3 41 82 123 164
grades_df = pd.DataFrame(
data={'exam1': [43, 81, 78, 75, 89, 70, 91, 65, 98, 87],
'exam2': [24, 63, 56, 56, 67, 51, 79, 46, 72, 60]},
index=['Andre', 'Barry', 'Chris', 'Dan', 'Emilio',
'Fred', 'Greta', 'Humbert', 'Ivan', 'James']
)
## w我现在要针对涉及2个科目和5个学生成绩的dataframe写出相关代码
## 首先:我需要各列的平均值
print(grades_df.mean())
exam1 77.7
exam2 57.4
dtype: float64
## 还要看一下原dataframe,要对每一列进行标准化,我需要用各列减去其平均值
print(grades_df - grades_df.mean())
exam1 exam2
Andre -34.7 -33.4
Barry 3.3 5.6
Chris 0.3 -1.4
Dan -2.7 -1.4
Emilio 11.3 9.6
Fred -7.7 -6.4
Greta 13.3 21.6
Humbert -12.7 -11.4
Ivan 20.3 14.6
James 9.3 2.6
## 接下来我要用标准偏差除以相应的列
print((grades_df - grades_df.mean())/grades_df.std())
exam1 exam2
Andre -2.196525 -2.186335
Barry 0.208891 0.366571
Chris 0.018990 -0.091643
Dan -0.170911 -0.091643
Emilio 0.715295 0.628408
Fred -0.487413 -0.418938
Greta 0.841896 1.413917
Humbert -0.803916 -0.746234
Ivan 1.284999 0.955703
James 0.588694 0.170194
## 如何标准化每一行呢??首先看原dataframe,这次需要各行的平均值,为此,我设置数轴等于列
## 意味着我要沿着每一列取平均值--这样就能得到每行的平均值。
print(grades_df.mean(axis="columns"))
Andre 33.5
Barry 72.0
Chris 67.0
Dan 65.5
Emilio 78.0
Fred 60.5
Greta 85.0
Humbert 55.5
Ivan 85.0
James 73.5
dtype: float64
## 现在我需要用dataframe的第一行减去第一个平均值,再用第二行减去第二个平均值。
## 但如果像刚才那样,用grades_df - grades_df.mean(),它就会用dataframe的一列减去这些值。这样是不行的
## 所以我需要使用sub函数,它代表减法,与减号有着相同的作用,但它还可以引入数轴参数。
## 在这种情况下,数轴应该是索引值。因为我想利用行索引值把dataframe的元素和series的元素相匹配()
## 我们将该dataframe命名为mean_diffs,以便此后使用
mean_diffs = grades_df.sub(grades_df.mean(axis="columns"),axis="index")
print(mean_diffs)
exam1 exam2
Andre 9.5 -9.5
Barry 9.0 -9.0
Chris 11.0 -11.0
Dan 9.5 -9.5
Emilio 11.0 -11.0
Fred 9.5 -9.5
Greta 6.0 -6.0
Humbert 9.5 -9.5
Ivan 13.0 -13.0
James 13.5 -13.5
## 接下来要用标准偏差做除法,使成绩列的标准偏差等于列,同时使数轴等于列,这样得到每一行的标准偏差了
grades_df.std(axis="columns")
print(grades_df.std(axis="columns"))
Andre 13.435029
Barry 12.727922
Chris 15.556349
Dan 13.435029
Emilio 15.556349
Fred 13.435029
Greta 8.485281
Humbert 13.435029
Ivan 18.384776
James 19.091883
dtype: float64
##然后通过mean_diffs.div用标准偏差series除以mean_diffs dataframe,然后我要通过数轴等于索引值,根据
##行索引匹配元素。
print(mean_diffs.div(grades_df.std(axis="columns"),axis="index"))
exam1 exam2
Andre 0.707107 -0.707107
Barry 0.707107 -0.707107
Chris 0.707107 -0.707107
Dan 0.707107 -0.707107
Emilio 0.707107 -0.707107
Fred 0.707107 -0.707107
Greta 0.707107 -0.707107
Humbert 0.707107 -0.707107
Ivan 0.707107 -0.707107
James 0.707107 -0.707107
engagement_df.groupby(“account_key”)–可以创建一个名为dataframegroupby object的特殊对象。
我将它视为一种字典,它映射各accout_key 和仅含有与该account相匹配的行的小型dataframe.
但事实上,它并不是字典,而是自定义对象,可以通过.groups属性查看映射。
接下来要对groupby对象使用.sum函数,以将各组的每一列相加。
在这里sum函数是一个groupby对象,所以我想知道,groupby对象还有什么其他函数,如果没有你需要的函数该怎么办?
与series和dataframe相同,groupby对象有很多方便使用的内置函数。但如果仍找不到你需要的函数,你可以用appLy函数
编写自己的函数,
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
values = np.array([1, 3, 2, 4, 1, 6, 4])
example_df = pd.DataFrame({
'value': values,
'even': values % 2 == 0,
'above_three': values > 3
}, index=['a', 'b', 'c', 'd', 'e', 'f', 'g'])
# Change False to True for each block of code to see what it does
# Examine DataFrame
if True:
print(example_df)
value even above_three
a 1 False False
b 3 False False
c 2 True False
d 4 True True
e 1 False False
f 6 True True
g 4 True True
# Examine groups
if True:
grouped_data = example_df.groupby('even')
# The groups attribute is a dictionary mapping keys to lists of row indexes
print(grouped_data.groups)
{False: Index(['a', 'b', 'e'], dtype='object'), True: Index(['c', 'd', 'f', 'g'], dtype='object')}
# Group by multiple columns
if True:
grouped_data = example_df.groupby(['even', 'above_three'])
print(grouped_data.groups)
{(False, False): Index(['a', 'b', 'e'], dtype='object'), (True, False): Index(['c'], dtype='object'), (True, True): Index(['d', 'f', 'g'], dtype='object')}
# Get sum of each group
if True:
grouped_data = example_df.groupby('even')
print(grouped_data.sum())
value above_three
even
False 5 0.0
True 16 3.0
# Limit columns in result
if True:
grouped_data = example_df.groupby('even')
# You can take one or more columns from the result DataFrame
print(grouped_data.sum()['value'])
print('\n' # Blank line to separate results)
# You can also take a subset of columns from the grouped data before
# collapsing to a DataFrame. In this case, the result is the same.
print(grouped_data['value'].sum())
File "", line 12
print(grouped_data['value'].sum())
^
SyntaxError: invalid syntax
filename = '/datasets/ud170/subway/nyc_subway_weather.csv'
subway_df = pd.read_csv(filename)
### Write code here to group the subway data by a variable of your choice, then
### either print out the mean ridership within each group or create a plot.
pandas有一个名为合并-merge的运算,它可以将两个表格合并为一个表格,从而创建一个含有这两个表格所有列的
新表格,
inner–account_key同时存在与两个表的行,
right–右侧注册表中的行,即使在提交表中没有相应条目,也会被保留
left–相反,即使左侧表中的行在右侧表中没有对应行,它会保留
outer–两个表的所有行都会被保留
DataFrame 也像 Pandas Series 一样拥有 plot() 方法。如果 df 是 DataFrame,那么 df.plot() 将生成线条图,其中不同颜色的每条线代表 DataFrame 中的一个变量。这种方法能使你方便快速地查看数据,特别是对于小型 DataFrame 而言,但是对于更复杂的图形,你通常会希望直接使用 matplotlib。
在接下来的测试题中,根据纽约地铁数据创建你的图形,展现数据有趣的一面。例如,你可能会创建:
雨天和晴天地铁客流量直方图。
以经纬度作为 x 和 y 轴、客流量作为气泡大小的地铁站散点图。
如果你选择此选项,你可能希望对 groupby() 使用 as_index=False 参数。以下测试题中有示例代码。
以地铁客流量作为一个轴、降雨量或温度作为另一个轴的散点图。
你已经处理过一维和二维数据,你可能想知道如何处理三维以上的数据。
NumPy 的 3D 数据
NumPy 数组可以具有任意多的维度。就像你可以从列表中创建 1D 数组,从列表的列表中创建 2D 数组一样,你可以从列表的列表的列表中创建 3D 数组,以此类推。例如,以下代码将创建 3D 数组:
a = np.array([
[[‘A1a’, ‘A1b’, A1c’], [‘A2a’, ‘A2b’, ‘A2c’]],
[[‘B1a’, ‘B1b’, ‘B1c’], [‘B2a’, ‘B2b’, ‘B2c’]]
])
Pandas 的 3D 数据
Pandas 有一个叫作 Panel 的数据结构,类似 DataFrame 或 Series,只不过用于 3D 数据。如果你有兴趣,可以在这里了解 Panel。
import numpy as np
a = np.array([[['A1a', 'A1b', A1c'], ['A2a', 'A2b', 'A2c']],[['B1a', 'B1b', 'B1c'], ['B2a', 'B2b', 'B2c']]])
print(a)
File "", line 2
a = np.array([[['A1a', 'A1b', A1c'], ['A2a', 'A2b', 'A2c']],[['B1a', 'B1b', 'B1c'], ['B2a', 'B2b', 'B2c']]])
^
SyntaxError: invalid syntax