写在前面
pandas在数据处理分析上往往占据主要地位,其中实现了很多功能函数,可以使数据分析更加方便快捷,这里只是pandas中比较基础的总结,更加复杂高级的用法还需要参考官方文档。pandas中两个常用的对象是Series和DataFrame。
Series对象
series是pandas中最基本的对象,并定义了和numpy.ndarray的接口,可以用numpy的函数直接操作series对象。series由两部分组成:index和values,index可看作一个索引,在创建series时可以指定index,若不指定,则会创建一个默认的index,values是保存元素值得narray数组。
s = pd.Series([1,2,3,4,5], index=["a","b","c","d","e"])
print s.index
print s.values
##
Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')
[1 2 3 4 5]
series支持两种索引,一是如numpy.narray的索引类型,第二是这里的index索引。
print s[1]
print s["a"]
#
2
1
另外series也支持两种切片类型,两者的区别是使用数字索引时和numpy.narray的一样,但使用这里的index切片时,会包括起点和终点值。
print s[1:3]
print s["b":"d"]
##
b 2
c 3
dtype: int64
b 2
c 3
d 4
dtype: int64
series对象之间可以进行运算,在进行运算时会将元素对齐,如果长度不一样时,多余的部分结果时NaN,该值时浮点数中一个特殊值。
s2 = pd.Series([1,2,3,4,5,6], index=["a","b","c","d","e","f"])
s+s2
#
a 2.0
b 4.0
c 6.0
d 8.0
e 10.0
f NaN
dtype: float64
DataFrame对象
DataFrame是pandas中最常用的数据类型,同时提供了许多将其它数据结构转化为DataFrame的函数,并且提供了从许多不同类型文件直接读取数据并以DataFrame对象返回。DataFrame对象的基本结构如下图:
DataFrame的同一列必须是同一类型数据,不同列可以是不同类型数据。通过[]+列索引来获取某一列,这是获取的类型是Series类型,当[]+列索引列表时将得到一个DataFrame类型。使用.loc[]将获得数据的某一行,返回的是Series类型,由于各列类型不一样,在获取时将会转换成通用的object类型,同样,为一个列表时将会时一个DataFrame类型。values属性将会把DataFrame转换成一个数组,由于数据类型不一样,所以最终仍时一个object类型的数组。
DataFrame的构造
DataFrame可以通过三个参数来构造,data是数据,index行索引,columns列索引。data可以是二维数组、字典,当为字典是,key是行索引,value可以是一维数组、列表或者Series对象。
df1 = pd.DataFrame(np.random.randint(0,10,(4,2)),index=["a","b","c","d"], columns=["A","B"])
df2 = pd.DataFrame({"a":[1,2,3,4],"b":[5,6,7,8],index=["A","B","C","D"]})
arr = np.array([("i1",1),("i2",2),("i3",3),("i4",4)],dtype=[("name","10s"),("count",int)])
df3 = pd.DataFrame(arr)
此外还可以调用以 from_开头的类方法,将特定格式的数椐转换成 DataFrame对象。from_dict()将字典转换为DataFrame对象,其 orient参数可以指定字典键对应的方向,默认值为”columns”,表示把字典的键转换为列索引,即字典中的每个值与一列对应。而 orient参数为”index”时,字典中的每个值与一行对应。当字典为嵌套字典,即字典的值为字典时,另外一个轴的索引值由第二层字典屮的键决定。
dictl = {"a":[1, 2, 3], "b":[4, 5, 6]}
dict2 = {"a":{"A":1,"B":2}, "b":{"A":3, "C":4}}
dfl = pd.DataFrame.from_dict(dictl, orient="index")
df2 = pd.DataFrame.from_dict(dictl, orient="columns")
df3 = pd.DataFrame.from_dict(dict2, orient="index")
df4 = pd.DataFrame.from_dict(dict2, orient="columns")
###############################################################
from_items()将key-value序列转换为DataFrame对象,其中value是一维数据的列表、数组或Series对象,当orient指定为index时,需要指定columns索引。若不指定将产生错误。
df1 = pd.DataFrame.from_items(items,orient="index",columns=["A","B","C"])
A B C
a 1 2 3
b 4 5 6
#######################################
df2 = pd.DataFrame.from_items(items,orient="columns")
a b
0 1 4
1 2 5
2 3 6
将DataFrame转换为其它格式数据
to_dict将DataFrame对象转化为字典,其orient参数决定字典的元素的类型:
# records指定字典类型
df2.to_dict(orient="records")
[{'a': 1, 'b': 4}, {'a': 2, 'b': 5}, {'a': 3, 'b': 6}]
# list指定列表类型
df2.to_dict(orient="list")
{'a': [1L, 2L, 3L], 'b': [4L, 5L, 6L]}
# dict指定嵌套字典类型
df2.to_dict(orient="dict")
{'a': {0: 1L, 1: 2L, 2: 3L}, 'b': {0: 4L, 1: 5L, 2: 6L}}
to_records()将DataFrame对象转化成结构数组,若index参数为True(默认),则返回的数据包含行索引数据。
df2.to_records()
rec.array([(0, 1, 4), (1, 2, 5), (2, 3, 6)],
dtype=[(u'index', '<i8'), (u'a', '<i8'), (u'b', '<i8')])
df2.to_records(index=False)
rec.array([(1, 4), (2, 5), (3, 6)],
dtype=[(u'a', '<i8'), (u'b', '<i8')])
Index对象
Index对象保存的是索引标签数据,它可以快速的找到标签对应的整数下标,可看成字典类型,通过Index.values属性可获得保存索引的数组,其元素类型是object,Index是只读类型,一旦创建就无法修改其元素。
df2.columns
Index([u'a', u'b'], dtype='object')
df2.columns.values
array(['a', 'b'], dtype=object)
Index对象可以通过get_loc()和get_indexer()来获取索引相应的整数下标,前者是获取一个,后者是获取一组,当Index中不存在该索引时,则返回-1。
df2.columns.get_loc("a")
0
df2.columns.get_indexer(["a","b","c"])
array([ 0, 1, -1])
MultiIndex对象
MultiIndex继承于Index,是多级索引的对象,通过[]获取单个元素,返回的结果依然是一个多级标签,同样可以用get_loc()和get_indexer()来获取单个和多个标签的下标。我们再次拿上面那副图作为例子:
假设这幅图的DataFrame对象为df,则可以验证下面的:
mindex = df.index
mindex[1]
('0-10','Slope')
mindex.get_loc(('0-10','Slope'))
1
mindex.get_indexer([('10-30','Top'),('0-10','Depression'),'nothing'])
[5 0 -1]
获取每一级的索引可以用level属性,level返回的是一个多维数组,level[0]是顶级所以,level[1]是下一级索引。
mindex.level[0]
Index([u'0-10',u'10-30'], dtype='object', name=u'depth')
mindex.level[1]
Index([u'Depression',u'Slope',u'Top'],dtype='object',name=u'Contour')
当把一个元组列表传递给Index对象时,将自动创建MutliIndex对象,若希望创建的是元组Index对象,则设置tupleize_cols为False。
pd.Index([("A", "x"), ("A", "y"), ("B", "x"), ("B", "y")], name=["classl", "class2"])
MultiIndex(levels=[[u'A', u'B'], [u'x', u'y']],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
names=[u'classl', u'class2'])
此外可以使用以from_开头的Multiindex类方法从特定的数据结构创建Multiindex对象。例如 from_airays()方法从多个数组创建Multiindex对象:
classl = ["A", "A", "B", "B"]
class2 = ["x", "y", "x", "y"]
pd.MultiIndex.from_arrays([classl, class2], names=["classl", "class2"])
MultiIndex(levels=[[u'A', u'B'], [u'x', u'y']],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
names=[u'classl', u'class2'])
from_product()则从多个集合的笛卡尔积创建 Multiindex对象。下而的程序将所创建的Multiindex对象传递给index和 columns参数,所创建的DataFrame对象的行和列使用同一个多级索引对象。
下标存取
[]操作符
[]支持如下几种下标对象:
- 单个索引标签,获取标签对应的列,返回一个Series对象;
- 多个索引标签,获取各个标签对应的列,返回一个DataFrame对象;
- 整数切片,返回整数下标对应的行;
- 标签切片,返回包含终值;
- 布尔数组,返回bool数组中为True对应的行;
- 布尔DataFrame,把DataFrame中为Fasle的元素设置为NaN。
np.random.seed(42)
df = pd.DataFrame(np.random.randint(0,10,(5,3)), index=["r1","r2","r3","r4","r5"], columns=["c1","c2","c3"])
c1 c2 c3
r1 6 3 7
r2 4 6 9
r3 2 6 7
r4 4 3 7
r5 7 2 5
df[2:4] df["r2":"r4"]
c1 c2 c3 c1 c2 c3
r2 4 6 9 r3 2 6 7
r3 2 6 7 r4 4 3 7
r4 4 3 7
df > 2 df[df>2]
c1 c2 c3 c1 c2 c3
r1 True True True r1 6.0 3.0 7
r2 True True True r2 4.0 6.0 9
r3 False True True r3 NaN 6.0 7
r4 True True True r4 4.0 3.0 7
r5 True False True r5 7.0 NaN 5
.loc[]和.iloc[]存取器
.loc[]的下标对象是一个元组,其中的两个元素分别与DataFrame的两个轴相对应。若下标不是元组,则该下标对应第0 轴,对应第1轴。每个轴的下标对象都支持单个标签、标签列表、标签切片以及布尔数组。
df.loc[["r2","r3"]] df.loc[["r2","r3"],["c1","c2"]]
c1 c2 c3 c1 c2
r2 4 6 9 r2 4 6
r3 2 6 7 r3 2 6
iloc[]和loc[]相似,只不过iloc是用整数下标存取。ix[]可以把标签和整数混用:
df.ix[2:4,["c1","c3"]]
c1 c3
r3 2 7
r4 4 7
.at[]和.iat[]存取单个元素
.at[]分别传入行列的标签,获取该行列的元素,.iat[]传入的是整数下标,此外,get_value()与.at[]类似,但效率要比.at[]快。
过滤筛选
在对DataFrame进行条件过滤时,可以使用bool数组进行过滤,除此,query()方法可以实现相同的功能,query()接受一个字符串条件:
df.query("c1>2 & c1<7")
c1 c2 c3
r1 6 3 7
r2 4 6 9
r4 4 3 7
有时候,需要用到全局或局部的变量进行过滤,则在变量名前加@:
low = 2
hi = 7
df.query("c1>@low & c1<@hi")
c1 c2 c3
r1 6 3 7
r2 4 6 9
r4 4 3 7
文件读写
pandas提供了很多与文件读写的函数,方便从文件中读取内容,返回DataFrame对象,同时能将DataFrame对象存储在文件中。pandas能方便与下面格式的文件交互:
这些函数的参数很多,所以这里不进行详细总结,可以参看官方文档。
数值运算
Series和DataFrame对象都支持Numpy的接口,因此可以使用Numpy提供的ufunc函数,而且也提供了各种运算方法,比如mean()、std()、max()等,这些函数和numpy中类似,都有三个常用参数:axis指定运算轴;level指定运算对应的索引级别;skipna是否跳过NaN。此外Pandas还提供了 add()、 sub()、 mul()、 div()、 mod()等二元运算符对应的函数。这些函数可以通过axis、 level和 fill_value等参数控制其运算行为。
字符串处理
pandas提供了大量的字符串处理函数,正由于函数数量过大,所以pandas提供了str(类似命名空间)来包装这些函数,例如将字符转换成大写:
se = pd.Series(["a","b","c"])
se.str.upper()
0 A
1 B
2 C
dtype: object
Python中包含两种字符串:字节字符串和Unicode字符串。通 过 str.decode()可以将字节字符串按照指定的编码解码为Unicode字符串。例如在UTF-8编码屮,一个汉字占用三个字符,因此下面的s_utf8 中的字符串长度分别为6、9、12。当调用str.decode()将其转换为Unicode字符串的序列之后,其各个元素的长度为实际的文字个数。 str.encode()可以把Unicode字符串按照指定的编码转换为字节字符串,在常用的汉字编码GB2312中,一个汉字占州两个字节,因此s_gb2312的元素长度分别为4、 6、 8。
s_utf8 = pd.Series([b"成都",b"成都市",b"四川成都"])
s_unicode = s_utf8.str.decode("utf-8")
s_gb2312 = s_unicode.str.encode("gb2312")
print s_utf8.str.len()
print s_unicode.str.len()
print s_gb2312.str.len()
0 6
1 9
2 12
dtype: int64
0 2
1 3
2 4
dtype: int64
0 4
1 6
2 8
dtype: int64
可以对str使用切片或下标,相当于对Series的每个元素都使用下标或切片:
s_unicode.str[:2]
0 成都
1 成都
2 四川
dtype: object
字符串序列和字符串一样,支持加法和乘法运算:
s_abc = pd.Series([u'a',u'b',u'c'])
s_unicode+u'-'+s_abc*2
0 成都-aa
1 成都市-bb
2 四川成都-cc
dtype: object
cat()函数能够连接两个字符串序列对象:
s_unicode.str.cat(s_abc,sep='_')
0 成都_a
1 成都市_b
2 四川成都_c
dtype: object
split()能够对字符串序列的每个元素进行分割,而join()函数能将一个字符串序列对象的元素连接起来:
s = pd.Series(['a|bc|de','x|xyz|yz'])
s_list = s.str.split("|")
0 [a, bc, de]
1 [x, xyz, yz]
dtype: object
s_list.str.join('*')
0 a*bc*de
1 x*xyz*yz
dtype: object
对于这种字符串序列对象,[]将会对每个字符序列的列表元素进行相应的操作:
s_list.str[1]
0 bc
1 xyz
dtype: object
还可以转换为嵌套列表,然后转换为DataFrame对象:
pd.DataFrame(s_list.tolist(), columns=["A","B","C"])
A B C
0 a bc de
1 x xyz yz
在字符串处理时,正则表达式时一个强有力的工具,而pandas也提供了如此的方法str.extract(),返回的时DataFrame对象,该对象若不指定组时,得到的DataFrame对象将会自动进行标签名设置,若指定,则返回的时带标签的DataFrame对象。
s.str.extract(r"(\w+)\|(\w+)\|(\w+)")
0 1 2
0 a bc de
1 x xyz yz
s.str.extract(r"(?P<A>\w+)\|(?P<B>\w+)|")
A B
0 a bc
1 x xyz
时间序列
pandas提供了时间点、时间段、时间间隔三种时间类型,封装在Timestamp对象内,该对象继承与python内置的datetime类,表示时间轴上的一个时间点,通过Timestamp.now()可以获取当前时间,该时间是不带时区信息的,通过tz_localize()将时间转化为带时区的时间对象,带时区时间对象可以通过tz_convert()转换为其它时区时间。
now = pd.Timestamp.now()
now_shanghai = now.tz_localize("Asia/Shanghai")
now_tokyo = now_shanghai.tz_convert("Asia/Tokyo")
print now
print now_shanghai
print now_tokyo
2017-12-18 10:59:30.939000
2017-12-18 10:59:30.939000+08:00
2017-12-18 11:59:30.939000+09:00
带时区时间的不同对象可以比较,但不带时区时间和带时区时间对象是无法比较的。所有的时区名在pytz模块的common_timezones()中规定。
now_shanghai == now_tokyo
True
Period对象表示一个标准的时间段,例如某年、某月等,时间段的长短由freq参数决定。
now_day = pd.Period.now(freq="D")
now_time = pd.Period.now(freq="H")
print now_day
print now_time
2017-12-18
2017-12-18 11:00
freq属性是一个描述时间段的字符串,其可选值可以通过下面的代码获得:
from pandas.tseries import frequencies
frequencies._period_code_map.keys()
frequencies._period_alias_dictionary()
对于周期为年度和星期的时间段,可以通过freq指定开始的时间。例如”W”表示以星期天开始的星期时间段,而”W-MON”则表示以星期一开始的星期时间段:
now_week_sun = pd.Period.now(freq="W")
now_week_mon = pd.Period.now(freq="W-MON")
print now_week_sun
print now_week_mon
2017-12-18/2017-12-24
2017-12-12/2017-12-18
时间段的起点和终点可以通过start_time和end_time获取,这两个属性都是Timestamp对象。to_period()函数可以将时间点对象转换为包含该时间点的时间段,该时间段不包含时区信息。
now_shanghai.to_period("H")
Period('2017-12-18 10:00', 'H')
Timestamp和Period对象可以其属性获取年月日。将两个时间点相减便得到表示时间间隔的Timedelta对象。
fest_day = pd.Timestamp("2018-1-1")
fest_day - now
Timedelta('13 days 13:00:29.061000')
时间间隔依然由相关属性来获取间隔的天数、分秒等。
NaN相关的函数
NaN是一个浮点数的特殊值,无法在整数中使用,所以,当整数数列中出现NaN,那么整数将转化为浮点数。DataFrame的where函数会将False对象的元素设置为NaN。
df = pd.DataFrame(np.random.randint(0,10,(3,3)), columns=list("ABC"))
A B C
0 1 8 4
1 1 3 6
2 5 3 9
df_nan = df.where(df>2)
A B C
0 NaN 8 4
1 NaN 3 6
2 5.0 3 9
isnull()和notnull()函数判断元素是否为NaN,两者的结果都是bool类型的DataFrame,两者的bool类型相反,但是实质是一样的。但notnull()会少创建一个临时对象,相对效率较高。
df_nan.isnull()
A B C
0 True False False
1 True False False
2 False False False
df_nan.notnull()
A B C
0 False True True
1 False True True
2 True True True
count()返回每列或每行的非NaN的元素个数,默认为列,即axis=0:
df_nan.count()
A 1
B 3
C 3
dtype: int64
df_nan.count(axis=1)
0 2
1 2
2 3
dtype: int64
在实际应用时最干脆的方法是对NaN的行列直接删除,这适合于包含NaN的行列在总数中占的比例很小的时候,通过thresh可以控制对NaN的筛选,只删除大于等于thresh的行。
df_nan.dropna()
A B C
2 5.0 3 9
df_nan.dropna(thresh=1)
A B C
0 NaN 8 4
1 NaN 3 6
2 5.0 3 9
有时候不能直接删除NaN的行列,这时候需要对其填充,ffill()使用之前的数据填充;bfill()使用之后的数据填充;interpolate()使用前后插值填充。interpolate()默认使用等距线性插值,可以通过其method参数指定插值算法。
s = pd.Series([3,np.NaN,7], index=[0,8,9])
s.interpolate()
0 3.0
8 5.0
9 7.0
dtype: float64
s.interpolate(method="index")
0 3.000000
8 6.555556
9 7.000000
dtype: float64
interpolate()默认使用前后两个值得平均值,当method=”index”时,根据index来进行插值,由于8和9比较接近,所以插值后离7比较近。此外,还可以用fillna()函数对不同列进行不同值填充,参数是以字典形式传入。
df_nan.fillna({"A":3.0})
A B C
0 3.0 8 4
1 3.0 3 6
2 5.0 3 9
各种聚合方法的skipna参数默认为True, 因此计兑时将忽略NaN 元素,注意每行或每列是单独运算的。如果需要忽略包含NaN 的整行,需要先调用dropna()。若 将 skipna参数设置为False, 则包含NaN 的行或列的运算结果为NaN。
df_nan.sum()
A 5.0
B 14.0
C 19.0
dtype: float64
df_nan.sum(skipna=False)
A NaN
B 14.0
C 19.0
dtype: float64
df_nan.dropna().sum()
A 5.0
B 3.0
C 9.0
dtype: float64
df.combine_first(other)使用other填充df中的NaN元素。它 将 df中的NaN元素替换为other中对应标签的元素。
DataFrame增添删除
DataFrame同时提供了对DataFrame对象得增删该查函数,这些函数包括:
增删行列
DataFrame可以看作是Series组成的字典,通过DataFrame[colname]=values可以添加新的列,如果需要从已有的列通过计算来得到新的列,则可以通过eval函数。
df = pd.DataFrame(np.random.randint(0,10,(4,4)), columns=list("ABCD"))
A B C D
0 6 9 1 9
1 4 2 6 7
2 8 8 9 2
3 0 6 7 8
df["newcol"] = df.eval("A+10")
A B C D newcol
0 6 9 1 9 16
1 4 2 6 7 14
2 8 8 9 2 18
3 0 6 7 8 10
assign()方法添加关键字指定的新列,其它内容保持不变。
df.assign(newcol2=df.A+1)
A B C D newcol newcol2
0 6 9 1 9 16 7
1 4 2 6 7 14 5
2 8 8 9 2 18 9
3 0 6 7 8 10 1
append()方法用于添加行,它没有inplace参数,只能返冋一个全新对象。由于每次调用append()都会复制所有的数据,因此在循环屮使用append()添加数据会极大地降低程序的运总速度。可以使用一个列表缓存所有的分块数据,然后调用concat()将所有这些数据沿着指定轴拼贴到一起。
def rand_dataframe(n):
columns=["A","B","C"]
for i in range(n):
nrow = np.random.randint(10,20)
yield pd.DataFrame(np.random.randint(0,100,size=(nrow,3)), columns=columns)
df_list = list(rand_dataframe(100))
df_res1 = pd.DataFrame([])
for df in df_list:
df_res1 = df_res1.append(df)
######################################################
df_res2 = pd.concat(df_list,axis=0)
drop()函数能删除指定标签的行和列.
df = pd.DataFrame(np.random.randint(0,100,size=(10,10)), columns=list("ABCDEFGHIJ"))
df.drop(["A","B"], axis=1)
df.drop([0,1], axis=0)
reset_index()可以将索引转换为列,level指定转换的索引级别,如果只希望从索引中删除某个级别,可以设置drop参数为True。
df.reset_index()
set_index()可以将指定列转换为index,append参数为True时,为当前索引添加新的级别,为False时,将删除原先的index。stack()方法把指定级別的列索引转换为行索引,而unstack()则把行索引转换为列索引。无论是stack()还是unstack(),当所有的索引被转换到同一个轴上时,将得到一个Series对象。reorder_levels()和 swaplevel()交换指走轴的索引级别。
分组运算
所谓分组运算是指使用特定的条件将数裾分为多个分组,然后对每个分组进行运算,最后再将结果整合起来。Pandas中的分组运算由DataFrame或 Series对象的groupby()方法实现。当分组用的数据在源数据中时,可以直接通过列名指定分纟11数据。当源数据是DataFrame类型时,groupby()方法返回一DataFrameGroupBy对象。源数据为Series类型,则返SeriesGroupBy对象。
Dose Res1 Res2 Tmt Age Gender
0 50 9.90 10.00 C 60 F
1 15 0.02 0.04 D 60 F
2 25 0.63 0.80 C 50 M
df.groupby("Tmt")
<pandas.core.groupby.DataFrameGroupBy object at 0x0959FD70>
还可以使用列表传递多组分组数据给groupby():
df.groupby(["Tmt","Age"])
可以通过len()获取分组数:
print len(tmt)
2
GroupBy对象支持迭代接口,它与字典的iteritems()方法类似,每次迭代得到分组的键和数据。当使用多列数据分组时,与每个组对应的键是一个元组。
for key , df in tmt:
print "key=", key,",shape=",df.shape
key= C ,shape= (2, 6)
key= D ,shape= (1, 6)
get_group()方法可以获得与指定的分组键对应的数据:
tmt.get_group("C")
Dose Res1 Res2 Tmt Age Gender
0 50 9.90 10.0 C 60 F
2 25 0.63 0.8 C 50 M
tmt.get_group("D")
Dose Res1 Res2 Tmt Age Gender
1 15 0.02 0.04 D 60 F
对GroupBy的下标操作将获得一个只包含源数据中指定列的新GroupBy象,GroupBy类中定义了getattr() 方法,因此当获取GroupBy中未定义的属性时,将按照下
面的顺序操作:
•如果属性名是源数据对象的某列的名称,则相当于GroupBy[name], 获取针对该列的GroupBy对象。
•如果属性名是源数据对象的方法,则相当于通过apply()对每个分组调用该方法。注意Pandas中定义了转换为apply()的方法集合,只有在此集合之中的方法才会被自动转换。
通过GroupBy对象提供的agg()、transform()、filter()以及apply()等方法可以实现各种分组运算。每个方法的第一个参数都是一个回调函数,该函数对每个分组的数据进行运算并返回结果。这些方法根据回调函数的返回结果生成最终的分组运算结果。
agg()聚合
agg()对每个分组中的数据进行聚合运算。所谓聚合运算是指将一组由N个数值组成的数据转换为单个数值的运算,例如求和、平均值、中间值甚至随机取值等都是聚合运算。其回调函数接收的数据是表示每个分组中每列数据的Series对象,若回调函数不能处理Series对象,则agg()会接着尝试将整个分组的数据作为DataFmme对象传递给回调函数。回调函数对其参数进行聚合运算,将 Series对象转换为单个数值,或将 DataFrame对象转换为Series对象。agg()返冋一个DataFmme对象,其行索引为每个分组的键,而列索引为源数据的列索引。
transform()转换
transform()对每个分组中的数据进行转换运算。与agg()相同,首先尝试将表示每列的Series对象传递给回调函数,如果失败,将表示整个分组的DataFmme对象传递给回调函数。回调函数的返回结果与参数的形状相同,transform()将这些结果按照源数据的顺序合并在一起。
filter()过滤
filter()对每个分组进行条件判断。它将表示每个分组的DataFrame对象传递给回调函数,该函数返True或False, 以决定是否保留该分组。filter()的返回结果是过滤掉一些行之后的DataFmme对象,其行索引与源数据的行索引的顺序一致。
apply()
apply()是一个强大的函数,能够实现前面说的几个函数的功能,但由于太灵活,用不好的化可能会出现很大的错误,具体可百度参看详解。