Pandas Tips
文章目录
Some tips for Pandas.
创建测试对象
s = pd.Series(my_list)
df = pd.DataFrame(np.random.rand(20, 5)) # 创建20行5列随机数组成的DataFrame对象
df.index = pd.data_range("2019/1/30", periods=df.shape[0]) # 增加日期索引
查看数据
df.head()
df.tail()
df.shape
df.describe()
df.info()
df.index
df.columns
df.dtypes
df.T
df.empty
df.copy()
s.dtype
s.value_counts() # 统计series对象的唯一值并计数
df.apply(pd.Series.value_counts) # 查看df对象每一列的唯一值和计数
df.query() # 按条件查询
df.take()
数据选取
df[col] # 根据列名选取,返回Series
df[[cols]] # 根据列名选取,返回df
df.loc[] # 按标签选取
df.iloc[] # 按位置选取
数据清洗
pd.isna()
pd.isnull()
pd.notna()
pd.notnull()
df.dropna(how='any') # 删除所有包含空值的行
df.dropna(axis=1) # 删除所有包含空值的列
df.fillna(x) # 用x填充空值
df.fillna(method='ffill') # 用前面的数据填充后面的
df.ffill()
df.fillna(method='bfill', limit=1) # 用后面的填充前面的, 填充1个
df.bfill()
# 索引
df.set_index('code')
df.reset_index(drop=None)
df.reindex([])
# 布尔索引
df[df.a > 0]
df[df > 0]
df[((df.a > 0) & (df.b < 0)) | (df.c = 1))]
df[~df['a'].isin([0, 1])]
# 命名
df.columns = ['a', 'b', 'c', 'd']
df.rename(columns={'a': 'A'})
df.rename(index=lambda x: x + 1)
# 替换
df.replace(1, 'one')
df.replace([1, 3], ['one', 'three'])
# 数据类型
df.code.astype(str)
df.date.to_datetime()
pd.to_datetime()
数据处理
# 过滤
df[df['score'] > 60]
df[df.age.isin([20, 21, 22])]
df.filter()
df.query()
# 排序
df.sort_values(by='age', ascending=True)
df.sort_values(by=['age', 'score'], ascending=[True, False])
df.sort_index(axis=1, ascending=False)
# 排名
df.rank(ascending=False, method='min', na_option='keep')
# 分组
df.groupby('sex')
df.groupby(['sex', 'age'])
# 分组聚合
df.groupby('sex').agg(np.mean)
df.groupby('sex').apply(max)
df.groupby('sex').apply(lambda x: x['score'] + 1)
# 分组后取数据
df.groupby('code').first() # 分组后取每组第一次出现数据
df.groupby('code').last() # 分组后取每组最后一次出现数据
df.groupby('code').nth(0) # 分组后取每组第一行数据
df.groupby('code').nth(-1) # 分组后取每组最后一行数据
# 上下平移
s.shift(2)
df.shift(-1)
# 相邻两行求差
df.diff()
# 相差百分比
df.pct_change()
# 求分位点
df.quantile(0.75) # 类似numpy的 percentile()
# 堆叠
df.stack()
df.unstack()
# 条件赋值
df.where(condition, other) # 满足条件的值不动,不满足条件的赋予other
df.where(df > 0, 0)
df.mask(condition, other) # 不满足条件的值不动,满足条件的赋予other
df.mask(df >0, 0)
# 将某列切分成多列
# 比如,某一列数据是 "a,b,c" 这种字符串,要按照","切分成三列
df['codes'].str.split(',', 3, expand=True).rename(columns={0: 'A', 1: 'B', 2: 'C'})
# 等同于
df['codes'].str.split(',').explode()
# 将某列切分成多列后,如果只想去其中一列
df['codes'].str.split(',').str[0]
字符串操作
df.str
df.str.startswith('abc')
df.str.split('.')
df.str.replace('-', '_')
时间操作
df.dt
df.dt.date
df.dt.year
df.dt.strftime('%Y-%m-%d')
拼接
df1.append(df2) # 将df2的行添加到df1的尾部
pd.concat([df1, df2, df3])
df1.join(df2, on='code', how='inner')
df1.merge(df2, on='code', how='left')
df1.merge(df2, on=['code', 'datetime'], how='outer')
pd.merge(df1, df2, on='code', how='inner')
pd.merge(df1, df2, left_on='code', right_on='id')
reduce(lambda left, right: pd.merge(left, right, how='inner', on='code'), [df1, df2, df3]) # 批量按某规则merge
数据导入
df.read_sql(sql, con=engine)
df.read_csv(filepath, index=False, header=0)
数据导出
df.to_csv(filepath, index=False, header=False)
df.to_sql(table_name, con, if_exist='append', index=False)
数据统计
df.mean()
df.sum()
df.corr() # 返回列与列间的相关系数
df.count() # 返回每列中非空值的个数
df.max()
df.min()
df.median()
df.std() # 返回每列标准差
综合使用
# 按年分组,取每组最后一条记录,剔除日期时间列,截取去年数据,转为array
last = df.groupby(df['datetime'].apply(lambda x: x.year)).last().drop(['datetime'], axis=1).loc[idt[-1].year - 1].to_numpy()
# 分组排序
df['rank'] = df.groupby('type').apply(lambda x: x.sort_values(by='score', ascending=False)).reset_index(drop=True)
# 排名
# 分组后,对每组应用函数,新增列,列的值为依据score值进行排名所得结果,结果: 新增排名列,索引为复合索引
df.groupby('type').apply(lambda x: x.assign(rank=lamda x: x['score'].rank(ascending=False)))
df.groupby('type').apply(lambda x: x.assign(rank=lamda x: x['score'].rank(ascending=False)))['rank'].to_numpy()
# 比较另一种排名
df.index = code
df.index.name = 'code'
df1 = df.groupby('type').apply(lambda x: x['return'].rank(ascending=False)).reset_index()
df2 = pd.DataFrame(code, columns=['code'])
rank = df2.merge(df1.rename(columns={'return': 'rank'})[['code', 'rank']]) # 这样做是为了保证排名与code保持一致
# 可以直接使用
df.groupby('type').apply(lambda x: x['return'].rank(ascending=False)).reset_index()['return'].to_numpy()
# 为df新增一列 rank
df = df.groupby('type').apply(lambda x: x.assign(rank=lamda x: x['score'].rank(ascending=False))).reset_index()
分组
分组排名,并将排名的结果赋予给新的一列
df = df.groupby('type').apply(lambda x: x.assign(rank=lamda x: x['score'].rank(ascending=False))).reset_index()
时间
pandas数据类型转为datetime
pandas时间的默认数据类型是 datetime64[ns]
,并不是datetime
,可以通过下面操作将其数据类型转为datetime
df['datetime'].dt.to_pydatetime()
DataFrame某一列是列表,将其展开
变成
- 方法一
df = pd.DataFrame([['2020-01-01', '2020-01-02'], ['A', 'B'], [['001', '002', '003'], ['001', '004']], [[0.1, 0.3, 0.6], [0.2, 0.8]], columns=['datetime', 'code', 'component', 'weight'])
def unnesting(s):
len1, len2 = 0, 0
if isinstance(s['weight'], list):
len1 = len(s['weight'])
if isinstance(s['component'], list):
len2 = len(s['component'])
length = max(len1, len2)
if length <= 0:
return pd.DataFrame([], columns=['datetime', 'code', 'component', 'weight'])
return pd.DataFrame({
'datetime': np.repeat(s['datetime'], length),
'code': np.repeat(s['code'], length),
'component': s['component'],
'weight': s['weight']
})
s = df.apply(unnesting)
df = pd.concat(s.to_list())
- 方法二
def explode(df):
component = df['component'].apply(pd.Series).stack().reset_index().rename(columns={0: 'component'})
weight = df['weight'].apply(pd.Series).stack().reset_index().rename(columns={0: 'weight'})
tmp = pd.merge(component, weight, on=['level_0', 'level_1'], how='outer')
return df.drop(columns=['component', 'weight']).merge(tmp.drop(columns=['level_1']).set_index('level_0'), left_index=True, right_index=True)
如果只有一列为列表
# c列为列表
df.drop('c', axis=1).join(pd.DataFrame(list(df[col])).stack().reset_index(level=1, drop=True).rename('c'))
df.drop('c', axis=1).join(df['c'].apply(pd.Series).stack().reset_index(level=1, drop=True).rename('c'))
# 最简单的,利用pandas接口 explode
df['c'].explode()