pandas常用操作总结
常用操作
- pandas常用操作总结
pandas读取csv,txt,excel,mysql
import pandas as pd
fpath = './datas/ml-latest-small/ratings.csv'
# # 使用pd.read_csv读取数据
ratings = pd.read_csv(fpath, engine='python', encoding='utf-8')
# 设置txt文件的存储位置
fpath = './datas/crazyant/access_pvuv.txt'
txt_demo = pd.read_csv(
fpath,
sep='\t',
header=None,
names=['a','b','c']
)
txt_demo.head()
fpath = './datas/crazyant/access_pvuv.xlsx'
xlsx_demo = pd.read_excel(fpath, engine='python', encoding='utf-8')
xlsx_demo
# 读取mysql表里数据
from sqlalchemy import create_engine
engin = create_engine("mysql+mysqlconnector://root:123456@localhost:3306/rabbit_test?charset=utf8")
sql = '''select * from student'''
# 查询结果
df = pd.read_sql_query(sql, engin)
print(df)
pandas存入excel,mysql
# 将dataframe输出到excel,index=False表示去除索引列
df_merged.to_excel(f"splits_dir/merged_data.xlsx", index=False)
# 将dataframe输出到mysql表
# 新建pandas中DataFrame
data = {
'id': [17, 18, 19],
"name": ["yanxu", "shuaishuai", "xiaolong"],
"age": [20, 22, 23],
"class_id": [1, 2, 3]
}
engin = create_engine("mysql+mysqlconnector://root:123456@localhost:3306/rabbit_test?charset=utf8")
df = pd.DataFrame(data)
# 将新建的DataFrame储存为mysql中的数据表,index=True储存index列
# if_exists:
# 1.fail:如果表存在,啥也不做
# 2.replace:如果表存在,删了表,再建立一个新表,把数据插入
# 3.append:如果表存在,把数据插入,如果表不存在创建一个表!!
df.to_sql("student", engin, index=False, if_exists="append")
# 或者这种形式
# pd.io.sql.to_sql(df, "student", con=engin, index=False, if_exists="append")
print(df)
pandas数据结构常用操作
# 根据多个字典序列创建dataframe
data = {
'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'year': ['2018-03-11', '2018-03-12', '2018-03-13', '2018-03-14', '2018-03-15'],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]
}
df = pd.DataFrame(data)
# 查看每一列得类型
df.dtypes
# 查看列名
df.columns
# 查看索引
df.index
# 查看列计数
df["year"].value_counts()
# 查看数量
df.count()
# 判断是不是数字
df["state"].str.isnumeric()
# 使用str的startswith、contains等得到bool的Series可以做条件查询
condition = df["year"].str.startswith("2018-03")
# 删除某列
df.drop("state", axis=1)
# 单行drop,就是删除某一行
df.drop(1, axis=0)
# 将数据随机打散
from sklearn.utils import shuffle
df_shuffle = shuffle(df)
# 判断索引是否是递增的
df_shuffle.index.is_monotonic_increasing
# 判断索引是否是唯一的
res4 = df_shuffle.index.is_unique
# 获取行数
df.shape[0]
# 将columns列变成python的列表形式
df.columns.tolist()
'''
从DataFrame中查询出Series
如果只查询一行、一列,返回的是pd.Series
如果查询多行、多列,返回的是pd.DataFrame
'''
# 查询一列
df["year"]
# 查询多列,结果是一个pd.DataFrame
df[["year", "pop"]]
# 查询一行,结果是pd.Series
df.loc[1] # 超出行数会报错
# 查询多行,结果是pd.DataFrame
df.loc[1:3]
# 设定索引日期,方便日期筛选
df.set_index('year', inplace=True)
# 得到单个值(2018-01-03最高温度)
res = df.loc["2018-01-03", "bWendu"]
# 得到一个Series(2018-01-03最高温度和最低温度)
ret = df.loc["2018-01-03", ["bWendu", "yWendu"]]
# 值列表批量查询
s1 = df.loc[['2018-01-03', '2018-01-04', '2018-01-05'], 'bWendu']
s2 = df.loc[['2018-01-03', '2018-01-04', '2018-01-05'], ['bWendu', 'yWendu']]
# 值区间查询
# 行index按区间
s3 = df.loc['2018-01-03':'2018-01-05', 'bWendu']
# 列index按区间
s4 = df.loc['2018-01-03', 'bWendu':'fengxiang']
# 条件查询
s6 = df.loc[df["yWendu"] < -10, :]
# 查询最高温度小于30度,并且最低温度大于15度,并且是晴天,并且天气为优的数据
s7 = df.loc[(df["bWendu"] <= 30) & (df["yWendu"] >= 15) & (df["tianqi"] == '晴') & (df["aqiLevel"] == 1), :]
# 直接写lambda表达式查询
s8 = df.loc[lambda df: (df["bWendu"] <= 30) & (df["yWendu"] >= 15), :]
pandas增加数据列
# 直接赋值法
# 替换掉温度的后缀℃
df.loc[:, "bWendu"] = df["bWendu"].str.replace("℃", "").astype('int32')
df.loc[:, "yWendu"] = df["yWendu"].str.replace("℃", "").astype('int32')
# 计算温差
# 注意,df["bWendu"]其实是一个Series,后面的减法返回的是Series
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]
# df.apply方法
def get_wendu_type(x):
if x["bWendu"] > 33:
return '高温'
if x["yWendu"] < -10:
return '低温'
return '常温'
# 注意需要设置axis==1,这是series的index是columns
df.loc[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)
# 查看温度类型的计数
s1 = df["wendu_type"].value_counts()
# df.assign方法
# 可以同时添加多个新的列
df.assign(
# 新增的列名
yWendu_huashi=lambda x: x["yWendu"] * 9 / 5 + 32,
# 摄氏度转华氏度
bWendu_huashi=lambda x: x["bWendu"] * 9 / 5 + 32
)
# 按条件选择分组分别赋值
# 先创建空列(这是第一种创建新列的方法)
df['wencha_type'] = ''
df.loc[df["bWendu"] - df["yWendu"] > 10, "wencha_type"] = "温差大"
df.loc[df["bWendu"] - df["yWendu"] <= 10, "wencha_type"] = "温差正常"
pandas统计结果和排序
# 一下子提取所有数字列统计结果
df.describe()
# 查看单个Series的统计数据
res2 = df["bWendu"].mean() # 平均值
df["bWendu"].max() # 最大值
df["bWendu"].min() # 最小值
# 唯一去重
df["fengxiang"].unique()
# 按值计算
df["fengxiang"].value_counts()
# 协方差矩阵
df.cov()
# 相关系数矩阵
df.corr()
# 单独查看空气质量和最高温度的相关系数
df["aqi"].corr(df["bWendu"])
# 空气质量和温差的相关系数
df["aqi"].corr(df["bWendu"]-df["yWendu"])
# 数据排序
# 升序
df["aqi"].sort_values()
# 降序
df["aqi"].sort_values(ascending=False)
# 根据索引升序
df.sort_index(inplace=True)
# 单列排序
df.sort_values(by="aqi") # 升序
df.sort_values(by="aqi", ascending=False) # 降序
# 多列排序
# 按空气质量等级、最高温度排序,默认升序
df.sort_values(by=["aqiLevel", "bWendu"])
# 两个字段都是降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=False)
# 分别指定升序和降序
df.sort_values(by=["aqiLevel", "bWendu"], ascending=[True, False])
pandas缺失值和缺失日期处理
# 检测空值
studf.isnull()
# 检测分数这一列空值
studf["分数"].isnull()
# 检测不为空
studf["分数"].notnull()
# 筛选没有空分数的所有行
studf.loc[studf["分数"].notnull(), :]
# 删除掉全是空值的列
# inplace=True则修改当前df,否则返回新的df
studf.dropna(axis="columns", how='all', inplace=True)
# 删除掉全是空值的行
studf.dropna(axis="index", how='all', inplace=True)
# 将分数列为空的填充为0分
studf.fillna({"分数": 0})
# 等同于
studf.loc[:, '分数'] = studf['分数'].fillna(0)
# 将姓名的缺失值填充
# 使用前面的有效值填充,用ffill:forward fill
studf.loc[:, '姓名'] = studf['姓名'].fillna(method="ffill")
# 将日期列转换成pandas的日期
df.set_index(pd.to_datetime(df["ymd"]), inplace=True)
# 日期区间
df.loc['2018-01-05':'2018-01-10']
# 日期筛选
# 按月份前缀筛选
df.loc['2018-03']
# 获取周、月、季度
# 周数字列表
res6 = df.index.week
# 月数字列表
df.index.month
# 季度数字列表
df.index.quarter
# 统计每周最高温度
df.groupby(df.index.week)["bWendu"].max()
# 缺失时间索引的填充
# 使用pandas.reindex方法
# 将df的索引设置为日期索引
df_date = df_date.set_index(pd.to_datetime(df_date.index))
# 生成完整的日期序列
pdates = pd.date_range(start="2019-12-01", end="2019-12-05")
# 填充缺失索引,并填充默认值
df_date_new = df_date.reindex(pdates, fill_value=0)
# 使用pandas.resample方法
# 先将索引变成日期索引,并删除原先得pdate一列
df_new2 = df.set_index(pd.to_datetime(df["pdate"])).drop("pdate", axis=1)
# 由于采样会让区间变成一个值,所以需要指定mean等采样值的设定方法
df_new2 = df_new2.resample("D").mean().fillna(0)
# resample的使用方式(2D每隔两天,pv/uv是两天得平均值)
res12 = df_new2.resample("2D").mean()
pandas两个表对应关系Merge合并
# 语法
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=('x', 'y'), copy=True, indicator=False, validate=None)
# 评分表和用户表合并
df_ratings_users = pd.merge(
df_ratings, df_users, left_on="UserID", right_on="UserID", how="inner"
)
# one-to-one 一对一关系的merge
left = pd.DataFrame({'sno': [11, 12, 13, 14],
'name': ['name_a', 'name_b', 'name_c', 'name_d']
})
right = pd.DataFrame({'sno': [11, 12, 13, 14],
'age': ['21', '22', '23', '24']
})
# 一对一关系,结果中有4条
ret = pd.merge(left, right, on='sno')
# 如果出现非Key的字段重名怎么办
# _left为左表同名字段后缀
pd.merge(left, right, on='key', suffixes=('_left', '_right')
pandas两个字段相同的表合并concat
查看详情
语法
:pandas.concat(objs, axis=0, join='outer', ignore_index=False)
objs是个列表
ignore_indez是否忽略掉原来的数据索引
# 默认的concat,参数为axis=0、join=outer、ignore_index=False
res = pd.concat([df1, df2])
# 使用DataFrame.append按行合并数据
df1 = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
# 给1个dataframe添加另一个dataframe
# 忽略原来的索引ignore_index=True
res6 = df1.append(df2, ignore_index=True)
pandas拆分合并excel
# 使用df.iloc方法,将一个大的dataframe,拆分成多个小dataframe
# 拆分(begin起始行数,end结束行数)
df_sub = df_source.iloc[begin:end]
df_sub.to_excel(file_name, index=False)
# 使用pd.concat进行df批量合并
# 遍历文件夹,得到要合并的Excel名称列表
excel_names = list()
for excel_name in os.listdir("splits_dir"):
excel_names.append(excel_name)
# 分别读取到dataframe
df_list = list()
for excel_name in excel_names:
excel_path = f"splits_dir/{excel_name}"
df_split = pd.read_excel(excel_path)
# 得到username
username = excel_name.replace("crazyant_blog_articles_", "").replace(".xlsx", "")[2:]
# 给每一个df添加1列
df_split["username"] = username
df_list.append(df_split)
# 使用pd.concat进行合并
df_merged = pd.concat(df_list)
# 将合并后的dataframe输出到excel
df_merged.to_excel(f"splits_dir/merged_data.xlsx", index=False)
pandas分组操作groupby
# 单个列groupby,查询所有数据列的统计
res = df.groupby('A').sum()
# 多个列groupby,查询所有数据列的统计
res2 = df.groupby(["A", "B"]).mean()
df.groupby(['A','B'], as_index=False).mean()
# 同时查看多种数据统计
res4 = df.groupby('A').agg([np.sum, np.mean, np.std])
# 查看单列的结果数据统计
# 方法1:根据A列分组,查看C列的求和,平均数,标准偏差
df.groupby('A')['C'].agg([np.sum, np.mean, np.std])
# 方法2
df.groupby('A').agg([np.sum, np.mean, np.std])['C']
# 不同列使用不同的聚合函数
df.groupby('A').agg({"C":np.sum, "D":np.mean})
分组后应用apply
# 用户对电影评分的归一化
# 实现按照用户ID分组,然后对其中一列归一化
def ratings_norm(df):
"""
@param df:每个用户分组的dataframe
"""
min_value = df["Rating"].min()
max_value = df["Rating"].max()
df["Rating_norm"] = df["Rating"].apply(
lambda x: (x - min_value) / (max_value - min_value))
return df
ratings = df_ratings.groupby("UserID").apply(ratings_norm)
res = ratings[ratings["UserID"] == 1].head()
# 每个月最高温度的两天
def getWenduTopN(df, topn):
"""
这里的df,是每个月份分组group的df
"""
# 根据最高温度排序,取日期和温度,默认是升序,所以取最后两个
return df.sort_values(by="bWendu")[["ymd", "bWendu"]][-topn:]
# 根据月份分组
res2 = df.groupby("month").apply(getWenduTopN, topn=2).head()
pandas替换数据函数map、apply、applymap
# 公司股票代码到中文的映射,注意这里是小写
dict_company_names = {
"bidu": "百度",
"baba": "阿里巴巴",
"iq": "爱奇艺",
"jd": "京东"
}
# map用于Series值的转换
# 方法一:Series.map(dict)
stocks["公司中文1"] = stocks["公司"].str.lower().map(dict_company_names)
# 方法2:Series.map(function)
stocks["公司中文2"] = stocks["公司"].map(lambda x: dict_company_names[x.lower()])
# apply用于Series和DataFrame的转换
stocks["公司中文3"] = stocks["公司"].apply(lambda x: dict_company_names[x.lower()])
# DataFrame.apply(function),function的参数是对应轴的Series
stocks["公司中文4"] = stocks.apply(
lambda x: dict_company_names[x["公司"].lower()],
axis=1)
# applymap用于DataFrame所有值的转换
# 将所有价格变成整型
sub_df = stocks[['收盘', '开盘', '高', '低', '交易量']]
# 将这些数字取整数,应用于所有元素
sub_df.applymap(lambda x : int(x))
# 直接修改原df的这几列
stocks.loc[:, ['收盘', '开盘', '高', '低', '交易量']] = sub_df.applymap(lambda x : int(x))
pandas实现指定列后面新增两列
# 实现两个表的关联
# 之筛选学生信息表的少量的列
df_sinfo = df_sinfo[["学号", "姓名", "性别"]]
# 合并两个表
df_merge = pd.merge(left=df_grade, right=df_sinfo, left_on="学号", right_on="学号")
# 将columns变成python的列表形式
new_columns = df_merge.columns.tolist()
# 按逆序insert,会将"姓名","性别"放到"学号"的后面
for name in ["姓名", "性别"][::-1]:
new_columns.remove(name)
# 将需要添加的列添加到学号这一列的后面
new_columns.insert(new_columns.index("学号")+1, name)
'''
['班级', '学号', '姓名', '性别', '语文成绩', '数学成绩', '英语成绩']
'''
# 按照新的列组合
df_merge = df_merge.reindex(columns=new_columns)