一、提要
pandas对于处理表格类数据来说是非常方便的模块,同时也是做数据分析绕不开的第三方库。这里将工作中常用到的各种处理方法记录下来
二、常用方法
接下来的以 df 表示我们要处理的 dataframe 表格数据
1、取值
# 循环遍历取值
for i in range(len(df)):
yh_bm = df.iloc[i]['yh_bm']
cp_name = df.iloc[i]['cp_name']
可以通过循环将该表所有编码,名称全部依次取出
# 下面这两个写法效果相同,都是取第几行第几列的那个值
jz_date = df.iloc[i][num]
jz_date = df.iloc[i,num]
# 取行名为 合计,列名为 穿透前金额 的值
df = df[df.values == '合计']['穿透前金额'].values[0]
# 定位取值
cp_name = df.loc[df['yh_bm'] =='345634A', 'cp_name'].values[0]
print(cp_name)
意思是取 yh_bm 这一列中,值为 345634A 的这一行中 cp_name 的值。其中values是将所有符合条件的值都取出来,列表形式。values[0]即是取第一个符合条件的值。
2、切片
# 总行数
z_ls=df.shape[0]
# 总列数
con1 = df.shape[1]
# 获取前10行
con=df.loc[:10]
# 取所有行中第一到二列
data=df.iloc[:,1:2]
3、删除Pandas DataFrame中的某些字段
import pandas as pd
# 创建一个示例DataFrame
data = {'A': [1, 2, 3],
'B': [4, 5, 6],
'C': [7, 8, 9]}
df = pd.DataFrame(data)
# 删除字段B和C
df = df.drop(['B', 'C'], axis=1)
# 打印结果
print(df)
A
0 1
1 2
2 3
4、获取索引
# 取出所有值为‘估值日’对应的索引行,列表形式展示
df = df[df.values == '估值日'].index.values.tolist()
5、判断并赋值
# 查询并赋值(如果id字段为'',产品状态赋值为新增)
df.loc[df['id'] == '', '产品状态'] = '新增'
# 如果id字段为'',产品状态赋值为新增,否则产品状态赋值为已存在。
df['产品状态'] = df.id.apply(lambda x: '新增' if x=='' else '已存在')
# 将 实际到期日<库内实际到期日 的各行数据,是否提前终止 字段值改为是
df.loc[df['实际到期日'] < df['库内实际到期日'], '是否提前终止'] = '是'
# 将 净值日期大于等于2022/8/24并且beizhu字段值为1的数据, 净值分配类型 字段值改为 扣除超额收益
df.loc[(df['净值日期'] >= datetime.datetime(2022, 8, 24)) & (df['beizhu'] == '1'), '净值分配类型'] = '扣除超额收益'
6、取某字段内包含某字段值的数据
# 取产品全称字段内包含备注字段值的数据
df=df[df.apply(lambda x: x.beizhu in x.产品全称, axis=1)]
输入:
产品全称 beizhu
中国 中
中国 国
中国 年
输出:
产品全称 beizhu
0 中国 中
1 中国 国
7、日期格式处理
# 净值日期减一天
df['净值日期'] = pd.to_datetime(df['净值日期'], errors='coerce') - pd.Timedelta('1 days')
# pandas日期相减,算出投资期限
df = df['投资结束日'].apply(pd.to_datetime) - df['投资开始日'].apply(pd.to_datetime)
df['投资期限'] = df.apply(lambda x: x.days)
# 如取最新的一百条成立公告(通过创建日期、公告日期排序,取前100条)ascending决定正序倒序
df = df.sort_values(by=['create_time', 'announcement_date'], ascending=False)[:100]
# 将trading_date列转为字符串类型
df['trading_date'] = df['trading_date'].astype(str)
# 取trading_date列中时间大于等于某个日期的行
con1= df['trading_date'] >= xz_start_date
# 取trading_date列中时间小于某个日期的行
con2 = df['trading_date'] < xz_end_date
# 将trading_date、xz_start_date字段转为时间格式,转换失败的填充null
df['trading_date'] = pd.to_datetime(df['trading_date'], errors='coerce')
df['xz_start_date'] = pd.to_datetime(df['xz_start_date'], errors='coerce')
# 取日期列 xz_start_date < trading_date 的表格内容
df=df[df['xz_start_date']<df['trading_date']]
8、去重
# 去重 subset决定通过哪些字段去重 keep表示保留哪一条(first,last是表示第一条或最后一条。而false则表示不保留) inplace表示是否改变源表
paimingdata1.drop_duplicates(subset=['产品id', '报告期', '持仓资产名称', '资产规模', '资产占比'], keep='first',inplace=True)
9、模糊取值
# 取某字段下存在某些字符的df
df = df[df['title'].str.contains('2021年第4季度报告|投资非标资产情况公告')]
即取title列中,值包含‘2021年第4季度报告’或‘投资非标资产情况公告’的表格内容
例:
输入
title date
中国银行2021年第4季度报告 2020/11/11
中国银行投资非标资产情况公告 2020/11/12
中国银行净值报告 2020/11/13
输出
title date
中国银行2021年第4季度报告 2020/11/11
中国银行投资非标资产情况公告 2020/11/12
10、从一个表里删除另一个表某字段已包含的表格
# ~表示取反 即不取 df_A产品全称字段 内包含 df_B产品全称字段值的内容
df_A = df_A[~df_A['产品全称'].isin(df_B['产品全称'])]
语言不好描述,看例子:
输入df_A:
产品全称 date
工银理财·鑫尊享 2023/3/3
工银理财·全鑫权益 2023/3/4
工银理财·全球臻选 2023/3/5
工银理财·"全鑫权益 2023/3/6
工银理财·核心优选私银 2023/3/7
工银理财·恒睿睿益 2023/3/8
工银理财·A 2023/3/9
工银理财·B 2023/3/10
工银理财·C 2023/3/11
工银理财 2023/3/12
输入df_B:
产品全称 date
工银理财·鑫尊享 2023/3/3
工银理财·全鑫权益 2023/3/4
工银理财·全球臻选 2023/3/5
工银理财·"全鑫权益 2023/3/6
工银理财·核心优选私银 2023/3/7
工银理财·恒睿睿益 2023/3/8
输出:
产品全称 date
6 工银理财·A 2023-03-09
7 工银理财·B 2023-03-10
8 工银理财·C 2023-03-11
9 工银理财 2023-03-12
11、填充、平移
# 向上填充,可选择method = 'bfill‘
# 向下填充,可选择method = 'ffill‘
df['产品名称'] = df['产品名称'].fillna(method='ffill')
df['融资客户名称'] = df['融资客户名称'].fillna(method='ffill')
#-1 向上平移一格
# 1 向下平移一格
df['产品名称_'] = df['产品名称'].shift(-1)
df['融资客户名称_'] =df['融资客户名称'].shift(1)
12、分组填充
# 即 通过'净值日期'和'银行产品编码'分组,上下填充'7日年化收益率'和'万份收益'的值
jzdata2[['7日年化收益率', '万份收益']] = jzdata2.groupby(['净值日期', '银行产品编码'])[['7日年化收益率', '万份收益']].ffill()
jzdata2[['7日年化收益率', '万份收益']] = jzdata2.groupby(['净值日期', '银行产品编码'])[['7日年化收益率', '万份收益']].bfill()
13、循环截取
当遇到上面这个表格内容的时候,该怎么将这一个表分成4个表呢
# 重置索引
leibie_df = df.reset_index(drop=True)
# 取出 产品全称 所在的所有索引
leibie_df_index = leibie_df[leibie_df.values == '产品全称'].index.values.tolist()
print(leibie_df_index)
# 获取索引数量
len_list = len(leibie_df_index)
num = 0
# 循环索引数量次数(有几个索引就循环几次,即有几个产品全称,就循环几次)
for x in range(len_list):
num += 1
# 如果此时循环次数==索引数量-1 即最后一次循环
if x == len_list - 1:
# 截取出来的小表格范围为 最后一个产品全称 所在的索引行 到最后
result_df = df[leibie_df_index[x]:]
else:
y = x + 1
# 截取出来的小表格范围为 一个产品全称 所在的索引行 到 另一个产品全称 所在的索引行
result_df = df[leibie_df_index[x]:leibie_df_index[y]]
# 将取出来的小表格重置索引
result_df=leibie_df1.reset_index(drop=True)
14、其他常用方法
# 取反(剔除)
# 剔除 产品ID值为1256249 并且 净值日期为2020-05-28的数据
df = df[~(df['产品ID'].isin([1256249]) & df['净值日期'].isin(['2020-05-28']))]
# 删除净值日期列是空值的行
df.dropna(subset=['净值日期'], inplace=True)
# 通过取反 剔除'产品全称'里是空值的行
df=df[~df['产品全称'].isin([''])]
# 重置行索引
df = df.reset_index(drop=True)
#重置列索引
df=df.T.reset_index(drop=True).T
# 删除name、age列中,【任一列值为空】的行;
df.dropna(subset=['name', 'age'],
axis=0, # axis=0表示删除行;
how='any', # how=any表示若任一列出现空值,就删掉该行
inplace=True # inplace=True表示在原df上进行修改;
)
# 删除name、age列中,二者都为空的行。
# 删除都为空的行,还是删除任一列值为空的行,使用参数how来控制
df.dropna(subset=['name', 'age'],
axis=0,
how='all', # how='all'表示指定列的值都为空,就删掉该行
inplace=True)
# 处理重复列名(相同列名,对应值不同,则将列名改名)
column_names = df.columns.values
column_names[2] = 'Changed'
df.columns = column_names
print(column_names)
# 删除重复列名(几列值完全相同)
df = df[df.columns].T.drop_duplicates().T
#处理特殊字符 如\n \r 空格
df = df.applymap((lambda x: "".join(x.split()) if type(x) is str else x))
# 批量模糊匹配剔除
# 剔除'项目名称'字段中包含'', '-', '—', '-', '0', '0.0', '0.00'的数据
df = df[~df['项目名称'].isin(['', '-', '—', '-', '0', '0.0', '0.00'])]
# 修改列名
df = df.rename(columns={'份额净值': '当日账面净值', '日期': '净值日期', '七日年化收益率': '7日年化收益率'})
或
df.rename(columns={'份额净值': '当日账面净值', '日期': '净值日期', '七日年化收益率': '7日年化收益率'},inplace=Ture)
house_info = pd.read_csv('house_info.csv')
1:取行的操作:
house_info.loc[3:6]类似于python的切片操作
2:取列操作:
house_info['price'] 这是读取csv文件时默认的第一行索引
3:取两列
house_info[['price','tradetypename']] 取多个列也是同理的,注意里面是一个list的列表,不然会报错误;
4:增加列:
house_Info['adress_new']=list([.....]) 跟字典的操作有点类似;
5:对某一列除以他的最大值,这样可以得到一个0,1的数值范围,也就是一个简易的归一化操作;
house_info['price']/house_info['price'].max()
6:对列进行排序操作:
qianshi_df.sort_values(by=['资产占比排名'], inplace=True, ascending=True) 这里的inplace表示再排序的时候是否生成一个新的dataframe 结构,ascending=true表示升序,默认也是升序;还有一点应该注意的是:对于缺省值,(Nan)排序的时候会把他排在末尾;
7:如何获取缺省值,:
column_null = pd.isnull(column)
column_is_null_true = column[column_null]
# pandas对列求和
import pandas as pd
datas = [
{'学生': '小红', '语文': None, '数学': 89.5, '英语': 99, '物理':70, 'active': False},
{'学生': '小明', '语文': 88, '数学': 89.5, '英语': 99, '物理':70, 'active': True},
{'学生': '小玉', '语文': 78.5, '数学': 79.5, '英语': 92.5, '物理':78, 'active': True},
{'学生': '小刚', '语文': 60, '数学': 59.5, '英语': 87, '物理':None, 'active': False},
]
sum = dict(pd.DataFrame(datas).drop(columns=['学生']).fillna(0).apply(lambda x: round(x.sum(), 2) if all(isinstance(d, (int, float)) and not isinstance(d, bool) for d in x) else ''))
print(sum)
输出:
{'语文': 226.5, '数学': 318.0, '英语': 377.5, '物理': 218.0, 'active': ''}
先将数据转成二维数组,然后排除掉不想求和的列,使用0填充nan值,然后对每一列进行遍历,判断每一个元素是否为int或float型,并且不为布尔型,然后使用sum函数对列求和。