Pandas非常用技巧汇总
原创致GreatChallengeHub
代码语言:javascript复制import pandas as pd
import numpy as np
import re
P1 缺失值填充
1.1 用另一列对应行的内容填充本列缺失值
代码语言:javascript复制df = pd.DataFrame({'A': [1, 2, 3, 4, 5], 'B': [1, np.nan, 3, np.nan, 5]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | 1 | 1.0 |
1 | 2 | NaN |
2 | 3 | 3.0 |
3 | 4 | NaN |
4 | 5 | 5.0 |
假设此处我们希望用A列的内容来填充B列的缺失值。
代码语言:javascript复制df['B'] = df['B'].fillna(df['A']) # 简单地使用fillna就可以
代码语言:javascript复制df
A | B | |
---|---|---|
0 | 1 | 1.0 |
1 | 2 | 2.0 |
2 | 3 | 3.0 |
3 | 4 | 4.0 |
4 | 5 | 5.0 |
注意:由于NaN的存在,B列初始的数据类型是float,如果要变成整数,使用astype转换即可。
1.2 用本列的均值来填充本列缺失值
代码语言:javascript复制df = pd.DataFrame({'A': [1, np.nan, 3, np.nan, 5]})
代码语言:javascript复制df
A | |
---|---|
0 | 1.0 |
1 | NaN |
2 | 3.0 |
3 | NaN |
4 | 5.0 |
假设此处我们希望用A列的均值来填充A列的缺失值。
代码语言:javascript复制df['A'].fillna(df['A'].mean(), inplace=True)
代码语言:javascript复制df
A | |
---|---|
0 | 1.0 |
1 | 3.0 |
2 | 3.0 |
3 | 3.0 |
4 | 5.0 |
注意:此处我们使用了 inplace=True 这个参数,它与以下命令是等同的。
代码语言:javascript复制df['A'] = df['A'].fillna(df['A'].mean()) # inplace可以直接替换,不需要再使用赋值语句
1.3 用分组均值来填充本列缺失值
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'b', 'a', 'b', 'a', 'b'], 'B': [1, np.nan, 3, 3, np.nan, 5]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1.0 |
1 | b | NaN |
2 | a | 3.0 |
3 | b | 3.0 |
4 | a | NaN |
5 | b | 5.0 |
假设此处我们希望根据A列的分组来填充B列的缺失值。 B列中1.0, 3.0, NaN属于A列中的a组(故填充均值2.0),而NaN, 3.0, 5.0属于A列中的B组(故填充均值4.0)。
代码语言:javascript复制df['B'] = df.groupby('A')['B'].transform(lambda x: x.fillna(x.mean()))
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1.0 |
1 | b | 4.0 |
2 | a | 3.0 |
3 | b | 3.0 |
4 | a | 2.0 |
5 | b | 5.0 |
transform是个非常有用的函数,它所得出的直接结果是一列数据。通常我们可以认为groupby后面跟各种aggregation函数(mean, sum, ...)后,我们会得到一个“缩水”的结果,表的行数会变成分组的个数。而groupby后面跟transform的话,表的行数会保持不变,相当于没有“缩水”。详见: https://www.jianshu.com/p/509d7b97088c
1.4 行列缺失情况统计
代码语言:javascript复制df = pd.DataFrame({'A': [1, np.nan, 3, 3, np.nan, 5],
'B': [1, np.nan, np.nan, 3, np.nan, 5],
'C': [1, np.nan, 2, 3, 4, 5]})
代码语言:javascript复制df
A | B | C | |
---|---|---|---|
0 | 1.0 | 1.0 | 1.0 |
1 | NaN | NaN | NaN |
2 | 3.0 | NaN | 2.0 |
3 | 3.0 | 3.0 | 3.0 |
4 | NaN | NaN | 4.0 |
5 | 5.0 | 5.0 | 5.0 |
假设我们分别需要按行和按列统计NaN的数量。
代码语言:javascript复制df.isnull().sum() # 按列统计
代码语言:javascript复制A 2
B 3
C 1
dtype: int64
代码语言:javascript复制df.isnull().sum(axis=1) # 按行统计
代码语言:javascript复制0 0
1 3
2 1
3 0
4 2
5 0
dtype: int64
代码语言:javascript复制df.isnull().sum().sum() # 总体统计
代码语言:javascript复制6
代码语言:javascript复制
P2 groupby相关
2.1 保留聚合列
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'b', 'a', 'b', 'a', 'b'], 'B': [1, 2, 3, 3, 4, 5]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | a | 3 |
3 | b | 3 |
4 | a | 4 |
5 | b | 5 |
我们按照A列中的分组进行聚合,并对B列进行求和,正常情况下我们会得到一个Series,而A列的内容被加入了索引中。
代码语言:javascript复制df.groupby('A')['B'].sum()
代码语言:javascript复制A
a 8
b 10
Name: B, dtype: int64
假设我们希望保留A列的内容,不使其进入索引,以便我们后续进行merge等操作,我们可以简单地使用 as_index=False 这一参数。
代码语言:javascript复制df.groupby('A', as_index=False)['B'].sum()
A | B | |
---|---|---|
0 | a | 8 |
1 | b | 10 |
2.2 取前n项
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'a', 'a', 'a', 'b', 'b', 'b'], 'B': [1, 3, 2, 4, 5, 2, 3]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | a | 3 |
2 | a | 2 |
3 | a | 4 |
4 | b | 5 |
5 | b | 2 |
6 | b | 3 |
假设我们想按照A列聚合后分别取每组的前2项,即a组取1、3,b组取5,2,我们可以利用head:
代码语言:javascript复制df.groupby('A')['B'].head(2)
代码语言:javascript复制0 1
1 3
4 5
5 2
Name: B, dtype: int64
注意:此处无论你是否采用 as_index=False 这一参数,结果都不会变化,如果你需要保留聚合列(用于后续merge等),请按照以下写法:
代码语言:javascript复制df.groupby('A', group_keys=False).apply(lambda x: x.head(2)) # 注意设置group_keys=False,否则返回多重索引
A | B | |
---|---|---|
0 | a | 1 |
1 | a | 3 |
4 | b | 5 |
5 | b | 2 |
这一技巧可以用于当我们想取最大或最小的前n项时,我们可以先进行排序,然后用head来选取:
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | a | 3 |
2 | a | 2 |
3 | a | 4 |
4 | b | 5 |
5 | b | 2 |
6 | b | 3 |
df.sort_values(['A', 'B'], ascending=False, inplace=True) # 第1步
代码语言:javascript复制df.groupby('A', group_keys=False).apply(lambda x: x.head(2)) # 第2步
A | B | |
---|---|---|
3 | a | 4 |
1 | a | 3 |
4 | b | 5 |
6 | b | 3 |
可以放心的是,即使你取的前n项的n超过了某个分组中成员数量的最大值,也不会报错。例如这里我取n=4,而b组只有3个,则结果中b组只返回3项。
代码语言:javascript复制df.groupby('A', group_keys=False).apply(lambda x: x.head(4))
A | B | |
---|---|---|
3 | a | 4 |
1 | a | 3 |
2 | a | 2 |
0 | a | 1 |
4 | b | 5 |
6 | b | 3 |
5 | b | 2 |
2.3 取第n项
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'a', 'a', 'a', 'b', 'b', 'b'], 'B': [1, 3, 2, 4, 5, 2, 3]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | a | 3 |
2 | a | 2 |
3 | a | 4 |
4 | b | 5 |
5 | b | 2 |
6 | b | 3 |
假设我们想按照A列聚合后分别取每组的第2项,即a组取3,b组取2,我们可以利用nth:
代码语言:javascript复制df.groupby('A')['B'].nth(1) # nth计数从0开始!!!
代码语言:javascript复制A
a 3
b 2
Name: B, dtype: int64
注意:nth与head不同,前者计数从0开始,后者从1开始。 另外,此处无论你是否采用 as_index=False 这一参数,结果都不会变化,如果你需要保留聚合列(用于后续merge等),请按照以下写法:
代码语言:javascript复制df.groupby('A', as_index=False).apply(lambda x: x.iloc[1])
A | B | |
---|---|---|
0 | a | 3 |
1 | b | 2 |
但这种方法有一个缺陷,当你所选取的n超过某个分组中成员数量的最大值时,就会报错,比如我取每组的第4项,而b组只有3个,就会报错。我们可以用以下命令取而代之:
代码语言:javascript复制df[df.groupby('A').cumcount() == 3] # 同样计数从0开始,此处即取第4项
A | B | |
---|---|---|
3 | a | 4 |
cumcount即累计计数,从0开始,每看到一条就 1,因此利用cumcount可以巧妙地解决这个问题。 这一技巧可以运用于我们想取最大或最小的第n项,同样先进行排序,再选取:
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | a | 3 |
2 | a | 2 |
3 | a | 4 |
4 | b | 5 |
5 | b | 2 |
6 | b | 3 |
df.sort_values(['A', 'B'], ascending=False, inplace=True) # 第1步
代码语言:javascript复制df[df.groupby('A').cumcount() == 1] # 第2步
A | B | |
---|---|---|
6 | b | 3 |
1 | a | 3 |
2.4 按时间特征及其他特征聚合
代码语言:javascript复制df = pd.DataFrame()
df['date'] = list(pd.date_range('2018-01-01', '2018-01-14')) * 2
df['shop'] = ['shop_A'] * 14 ['shop_B'] * 14
df['sales'] = [1, 2, 5, 3, 1, 5, 2, 3, 1, 1, 0, 0, 4, 5,
5, 1, 1, 2, 3, 4, 4, 0, 1, 2, 1, 2, 0, 5]
代码语言:javascript复制df
date | shop | sales | |
---|---|---|---|
0 | 2018-01-01 | shop_A | 1 |
1 | 2018-01-02 | shop_A | 2 |
2 | 2018-01-03 | shop_A | 5 |
3 | 2018-01-04 | shop_A | 3 |
4 | 2018-01-05 | shop_A | 1 |
5 | 2018-01-06 | shop_A | 5 |
6 | 2018-01-07 | shop_A | 2 |
7 | 2018-01-08 | shop_A | 3 |
8 | 2018-01-09 | shop_A | 1 |
9 | 2018-01-10 | shop_A | 1 |
10 | 2018-01-11 | shop_A | 0 |
11 | 2018-01-12 | shop_A | 0 |
12 | 2018-01-13 | shop_A | 4 |
13 | 2018-01-14 | shop_A | 5 |
14 | 2018-01-01 | shop_B | 5 |
15 | 2018-01-02 | shop_B | 1 |
16 | 2018-01-03 | shop_B | 1 |
17 | 2018-01-04 | shop_B | 2 |
18 | 2018-01-05 | shop_B | 3 |
19 | 2018-01-06 | shop_B | 4 |
20 | 2018-01-07 | shop_B | 4 |
21 | 2018-01-08 | shop_B | 0 |
22 | 2018-01-09 | shop_B | 1 |
23 | 2018-01-10 | shop_B | 2 |
24 | 2018-01-11 | shop_B | 1 |
25 | 2018-01-12 | shop_B | 2 |
26 | 2018-01-13 | shop_B | 0 |
27 | 2018-01-14 | shop_B | 5 |
通常情况下,如果我们想按照时间来聚合(从日到周),我们可以使用resample。但在这里,我们希望按照date和shop来聚合,即看看每个店每周的总销量分别是多少,这时候resample就不够用了,我们需要使用pd.Grouper:
代码语言:javascript复制df.groupby([pd.Grouper(key='date', freq='7d'), 'shop'])['sales'].sum()
代码语言:javascript复制date shop
2018-01-01 shop_A 19
shop_B 20
2018-01-08 shop_A 14
shop_B 11
Name: sales, dtype: int64
Grouper中的key就是需要聚合的时间列,而freq就是按照怎样的时间跨度来聚合。我们按照这个Grouper和shop进行聚合就完成了我们所想要的操作,如果我们希望能展平index的话,直接reset_index即可:
代码语言:javascript复制df.groupby([pd.Grouper(key='date', freq='7d'), 'shop'])['sales'].sum().reset_index()
date | shop | sales | |
---|---|---|---|
0 | 2018-01-01 | shop_A | 19 |
1 | 2018-01-01 | shop_B | 20 |
2 | 2018-01-08 | shop_A | 14 |
3 | 2018-01-08 | shop_B | 11 |
2.5 对不同的列进行不同类型的聚合
代码语言:javascript复制df=pd.DataFrame({'A':['g1', 'g1', 'g2', 'g2', 'g1'],'B':[3, 2, 3, 4, 2],'C':[1, 2, 1, 3, 4]})
代码语言:javascript复制df
A | B | C | |
---|---|---|---|
0 | g1 | 3 | 1 |
1 | g1 | 2 | 2 |
2 | g2 | 3 | 1 |
3 | g2 | 4 | 3 |
4 | g1 | 2 | 4 |
假设我们希望根据A列中的分组,对B列进行求和,而对C列求均值。我们可以定义一个字典,分别写出列名和相应的操作,然后通过agg函数完成操作。
代码语言:javascript复制agg_dic = {'B': 'sum', 'C': 'mean'}
df.groupby('A', as_index=False).agg(agg_dic)
A | B | C | |
---|---|---|---|
0 | g1 | 7 | 2.333333 |
1 | g2 | 7 | 2.000000 |
2.6 分组后装入列表
代码语言:javascript复制df=pd.DataFrame({'A':['g1', 'g1', 'g2', 'g2', 'g1'],'B':[3, 2, 3, 4, 2]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | g1 | 3 |
1 | g1 | 2 |
2 | g2 | 3 |
3 | g2 | 4 |
4 | g1 | 2 |
假设我们想根据A列分组,并将每组对应的元素放入列表中(比如g1对应[3, 2, 2])。
代码语言:javascript复制df.groupby('A')['B'].apply(list).reset_index()
A | B | |
---|---|---|
0 | g1 | [3, 2, 2] |
1 | g2 | [3, 4] |
2.7 列表元素拆出
代码语言:javascript复制df=pd.DataFrame({'A':['g1', 'g2'],'B':[[3, 2, 1], [4, 2]]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | g1 | [3, 2, 1] |
1 | g2 | [4, 2] |
与2.6中的操作相反,这次我们希望g1, g2分别于其对应的B列中列表内的每个元素单独形成一行(g1-3, g1-2, g1-1, g2-4, g2-2)。
代码语言:javascript复制vals = df['B'].values.tolist() # 将B列的内容转为列表
rs = [len(r) for r in vals] # 获取B列中每个列表的长度
a = np.repeat(df['A'], rs) # A列中的每个元素重复rs中的对应次数
df2 = pd.DataFrame(np.column_stack((a, np.concatenate(vals))), columns=df.columns) # column_stack为列合并(行数不变)
代码语言:javascript复制df2
A | B | |
---|---|---|
0 | g1 | 3 |
1 | g1 | 2 |
2 | g1 | 1 |
3 | g2 | 4 |
4 | g2 | 2 |
2.8 组内打乱
代码语言:javascript复制df = pd.DataFrame({'A':['g1', 'g1', 'g1', 'g1', 'g2', 'g2', 'g2'],'B':[1, 2, 3, 4, 5, 6, 7]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | g1 | 1 |
1 | g1 | 2 |
2 | g1 | 3 |
3 | g1 | 4 |
4 | g2 | 5 |
5 | g2 | 6 |
6 | g2 | 7 |
假设我们想分别根据A列的分组打乱B的顺序,即分别打乱1、2、3、4(g1组)和5、6、7(g2组),我们可以利用transform来完成:
代码语言:javascript复制df['B'] = df.groupby('A')['B'].transform(np.random.permutation)
代码语言:javascript复制df
A | B | |
---|---|---|
0 | g1 | 1 |
1 | g1 | 2 |
2 | g1 | 4 |
3 | g1 | 3 |
4 | g2 | 7 |
5 | g2 | 6 |
6 | g2 | 5 |
2.9 组内出现次数相关
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b'],
'B': [1, 3, 2, 4, 3, 5, 2, 3, 2, 2, 2]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | a | 3 |
2 | a | 2 |
3 | a | 4 |
4 | a | 3 |
5 | b | 5 |
6 | b | 2 |
7 | b | 3 |
8 | b | 2 |
9 | b | 2 |
10 | b | 2 |
假设我们想知道根据A列分组后,查看每组内B列元素出现次数最多的元素和其出现的次数,我们可以通过value_counts来实现。首先,我们可以查看B列每个元素出现的次数:
代码语言:javascript复制df.groupby('A')['B'].value_counts()
代码语言:javascript复制A B
a 3 2
1 1
2 1
4 1
b 2 4
3 1
5 1
Name: B, dtype: int64
如果我们要选择次数最多就使用max()和idxmax():
代码语言:javascript复制df.groupby('A')['B'].apply(lambda x: x.value_counts().idxmax())
代码语言:javascript复制A
a 3
b 2
Name: B, dtype: int64
通过apply与value_counts和idxmax的结合,我们看到a组和b组中出现次数最多的分别是3和2。
代码语言:javascript复制df.groupby('A')['B'].apply(lambda x: x.value_counts().max())
代码语言:javascript复制A
a 2
b 4
Name: B, dtype: int64
而通过apply与value_counts和max的结合,我们看到a组和b组中出现次数最多的元素分别出现了2次和4次。
代码语言:javascript复制
P3 行列操作
3.1 复制多行
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'b'], 'B': [1, 3]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 3 |
假设由于某些原因,我们需要对行进行复制,一种是按块复制,即ab ab ab:
代码语言:javascript复制pd.concat([df]*4) # 复制4次
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 3 |
0 | a | 1 |
1 | b | 3 |
0 | a | 1 |
1 | b | 3 |
0 | a | 1 |
1 | b | 3 |
另一种是按行复制,即 aaa bbb:
代码语言:javascript复制pd.concat([df]*4).sort_values('A').reset_index(drop=True) # 复制后按A列排序,并重设索引以达到效果
A | B | |
---|---|---|
0 | a | 1 |
1 | a | 1 |
2 | a | 1 |
3 | a | 1 |
4 | b | 3 |
5 | b | 3 |
6 | b | 3 |
7 | b | 3 |
3.2 合并多列内容(文本)
代码语言:javascript复制df = pd.DataFrame({'A': [1988, 1993], 'B': ['02', '03'], 'C':[21, 13]})
代码语言:javascript复制df
A | B | C | |
---|---|---|---|
0 | 1988 | 02 | 21 |
1 | 1993 | 03 | 13 |
假设我们希望每行的三个单元格合并成形如 1998-02-21 的形式。
代码语言:javascript复制df['D'] = df['A'].astype(str) '-' df['B'].astype(str) '-' df['C'].astype(str)
代码语言:javascript复制df
A | B | C | D | |
---|---|---|---|---|
0 | 1988 | 02 | 21 | 1988-02-21 |
1 | 1993 | 03 | 13 | 1993-03-13 |
注意:此处由于某些单元格中存在数值,所以我们要先用astype将其转化为字符串,然后合并,否则可能报错。
3.3 拆分列内容(文本)
代码语言:javascript复制df = pd.DataFrame({'A': ['1988-02-21', '1993-03-13']})
代码语言:javascript复制df
A | |
---|---|
0 | 1988-02-21 |
1 | 1993-03-13 |
假设与之前相反,我们希望把A列拆分为年、月、日3列,可以进行如下操作:
代码语言:javascript复制df2 = pd.DataFrame(df['A'].str.split('-').tolist(), columns=['year', 'month', 'day'])
代码语言:javascript复制df2
year | month | day | |
---|---|---|---|
0 | 1988 | 02 | 21 |
1 | 1993 | 03 | 13 |
逐段分解上述命令: (1)首先,我们使用了df['A'].str,这样就可以进行字符操作,以便我们后续split(); (2)我们利用tolist()将分割后的字符串装入列表; (3)我们重新创建了一个表,而columns=['year', 'month', 'day']指定了新表的列名。
3.4 拆分列内容(文本,拆分后不定长)
代码语言:javascript复制df = pd.DataFrame({'A': ['88-02-21-00-23', '93-03-13', '00-51-03-13']})
代码语言:javascript复制df
A | |
---|---|
0 | 88-02-21-00-23 |
1 | 93-03-13 |
2 | 00-51-03-13 |
假设此处我们希望按照'-'为分隔符来拆分A列的内容,但我们发现每行分割后元素数量并不相同(5个、3个、4个),用之前的操作会很麻烦,我们可以用如下操作(但是无法直接命名拆分后的列):
代码语言:javascript复制df['A'].str.split('-', expand=True)
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 88 | 02 | 21 | 00 | 23 |
1 | 93 | 03 | 13 | None | None |
2 | 00 | 51 | 03 | 13 | None |
3.5 选取包含特定文本的列
代码语言:javascript复制df = pd.DataFrame({'A': ['highest', 'good', 'just', 'newest', 'newer', 'estimate']})
代码语言:javascript复制df
A | |
---|---|
0 | highest |
1 | good |
2 | just |
3 | newest |
4 | newer |
5 | estimate |
假设我们需要选取字符串中包含'est'的行,我们依然会用到df['A'].str来进行字符级操作:
代码语言:javascript复制df[df['A'].str.contains('est')]
A | |
---|---|
0 | highest |
3 | newest |
5 | estimate |
事实上,contains里可以包含各种正则表达式:
代码语言:javascript复制df = pd.DataFrame({'A': ['yes ok', 'yesok', 'yes 2 ok', 'okok', 'yes yes', 'ok yes']})
代码语言:javascript复制df
A | |
---|---|
0 | yes ok |
1 | yesok |
2 | yes 2 ok |
3 | okok |
4 | yes yes |
5 | ok yes |
df[df['A'].str.contains(re.compile('yes. ok'))]
A | |
---|---|
0 | yes ok |
2 | yes 2 ok |
3.6 clip的用途
代码语言:javascript复制df = pd.DataFrame({'Name': ['Apple', 'Peach', 'Melon', 'Grape', 'Banana'], 'Sales': [2, 0, 5, 1, -1]})
代码语言:javascript复制df
Name | Sales | |
---|---|---|
0 | Apple | 2 |
1 | Peach | 0 |
2 | Melon | 5 |
3 | Grape | 1 |
4 | Banana | -1 |
假设此处我们sales转换为多分类,即≤0(没卖出去或惨遭退货),卖出去1件,和卖出1件以上,以便后续处理,我们可以简单地使用clip来完成。这在某些低销量商品转化为分类问题的过程中可能会用到。
代码语言:javascript复制df['label'] = df['Sales'].clip(0, 2) # 下限为0,上限为2
代码语言:javascript复制df
Name | Sales | label | |
---|---|---|---|
0 | Apple | 2 | 2 |
1 | Peach | 0 | 0 |
2 | Melon | 5 | 2 |
3 | Grape | 1 | 1 |
4 | Banana | -1 | 0 |
3.7 值替换
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'b', 'a', 'b', 'a', 'b'], 'B': [1, 2, 3, 3, 3, 5]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | a | 3 |
3 | b | 3 |
4 | a | 3 |
5 | b | 5 |
假设此处我们需要将A列中的内容进行替换,'a'替换为'Male','b'替换为'Female',我们可以利用字典和map命令来进行。
代码语言:javascript复制dic = {'a': 'Male', 'b': 'Female'}
代码语言:javascript复制df['A'] = df['A'].map(dic)
代码语言:javascript复制df
A | B | |
---|---|---|
0 | Male | 1 |
1 | Female | 2 |
2 | Male | 3 |
3 | Female | 3 |
4 | Male | 3 |
5 | Female | 5 |
然而,使用map有一个问题,如果A列中有某些值不在字典中,这些值会变成NaN,如下所示:
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'b', 'a', 'b', 'a', 'b', 'c', 'd'], 'B': [1, 2, 3, 3, 3, 5, 4, 5]})
代码语言:javascript复制df['A'] = df['A'].map(dic)
代码语言:javascript复制df
A | B | |
---|---|---|
0 | Male | 1 |
1 | Female | 2 |
2 | Male | 3 |
3 | Female | 3 |
4 | Male | 3 |
5 | Female | 5 |
6 | NaN | 4 |
7 | NaN | 5 |
可以看到A列中的'c'和'd'变成了NaN,要解决这一问题,我们可以用字典与replace()函数的结合。
代码语言:javascript复制df = pd.DataFrame({'A': ['a', 'b', 'a', 'b', 'a', 'b', 'c', 'd'], 'B': [1, 2, 3, 3, 3, 5, 4, 5]})
代码语言:javascript复制df['A'] = df['A'].replace(dic)
代码语言:javascript复制df
A | B | |
---|---|---|
0 | Male | 1 |
1 | Female | 2 |
2 | Male | 3 |
3 | Female | 3 |
4 | Male | 3 |
5 | Female | 5 |
6 | c | 4 |
7 | d | 5 |
可以看到'c'和'd'被保留了下来。
3.8 最值查询
代码语言:javascript复制df = pd.DataFrame({'Name': ['Apple', 'Peach', 'Melon', 'Grape', 'Banana'], 'Sales': [2, 0, 5, 1, -1]})
代码语言:javascript复制df
Name | Sales | |
---|---|---|
0 | Apple | 2 |
1 | Peach | 0 |
2 | Melon | 5 |
3 | Grape | 1 |
4 | Banana | -1 |
假设我们分别需要知道Sales最大值和最小值所对应的Name。
代码语言:javascript复制df.iloc[df['Sales'].idxmax()] # idxmax即返回最大值对应的索引,最小值使用idxmin
代码语言:javascript复制Name Melon
Sales 5
Name: 2, dtype: object
上述命令返回的是改行的所有内容,如果我们只需要知道Name,加上列名即可。
代码语言:javascript复制df['Name'].iloc[df['Sales'].idxmax()]
代码语言:javascript复制'Melon'
3.9 选出第N大/第N小
代码语言:javascript复制df = pd.DataFrame({'A': [1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8], 'B': [2, 4, 2, 1, 4, 5, 11, 23, 42, 1, 22]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | 1 | 2 |
1 | 1 | 4 |
2 | 2 | 2 |
3 | 2 | 1 |
4 | 3 | 4 |
5 | 4 | 5 |
6 | 5 | 11 |
7 | 6 | 23 |
8 | 7 | 42 |
9 | 7 | 1 |
10 | 8 | 22 |
假设我们想选出A中第二大的值(7)所对应的行,我们可以使用rank:
代码语言:javascript复制df[df['A'].rank(method='dense', ascending=False) == 2]
A | B | |
---|---|---|
8 | 7 | 42 |
9 | 7 | 1 |
注意:此处rank中的参数method我们设为"dense",意味着无论有多少并列,我们的排名数始终为1、2、3……而不会因为并列而跳过某些值
如果要选择第三小的值:
代码语言:javascript复制df[df['A'].rank(method='dense', ascending=True) == 3]
A | B | |
---|---|---|
4 | 3 | 4 |
3.10 选取特定数据类型的行
代码语言:javascript复制df = pd.DataFrame({'A': [1988, 1993, 'noise', 'noise2', 2018, 'noise3']})
代码语言:javascript复制df
A | |
---|---|
0 | 1988 |
1 | 1993 |
2 | noise |
3 | noise2 |
4 | 2018 |
5 | noise3 |
df.info()
代码语言:javascript复制<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 1 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 A 6 non-null object
dtypes: object(1)
memory usage: 176.0 bytes
代码语言:javascript复制df
A | |
---|---|
0 | 1988 |
1 | 1993 |
2 | noise |
3 | noise2 |
4 | 2018 |
5 | noise3 |
df中混杂有数值与字符串,假设我们想将他们分离开来,比如我们只需要选取数值,如果我们用如下命令的话会报错:
代码语言:javascript复制df[type(df['A']) == int]
代码语言:javascript复制---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
~/anaconda3/lib/python3.8/site-packages/pandas/core/indexes/base.py in get_loc(self, key, method, tolerance)
2645 try:
-> 2646 return self._engine.get_loc(key)
2647 except KeyError:
pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()
pandas/_libs/index.pyx in pandas._libs.index.IndexEngine.get_loc()
pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()
pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.get_item()
KeyError: False
我们需要通过apply来完成选取。
代码语言:javascript复制df[df['A'].apply(lambda x: type(x) == int)]
A | |
---|---|
0 | 1988 |
1 | 1993 |
4 | 2018 |
3.11 总体统计
代码语言:javascript复制df = pd.DataFrame({'A':[1, 2, 1, 3], 'B':[2, 1, 1, 4], 'C':[3, 4, 1, 1]})
代码语言:javascript复制df
A | B | C | |
---|---|---|---|
0 | 1 | 2 | 3 |
1 | 2 | 1 | 4 |
2 | 1 | 1 | 1 |
3 | 3 | 4 | 1 |
我们知道通常我们对某一列进行数值统计的时候会用value_counts函数,比如统计A列有多少个1,多少个2……然而value_counts只能用于Series,并不能用于DataFrame,当我们要对全表进行数值统计时应该怎么办呢?我个人的办法是,先把df拉长成一个Series,然后再应用value_counts函数:
代码语言:javascript复制pd.Series(np.ravel(df)).value_counts()
代码语言:javascript复制1 6
4 2
3 2
2 2
dtype: int64
3.12 滑窗统计相关
代码语言:javascript复制df = pd.DataFrame({'signal': [1, 2, 3, 2, 5, 3, 5, 6, 3, 2, 3, 5, 6, 2, 1, 3, 2]})
代码语言:javascript复制df
signal | |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 2 |
4 | 5 |
5 | 3 |
6 | 5 |
7 | 6 |
8 | 3 |
9 | 2 |
10 | 3 |
11 | 5 |
12 | 6 |
13 | 2 |
14 | 1 |
15 | 3 |
16 | 2 |
我们都知道rolling能提供滑窗功能,辅以各种统计函数就能实现滑窗均值、滑窗最值等等功能。但有时候我们的需求可能会更复杂一些,而rolling原生的统计函数并不多,不过幸好,我们有apply。假设我们要统计的窗口长度为5,每个窗口内统计最大top 3的和:
代码语言:javascript复制df['rolling_top3_sum'] = df['signal'].rolling(5).apply(lambda x: np.sum(np.sort(x)[-3:]))
代码语言:javascript复制df
signal | rolling_top3_sum | |
---|---|---|
0 | 1 | NaN |
1 | 2 | NaN |
2 | 3 | NaN |
3 | 2 | NaN |
4 | 5 | 10.0 |
5 | 3 | 11.0 |
6 | 5 | 13.0 |
7 | 6 | 16.0 |
8 | 3 | 16.0 |
9 | 2 | 14.0 |
10 | 3 | 14.0 |
11 | 5 | 14.0 |
12 | 6 | 14.0 |
13 | 2 | 14.0 |
14 | 1 | 14.0 |
15 | 3 | 14.0 |
16 | 2 | 11.0 |
rolling函数的参数自然就是窗口长度,rolling出来的结果可以看做是个array,所以我们可以对其应用各种numpy函数,这里我们拆解一下apply:首先我们先对rolling出来的array进行排序(从小到大),然后取倒数3个,最后将其加和。比如第6个窗口是[3, 2, 5, 3, 5],排序后是[2, 3, 3, 5, 5],取最后3个(最大值top 3)是[3, 5, 5],求和为13。
3.13 导出字典
代码语言:javascript复制df = pd.DataFrame({'A':['a', 'b', 'c', 'd'], 'B':[2, 1, 1, 4]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | a | 2 |
1 | b | 1 |
2 | c | 1 |
3 | d | 4 |
我们假设我们希望导出一个字典,以A列为键,以B列为值。我们用set_index()来指定为键的列,然后用to_dict()函数进行转换:
代码语言:javascript复制df.set_index('A').to_dict()
代码语言:javascript复制{'B': {'a': 2, 'b': 1, 'c': 1, 'd': 4}}
可以看到转换后我们想要的字典被包含在另一个字典里,而那个字典的键就是另一列(B列)的列名:
代码语言:javascript复制df.set_index('A').to_dict()['B']
代码语言:javascript复制{'a': 2, 'b': 1, 'c': 1, 'd': 4}
3.14 Count Encoding
代码语言:javascript复制df = pd.DataFrame({'A':[1, 1, 1, 2, 3, 1, 3, np.nan], 'B':[1, 1, 1, 1, 1, 2, 2, 2]})
代码语言:javascript复制df
A | B | |
---|---|---|
0 | 1.0 | 1 |
1 | 1.0 | 1 |
2 | 1.0 | 1 |
3 | 2.0 | 1 |
4 | 3.0 | 1 |
5 | 1.0 | 2 |
6 | 3.0 | 2 |
7 | NaN | 2 |
假设我们希望有一列标记A中每个元素出现的次数(即Count Encoding),一个比较简单的方法是先将value_counts的结果转化为dict,再利用map函数:
代码语言:javascript复制tmp = df['A'].value_counts().to_dict()
df['A_cnt'] = df['A'].map(tmp)
df
A | B | A_cnt | |
---|---|---|---|
0 | 1.0 | 1 | 4.0 |
1 | 1.0 | 1 | 4.0 |
2 | 1.0 | 1 | 4.0 |
3 | 2.0 | 1 | 1.0 |
4 | 3.0 | 1 | 2.0 |
5 | 1.0 | 2 | 4.0 |
6 | 3.0 | 2 | 2.0 |
7 | NaN | 2 | NaN |
值得注意的是,该方法并不支持nan,如果需要对nan也进行统计,则需先用fillna进行填充。
3.15 检查单调性
代码语言:javascript复制df = pd.DataFrame({'A':[1, 1, 2, 3, 5], 'B':[2, 1, 1, 2, 4], 'C':[5, 4, 3, 2, 1]})
代码语言:javascript复制df
A | B | C | |
---|---|---|---|
0 | 1 | 2 | 5 |
1 | 1 | 1 | 4 |
2 | 2 | 1 | 3 |
3 | 3 | 2 | 2 |
4 | 5 | 4 | 1 |
假设我们希望检查某一列是否单调递增,我们可以使用is_monotonic来查看。注意,is_monotonic是pd.Series的属性:
代码语言:javascript复制print(df['A'].is_monotonic)
print(df['B'].is_monotonic)
print(df['C'].is_monotonic)
代码语言:javascript复制True
False
False
如果要查看是否单调递减,则使用is_monotonic_decreasing:
代码语言:javascript复制print(df['A'].is_monotonic_decreasing)
print(df['B'].is_monotonic_decreasing)
print(df['C'].is_monotonic_decreasing)
代码语言:javascript复制False
False
True
如果我们要按行查看我们需要结合apply函数,并使用is_monotonic.fget()
代码语言:javascript复制df.apply(pd.Series.is_monotonic.fget, axis=1)
代码语言:javascript复制0 True
1 True
2 False
3 False
4 False
dtype: bool
查看单调递减也是类似的:
代码语言:javascript复制df.apply(pd.Series.is_monotonic_decreasing.fget, axis=1)
代码语言:javascript复制0 False
1 False
2 False
3 True
4 True
dtype: bool
3.16 一次性合并多个DataFrame
代码语言:javascript复制df1 = pd.DataFrame({'A':['a', 'b', 'c'], 'm1':[1, 2, 3]})
df2 = pd.DataFrame({'A':['b', 'c', 'd'], 'm2':[3, 4, 3]})
df3 = pd.DataFrame({'A':['a', 'c', 'f'], 'm3':[4, 2, 1]})
假设我们想将这三个DataFrame合并,查看A列中每个不同的元素从m1到m3期间的变化(outer merge)。如果我们使用两两合并,当DataFrame的数量很多时,我们就需要写很多行代码,在此可以考虑采用reduce:
代码语言:javascript复制from functools import reduce
代码语言:javascript复制df_ls = [df1, df2, df3] # 将需要合并的DataFrame放入一个列表中
reduce(lambda left, right: pd.merge(left, right, how='outer', on='A'), df_ls) # 第一个参数为需要执行的操作,第二个参数为列表
A | m1 | m2 | m3 | |
---|---|---|---|---|
0 | a | 1.0 | NaN | 4.0 |
1 | b | 2.0 | 3.0 | NaN |
2 | c | 3.0 | 4.0 | 2.0 |
3 | d | NaN | 3.0 | NaN |
4 | f | NaN | NaN | 1.0 |
3.17 共现矩阵
代码语言:javascript复制df = pd.DataFrame({'labal_A':[1, 0, 0, 1, 1, 0, 1, 0],
'labal_B':[1, 1, 0, 1, 0, 0, 1, 0],
'labal_C':[0, 1, 1, 1, 0, 0, 1, 1],
'labal_D':[0, 0, 1, 0, 1, 1, 1, 1]})
代码语言:javascript复制df
labal_A | labal_B | labal_C | labal_D | |
---|---|---|---|---|
0 | 1 | 1 | 0 | 0 |
1 | 0 | 1 | 1 | 0 |
2 | 0 | 0 | 1 | 1 |
3 | 1 | 1 | 1 | 0 |
4 | 1 | 0 | 0 | 1 |
5 | 0 | 0 | 0 | 1 |
6 | 1 | 1 | 1 | 1 |
7 | 0 | 0 | 1 | 1 |
假设我们有一组0-1标签(label_A到label_D),我们想要获得标签之间的共现矩阵,即标签两两之间共同出现的次数。我们可以使用转置后点积的方法:
代码语言:javascript复制df.T.dot(df)
labal_A | labal_B | labal_C | labal_D | |
---|---|---|---|---|
labal_A | 4 | 3 | 2 | 2 |
labal_B | 3 | 4 | 3 | 1 |
labal_C | 2 | 3 | 5 | 3 |
labal_D | 2 | 1 | 3 | 5 |
其中对角线上的数代表每个标签中1出现了多少次,该矩阵是一个对称矩阵。
3.18 笛卡尔积
代码语言:javascript复制a = ['id_1', 'id_2', 'id_3', 'id_4']
b = pd.date_range('2020-01-01', '2020-01-03')
c = ['type_A', 'type_B']
假设我们有上述数据,并希望生成它们的笛卡尔积(即a, b, c三者所有可能的排列组合)。我们可以先用它们建立一个MultiIndex,然后装入一个空的DataFrame中并reset_index即可:
代码语言:javascript复制idx = pd.MultiIndex.from_product([a, b, c], names=['uid', 'date', 'type'])
pd.DataFrame(index=idx).reset_index()
uid | date | type | |
---|---|---|---|
0 | id_1 | 2020-01-01 | type_A |
1 | id_1 | 2020-01-01 | type_B |
2 | id_1 | 2020-01-02 | type_A |
3 | id_1 | 2020-01-02 | type_B |
4 | id_1 | 2020-01-03 | type_A |
5 | id_1 | 2020-01-03 | type_B |
6 | id_2 | 2020-01-01 | type_A |
7 | id_2 | 2020-01-01 | type_B |
8 | id_2 | 2020-01-02 | type_A |
9 | id_2 | 2020-01-02 | type_B |
10 | id_2 | 2020-01-03 | type_A |
11 | id_2 | 2020-01-03 | type_B |
12 | id_3 | 2020-01-01 | type_A |
13 | id_3 | 2020-01-01 | type_B |
14 | id_3 | 2020-01-02 | type_A |
15 | id_3 | 2020-01-02 | type_B |
16 | id_3 | 2020-01-03 | type_A |
17 | id_3 | 2020-01-03 | type_B |
18 | id_4 | 2020-01-01 | type_A |
19 | id_4 | 2020-01-01 | type_B |
20 | id_4 | 2020-01-02 | type_A |
21 | id_4 | 2020-01-02 | type_B |
22 | id_4 | 2020-01-03 | type_A |
23 | id_4 | 2020-01-03 | type_B |
3.19 行转列
代码语言:javascript复制df = pd.DataFrame({'product':['A', 'B', 'C'],
'2020-01-01':[5, 1, 3],
'2020-01-02':[2, 2, 3],
'2020-01-03':[4, 3, 6]})
代码语言:javascript复制df
product | 2020-01-01 | 2020-01-02 | 2020-01-03 | |
---|---|---|---|---|
0 | A | 5 | 2 | 4 |
1 | B | 1 | 2 | 3 |
2 | C | 3 | 3 | 6 |
假设我们有一些销售数据,每一天的记录都是单独的一列,而我们想将其转化成所有日期都在同一列的样子,我们可以使用行转列的melt函数:
代码语言:javascript复制pd.melt(df, id_vars='product')
product | variable | value | |
---|---|---|---|
0 | A | 2020-01-01 | 5 |
1 | B | 2020-01-01 | 1 |
2 | C | 2020-01-01 | 3 |
3 | A | 2020-01-02 | 2 |
4 | B | 2020-01-02 | 2 |
5 | C | 2020-01-02 | 3 |
6 | A | 2020-01-03 | 4 |
7 | B | 2020-01-03 | 3 |
8 | C | 2020-01-03 | 6 |
P4 时间相关
4.1 创建时间信息
代码语言:javascript复制df = pd.DataFrame()
代码语言:javascript复制df
代码语言:javascript复制df['date'] = pd.date_range('2019-01-01', '2019-01-06') # 按日,通过起止时间
代码语言:javascript复制df
date | |
---|---|
0 | 2019-01-01 |
1 | 2019-01-02 |
2 | 2019-01-03 |
3 | 2019-01-04 |
4 | 2019-01-05 |
5 | 2019-01-06 |
另一种方法是通过开始时间和时长,如下:
代码语言:javascript复制df = pd.DataFrame()
df['date'] = pd.date_range('2019-01-01', periods=10) # 按日,从2019年1月1日起,时长为10天
代码语言:javascript复制df
date | |
---|---|
0 | 2019-01-01 |
1 | 2019-01-02 |
2 | 2019-01-03 |
3 | 2019-01-04 |
4 | 2019-01-05 |
5 | 2019-01-06 |
6 | 2019-01-07 |
7 | 2019-01-08 |
8 | 2019-01-09 |
9 | 2019-01-10 |
df['date'].values[0]
代码语言:javascript复制numpy.datetime64('2019-01-01T00:00:00.000000000')
代码语言:javascript复制type(df['date'].values[0])
代码语言:javascript复制numpy.datetime64
如果我们希望指定更小的时间粒度,我们需要: (1)细化起止时间; (2)修改freq参数。
代码语言:javascript复制df = pd.DataFrame()
代码语言:javascript复制df['date'] = pd.date_range('2019-01-01 01:40:00', '2019-01-01 10:00:00', freq='1h') # 按小时
代码语言:javascript复制df
date | |
---|---|
0 | 2019-01-01 01:40:00 |
1 | 2019-01-01 02:40:00 |
2 | 2019-01-01 03:40:00 |
3 | 2019-01-01 04:40:00 |
4 | 2019-01-01 05:40:00 |
5 | 2019-01-01 06:40:00 |
6 | 2019-01-01 07:40:00 |
7 | 2019-01-01 08:40:00 |
8 | 2019-01-01 09:40:00 |
4.2 文本转化为时间
代码语言:javascript复制df = pd.DataFrame({'date': ['01/05/2016', '01/28/2017', '02/21/2018', '03/05/2018', '11/24/2019']})
代码语言:javascript复制df
date | |
---|---|
0 | 01/05/2016 |
1 | 01/28/2017 |
2 | 02/21/2018 |
3 | 03/05/2018 |
4 | 11/24/2019 |
我们经常会在表格中遇到各种代表时间的文本,有时为了后续操作方便,我们需要将其转化为python可以识别的时间信息(比如Timestamp),我们可以使用pd.to_datetime:
代码语言:javascript复制df['date'] = pd.to_datetime(df['date'], format='%m/%d/%Y')
代码语言:javascript复制df
date | |
---|---|
0 | 2016-01-05 |
1 | 2017-01-28 |
2 | 2018-02-21 |
3 | 2018-03-05 |
4 | 2019-11-24 |
我们可以在format参数中指定原始数据的格式,以便正确解析(有时不规定format出来的结果可能是错的)。另外需要注意的是,有些年份只用两位数,如17代表2017年,这时在format中要使用%y作为占位符,而不是%Y,否则会报错。
代码语言:javascript复制df = pd.DataFrame({'date': ['01/05/16', '01/28/17', '02/21/18', '03/05/18', '11/24/19']})
代码语言:javascript复制df
date | |
---|---|
0 | 01/05/16 |
1 | 01/28/17 |
2 | 02/21/18 |
3 | 03/05/18 |
4 | 11/24/19 |
df['date'] = pd.to_datetime(df['date'], format='%m/%d/%y') # 注意y小写
代码语言:javascript复制df
date | |
---|---|
0 | 2016-01-05 |
1 | 2017-01-28 |
2 | 2018-02-21 |
3 | 2018-03-05 |
4 | 2019-11-24 |
4.3 间隔时间选取
代码语言:javascript复制df = pd.DataFrame({'date': pd.date_range('2018-12-01', '2018-12-20')})
代码语言:javascript复制df
date | |
---|---|
0 | 2018-12-01 |
1 | 2018-12-02 |
2 | 2018-12-03 |
3 | 2018-12-04 |
4 | 2018-12-05 |
5 | 2018-12-06 |
6 | 2018-12-07 |
7 | 2018-12-08 |
8 | 2018-12-09 |
9 | 2018-12-10 |
10 | 2018-12-11 |
11 | 2018-12-12 |
12 | 2018-12-13 |
13 | 2018-12-14 |
14 | 2018-12-15 |
15 | 2018-12-16 |
16 | 2018-12-17 |
17 | 2018-12-18 |
18 | 2018-12-19 |
19 | 2018-12-20 |
假设我们希望每隔3天取一个值(即1、4、7……),只需利用索引即可。
代码语言:javascript复制df[df.index%3 == 0] # 后续可以根据需求决定是否要reset_index
date | |
---|---|
0 | 2018-12-01 |
3 | 2018-12-04 |
6 | 2018-12-07 |
9 | 2018-12-10 |
12 | 2018-12-13 |
15 | 2018-12-16 |
18 | 2018-12-19 |
如果我们的时间是不连续的话,无法利用索引,该怎么办呢?
代码语言:javascript复制df = pd.DataFrame({'date': list(pd.date_range('2018-12-01', '2018-12-10')) list(pd.date_range('2018-12-15', '2018-12-20'))})
代码语言:javascript复制df # 12-11 到 12-14 是缺失的
date | |
---|---|
0 | 2018-12-01 |
1 | 2018-12-02 |
2 | 2018-12-03 |
3 | 2018-12-04 |
4 | 2018-12-05 |
5 | 2018-12-06 |
6 | 2018-12-07 |
7 | 2018-12-08 |
8 | 2018-12-09 |
9 | 2018-12-10 |
10 | 2018-12-15 |
11 | 2018-12-16 |
12 | 2018-12-17 |
13 | 2018-12-18 |
14 | 2018-12-19 |
15 | 2018-12-20 |
df[df['date'].isin(pd.date_range('2018-12-01', '2018-12-20', freq='3D'))]
date | |
---|---|
0 | 2018-12-01 |
3 | 2018-12-04 |
6 | 2018-12-07 |
9 | 2018-12-10 |
11 | 2018-12-16 |
14 | 2018-12-19 |
逐段分解上述命令: (1)首先,最里面的括号,我们创建了一个日期索引,首尾与df中的日期对齐,间隔为3天; (2)然后我们选取df的date列中存在于上述日期索引的行。
4.3 获取某个日期是星期几
代码语言:javascript复制df = pd.DataFrame()
df['date'] = pd.date_range('2019-01-01', periods=10)
代码语言:javascript复制df
date | |
---|---|
0 | 2019-01-01 |
1 | 2019-01-02 |
2 | 2019-01-03 |
3 | 2019-01-04 |
4 | 2019-01-05 |
5 | 2019-01-06 |
6 | 2019-01-07 |
7 | 2019-01-08 |
8 | 2019-01-09 |
9 | 2019-01-10 |
假设我们需要知道当前每个日期是星期几,我们需要导入datetime,然后使用apply来完成。
代码语言:javascript复制from datetime import datetime
df['weekday'] = df['date'].apply(datetime.weekday)
代码语言:javascript复制df
date | weekday | |
---|---|---|
0 | 2019-01-01 | 1 |
1 | 2019-01-02 | 2 |
2 | 2019-01-03 | 3 |
3 | 2019-01-04 | 4 |
4 | 2019-01-05 | 5 |
5 | 2019-01-06 | 6 |
6 | 2019-01-07 | 0 |
7 | 2019-01-08 | 1 |
8 | 2019-01-09 | 2 |
9 | 2019-01-10 | 3 |
注意:这里的weekday是0-6,其中0代表星期一。
源码:
https://www.kesci.com/mw/project/604a285c74dfc60016e0fda0
https://github.com/SilenceGTX/pandas_tricks