pandas常用tips

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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值