1. 去重及替换
1.1 .duplicated()
方法,判断是否重复
可以通过布尔判断,得到不重复的值(类比之前的.is_unique()
方法)
s = pd.Series([1,1,1,2,2,3,4,5])
print(s.duplicated())
print(s[s.duplicated() == False])
–> 输出的结果为:
0 False
1 True
2 True
3 False
4 True
5 False
6 False
7 False
dtype: bool
0 1
3 2
5 3
6 4
7 5
dtype:
1.2 drop.duplicates()
移除重复
★★★★★ inplace
参数:是否替换原值,默认False
(也就是不改变原来数据的值)
这里特别容易出错,有 两种方式 可以改变原来的数据,一种是通过inplace参数,还有一种是重新赋值(这里容易搞混)
s.drop_duplicates(inplace = True)
print(s)
s = s.drop_duplicates()
print(s)
–> 输出的结果为:(注意上面的操作,一个是赋值了,一个是没有赋值,在使用inplace=True
时候,不用赋值)
0 1
3 2
5 3
6 4
7 5
dtype: int64
0 1
3 2
5 3
6 4
7 5
dtype:
Dataframe中使用duplicated(上面对于Series的操作都适用于DataFrame,因为里面的的任意一列单独拿出来都是一个Series)
df = pd.DataFrame({'key1':['a','a',3,4,5],
'key2':['a','a','b','b','c']})
print(df.duplicated())
print(df['key2'].duplicated())
print(df['key2'].drop_duplicates())
–> 输出的结果为:
0 False
1 True
2 False
3 False
4 False
dtype: bool
0 False
1 True
2 False
3 True
4 False
Name: key2, dtype: bool
0 a
2 b
4 c
Name: key2, dtype: object
★★★★★1.3 替换
.replace()
方法 在进行DataFrame数据微调的时候经常使用(可以和之前的删除数据del 列名
进行类比)
可一次性替换一个值或多个值,也可传入列表或字典
s = pd.Series(list('ascaazsd'))
print(s.replace('a', np.nan))
print(s.replace(['a','s'] ,np.nan))
print(s.replace({'a':'hello world!','s':123}))
–> 输出的结果为:
0 NaN
1 s
2 c
3 NaN
4 NaN
5 z
6 s
7 d
dtype: object
0 NaN
1 NaN
2 c
3 NaN
4 NaN
5 z
6 NaN
7 d
dtype: object
0 hello world!
1 123
2 c
3 hello world!
4 hello world!
5 z
6 123
7 d
dtype: object
2. 数据分组
分组统计 - groupby功能
df.groupby
(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
Dataframe在行(axis=0)或列(axis=1)上进行分组,将一个函数应用到各个分组并产生一个新值,然后函数执行结果被合并到最终的结果对象中。
2.1 groupby对象
1) 直接分组得到一个groupby
对象(可迭代),是一个中间数据,没有进行计算
df = pd.DataFrame({'X' : ['A', 'B', 'A', 'B'], 'Y' : [1, 4, 3, 2]})
print(df)
print(df.groupby('X'))
print(type(df.groupby('X'))
–> 输出的结果为:
0 A 1
1 B 4
2 A 3
3 B 2
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x10C1F890>
<class 'pandas.core.groupby.generic.DataFrameGroupBy'>
2) 迭代的对象组成list
列表就可以进行索引、也可以对列表进行遍历循环输出
print(list(df.groupby('X')))
print(list(df.groupby('X'))[0])
for n,g in df.groupby('X'):
print(n)
print(g)
print('——————')
–> 输出的结果为:(从结果可以看出,迭代器里面的元素是以元祖的方式存放的,第一个是组名(分组后的标签名),第二个就是组内的数据DataFrame)
[('A', X Y
0 A 1
2 A 3), ('B', X Y
1 B 4
3 B 2)]
('A', X Y
0 A 1
2 A 3)
A
X Y
0 A 1
2 A 3
——————
B
X Y
1 B 4
3 B 2
3) .get_group()
提取分组后的组内数据DataFrame
print(df.groupby(['X']).get_group('A'),'\n')
print(df.groupby(['X']).get_group('B'),'\n')
–> 输出的结果为:
0 A 1
2 A 3
X Y
1 B 4
3 B 2
4) .groups
:将分组后的groups转为dict
,可以字典索引方法来查看groups里的元素
grouped = df.groupby(['X'])
print(grouped.groups)
print(grouped.groups['A'])
print(grouped.groups['A'].values)
–> 输出的结果为:(注意这里存在着pandas的版本问题,只是数据显示的问题,可以通过.values
方式转换)
#老版本会输出下面内容
{'B': [1, 3], 'A': [0, 2]}
[0, 2]
#新版本会输出下面内容(pandas版本1.0.1)
{'A': Int64Index([0, 2], dtype='int64'), 'B': Int64Index([1, 3], dtype='int64')}
Int64Index([0, 2], dtype='int64')
#添加.values的方式就可以获得和原来一样的数据类型
[0 2]
5) .size()
:查看分组后的长度
sz = grouped.size()
print(sz,type(sz))
–> 输出的结果为:(这一步的输出是基于上一步分组后的结果)
X
A 2
B 2
dtype: int64 <class 'pandas.core.series.Series'>
2.2 按照多列进行分组
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
'C' : np.random.randn(8),
'D' : np.random.randn(8)})
grouped = df.groupby(['A','B']).groups
print(df)
print(grouped)
print(grouped[('foo', 'three')])
–> 输出的结果为:
0 foo one -0.668695 0.247781
1 bar one -0.125374 2.259134
2 foo two -0.112052 1.618603
3 bar three -0.098986 0.150488
4 foo two 0.912286 -1.260029
5 bar two 1.096757 -0.571223
6 foo one -0.090907 -1.671482
7 foo three 0.088176 -0.292702
#老版本输出结果
{('bar', 'two'): [5], ('foo', 'two'): [2, 4], ('bar', 'one'): [1], ('foo', 'three'): [7], ('bar', 'three'): [3], ('foo', 'one'): [0, 6]}
[7]
#新版本输出如下
{('bar', 'one'): Int64Index([1], dtype='int64'), ('bar', 'three'): Int64Index([3], dtype='int64'), ('bar', 'two'): Int64Index([5], dtype='int64'), ('foo', 'one'): Int64Index([0, 6], dtype='int64'), ('foo', 'three'): Int64Index([7], dtype='int64'), ('foo', 'two'): Int64Index([2, 4], dtype='int64')}
Int64Index([7], dtype='int64')
2.3 按照值类型分列
其他轴上的分组 ,通过改变axis
的参数完成
df = pd.DataFrame({'data1':np.random.rand(2),
'data2':np.random.rand(2),
'key1':['a','b'],
'key2':['one','two']})
print(df)
print(df.dtypes)
for n,p in df.groupby(df.dtypes, axis=1):
print(n)
print(p)
print('——————')
–> 输出的结果为:
0 0.418399 0.540522 a one
1 0.903899 0.960402 b two
data1 float64
data2 float64
key1 object
key2 object
dtype: object
float64
data1 data2
0 0.418399 0.540522
1 0.903899 0.960402
——————
object
key1 key2
0 a one
1
2.4 通过字典或者Series分组
mapping中,a、b列对应的为one,c、d列对应的为two,以字典来分组(e的存在不影响)
df = pd.DataFrame(np.arange(16).reshape(4,4),
columns = ['a','b','c','d'])
print(df)
mapping = {'a':'one','b':'one','c':'two','d':'two','e':'three'}
by_column = df.groupby(mapping, axis = 1)
print(by_column.sum())
–> 输出的结果为:(要想分组之后产生我们需要的数据,需要添加一些方法,比如这里的.sum()
汇总)
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
3 12 13 14 15
one two
0 1 5
1 9 13
2 17 21
3 25 29
s中,index中a、b对应的为one,c、d对应的为two,以Series来分组
s = pd.Series(mapping)
print(s,'\n')
print(s.groupby(s).count())
–> 输出的结果为:(自动按照Series的值进行分组,选择以.count()
方式统计)
a one
b one
c two
d two
e three
dtype: object
one 2
three 1
two 2
dtype:
2.5 通过函数分组
比如这里按照len
(字母长度)分组
df = pd.DataFrame(np.arange(16).reshape(4,4),
columns = ['a','b','c','d'],
index = ['abc','bcd','aa','b'])
print(df,'\n')
print(df.groupby(len).sum())
–> 输出的结果为:(这里的len默认是对标签index使用的,选择以.sum()
进行统计)
0 1 2 3
bcd 4 5 6 7
aa 8 9 10 11
b 12 13 14 15
a b c d
1 12 13 14 15
2 8 9 10 11
3 4 6 8 10
3. 分组统计方法
上面的示例中已经使用到了一些分组统计的方法,比如.sum()
,.count()
等方法,下面介绍常用的统计方法
3.1 常用的统计方法
唯一索引用.groupby(level=0)
,将同一个index的分为一组
s = pd.Series([1, 2, 3, 10, 20, 30], index = [1, 2, 3, 1, 2, 3])
grouped = s.groupby(level=0)
print(grouped,'\n')
print(s)
–> 输出的结果为:(第一个输出就是groupby
(迭代) 对象)
<pandas.core.groupby.generic.SeriesGroupBy object at 0x115276F0>
1 1
2 2
3 3
1 10
2 20
3 30
dtype:
1) 非NaN的第一个值
print(grouped.first(),'→ first:非NaN的第一个值')
–> 输出的结果为:
1 1
2 2
3 3
dtype:
2) 非NaN的最后一个值
print(grouped.last(),'→ last:非NaN的最后一个值\n')
–> 输出的结果为:
1 10
2 20
3 30
dtype:
3) 非NaN的和
print(grouped.sum(),'→ sum:非NaN的和\n')
–> 输出的结果为:
1 11
2 22
3 33
dtype: int64 → sum:非NaN的和
4) 非NaN的平均值
print(grouped.mean(),'→ mean:非NaN的平均值\n')
–> 输出的结果为:
1 5.5
2 11.0
3 16.5
dtype:
5) 非NaN的算术中位数
print(grouped.median(),'→ median:非NaN的算术中位数\n')
–> 输出的结果为:
1 5.5
2 11.0
3 16.5
dtype:
6) 非NaN的值
print(grouped.count(),'→ count:非NaN的值\n')
–> 输出的结果为:
1 2
2 2
3 2
dtype:
7)非NaN的最小值、最大值
print(grouped.min(),'→ min、max:非NaN的最小值、最大值\n')
–> 输出的结果为:
1 1
2 2
3 3
dtype: int64 → min、max:非NaN的最小值、最大值
8) 非NaN的标准差和方差
print(grouped.std(),'→ std,var:非NaN的标准差和方差\n')
–> 输出的结果为:
1 6.363961
2 12.727922
3 19.091883
dtype:
9) 非NaN的积
print(grouped.prod(),'→ prod:非NaN的积\n'
–> 输出的结果为:
1 10
2 40
3 90
dtype:
3.2 多函数计算:agg()
★★★★★函数写法可以用str
,或者np.
方法;可以通过list
,dict
传入,当用dict
时,key
名为columns
df = pd.DataFrame({'a':[1,1,2,2],
'b':np.random.rand(4),
'c':np.random.rand(4),
'd':np.random.rand(4),})
print(df)
print(df.groupby('a').agg(['mean',np.sum]))
print(df.groupby('a')['b'].agg({'result1':np.mean,
'result2':np.sum}))
–> 输出的结果为:
0 1 0.093550 0.988628 0.481633
1 1 0.389688 0.068360 0.371444
2 2 0.412428 0.232056 0.740094
3 2 0.320511 0.393042 0.891658
b c d
mean sum mean sum mean sum
a
1 0.241619 0.483238 0.528494 1.056988 0.426539 0.853077
2 0.366470 0.732939 0.312549 0.625099 0.815876 1.631752
result1 result2
a
1 0.241619 0.483238
2 0.366470 0.732939
3.3 分组转换及一般性
“拆分-应用-合并” ,主要是merge
/ transform
/ apply
方法的使用
1) 数据分组转换
df = pd.DataFrame({'data1':np.random.rand(5),
'data2':np.random.rand(5),
'key1':list('aabba'),
'key2':['one','two','one','two','one']})
print(df)
–> 输出的结果为:
0 0.241148 0.215440 a one
1 0.554391 0.765252 a two
2 0.920091 0.216041 b one
3 0.201641 0.869712 b two
4 0.961804 0.430776
按照key1分组求均值,进行合并
k_mean = df.groupby('key1').mean()
print(k_mean)
print(pd.merge(df,k_mean,left_on='key1',right_index=True).add_prefix('mean_'))
–> 输出的结果为:(通过分组、合并,得到一个包含均值的Dataframe,其中.add_prefix('mean_')
:添加前缀)
0.585781 0.470489
b 0.560866 0.542877
mean_data1_x mean_data2_x mean_key1 mean_key2 mean_data1_y mean_data2_y
0 0.241148 0.215440 a one 0.585781 0.470489
1 0.554391 0.765252 a two 0.585781 0.470489
4 0.961804 0.430776 a one 0.585781 0.470489
2 0.920091 0.216041 b one 0.560866 0.542877
3 0.201641 0.869712 b two 0.560866 0.542877
按照key2分组求均值,字符串不能进行计算
print(df.groupby('key2').mean())
print(df.groupby('key2').transform(np.mean))
–> 输出的结果为:(data1、data2每个位置元素取对应分组列的均值,和原数据的标签index
相对应)
0.209669 0.381341
two 0.206753 0.898320
data1 data2
0 0.209669 0.381341
1 0.206753 0.898320
2 0.209669 0.381341
3 0.206753 0.898320
4 0.209669 0.381341
2)一般化Groupby方法:apply(函数)
★★★★★属于进阶的方法,一般可以节省很多代码量完成复杂的工作,但是掌握有一定的难度,apply后面多函数(常见就是lambda表达式),调用其功能
比如:直接查看描述分组后的统计量(.describe()
方法)
df = pd.DataFrame({'data1':np.random.rand(5),
'data2':np.random.rand(5),
'key1':list('aabba'),
'key2':['one','two','one','two','one']})
print(df)
print(df.groupby('key1').apply(lambda x: x.describe()))
–> 输出的结果为:
0 0.873000 0.751742 a one
1 0.934280 0.386892 a two
2 0.847525 0.779258 b one
3 0.513672 0.467257 b two
4 0.489208 0.822993 a one
data1 data2
key1
a count 3.000000 3.000000
mean 0.357638 0.553313
std 0.225001 0.407336
min 0.101986 0.185609
25% 0.273682 0.334385
50% 0.445378 0.483161
75% 0.485464 0.737165
max 0.525550 0.991168
b count 2.000000 2.000000
mean 0.544131 0.745138
std 0.525377 0.016776
min 0.172633 0.733276
25% 0.358382 0.739207
50% 0.544131 0.745138
75% 0.729879 0.751070
max 0.915628 0.757001
除使用lambda函数外,还可以自定义函数,如下
def f_df1(d,n):
return(d.sort_index()[:n])
#f_df1函数:返回排序后的前n行数据
def f_df2(d,k1):
return(d[k1])
# f_df2函数:返回分组后表的k1列,结果为Series,层次化索引
print(df.groupby('key1').apply(f_df1,2))
print(df.groupby('key1').apply(f_df2,'data2'))
print(type(df.groupby('key1').apply(f_df2,'data2')))
–> 输出的结果为:
0 0.373092 0.473234 a one
1 0.777516 0.784485 a two
b 2 0.214563 0.007377 b one
3 0.452728 0.741134 b two
key1
a 0 0.473234
1 0.784485
4 0.626037
b 2 0.007377
3 0.741134
Name: data2, dtype: float64
<class 'pandas.core.series.Series'>