Loading

Pandas学习笔记

Pandas

Pandas的命名来自于面板数据这个概念,即Panel datas

一些注意事项

  • drop和take的0是行1是列,其他的1是行0是列

  • Pandas 可以像数据库一样query df.query('order_amount <= 1000')

  • 知识点:DataFrame的applyapplymap的区别

    • applymap:返回df
    • 将函数做用于DataFrame中的所有元素(elements)
    • apply:返回Series
    • apply()将一个函数作用于DataFrame中的每个行或者列
    • 读取xlsx文件df = pd.read_excel('./datasets/my_films.xlsx',engine='openpyxl') 注意这个最后是小写L
  • 统计每个用户每个月的消费次数

    这个透视表pivot_table,可以顺便填上空白值,以及统计方法aggfunc

bb = df.pivot_table(index='user_id',values='order_product',aggfunc='count',columns='month',fill_value=0)
  • 绘图特别简单。在后面加上plot(kind='xxx')就行了

实训课一、DataFrame初始化

0. 利用字典创建

data={"one":np.random.randn(4),"two":np.linspace(1,4,4),"three":['zhangsan','李四',999,0.1]}
df=pd.DataFrame(data,index=[1,2,3,4])
set _index用于将df中的一行或多行设置为索引。
df.set_index(['one'],drop=False)
df.set_index(['one','two'])
参数drop默认为True,意为将该列设置为索引后从数据中删除,如果设为False,将继续在数据中保留该行。

如果要设置的索引不在数据中,可以df.index=['a','b','c','d']
df.reset_index(drop=True)
参数drop默认值为False,意为将原来的索引做为数据列保留,如果设为True,原来的索引会直接删除。

02 利用数组创建

data=np.random.randn(6,4)#创建一个6行4列的数组
df=pd.DataFrame(data,columns=list('ABCD'),index=[1,2,'a','b','2006-10-1','第六行'])

03 创建一个空DataFrame

pd.DataFrame(columns=('id','name','grade','class'))

实训课二、DataFrame的级联and合并操作

匹配级联 concat, append——直接拼接两个表

df1 = DataFrame(data=np.random.randint(0,100,size=(4,3)),columns=['A','B','C'])
df2 = DataFrame(data=np.random.randint(0,100,size=(4,4)),columns=['A','B','C','D'])
pd.concat((df1,df1),axis=0) #竖着合并df1,df1
pd.concat((df1,df2),axis=0) #竖着合并df1,df2 不存在的数据填充NaN,默认outer
pd.concat((df1,df2),axis=0,join='inner') #竖着合并df1,df2,不存在的那一列直接删掉
df1.append(df2) #默认竖着合并两个表,若无法对应则填Nan,默认outer

合并操作 merge ——通过某一列将两个表连接起来

一对一合并

#df1,df2共有employee这个属性,且每个属性均只出现有且只有一次
pd.merge(df1,df2,on='employee')  #通过'employee'这个表连接两个表

一对多合并

#df3,df4共有group这个属性,会把group属性相同的所有行进行全连接,也就是若df3的group的Accounting属性有3个,df4的Accounting属性有2个,最终表的Accounting属性有6个
pd.merge(df3,df4,on='group')

多对多连接

#df1,df5,有一列有相同的属性,然后左连接是,左边那个表全部保留,遍历右边的表,若存在与之对应的,则新表增加一行,若不存在,则将不存在的属性赋值为Nan
pd.merge(df1,df5,how='right')
pd.merge(df1,df5,how='left')

当两张表没有可进行连接的列时,可使用left_on和right_on手动指定merge中左右两边的哪一列列作为连接的列

pd.merge(df1,df5,left_on='employee',right_on='name')  #左表的employee和右表的name进行连接

实训课三、高级操作

替换 replace

df.replace(to_replace=0,value='zero')   #把0值全部替换成zero
df.replace(to_replace={5:'five'})		#把5值全部替换成five
df.replace(to_replace={2:6,3:5},value='five') #把第2列的6和第3列的5全部变成five

映射 map

dic = {
    'zhangsan':"jay",
    'lisi':'tom',
    'wangwu1':'jerry'
}
df['e_name'] = df['name'].map(dic)  #dic是字典


def after_sal(s):
    return s-(s-3000)*0.5
df['after_sal'] = df['salary'].map(after_sal) #这里的map可以写成apply,apply远比map高

随机抽样 take, permutation

df = pd.DataFrame(data=np.random.random(size=(100,4)),columns=['A','B','C','D'])  #随机生成100*4
df.take(indices=np.random.permutation(4),axis=1) #0行,1列 把列随机替换
df.take(indices=np.random.permutation(4),axis=1).take(indices=np.random.permutation(100),axis=0)[:20] #先列随机,再行随机,再取前20个

数据分组聚合

df = pd.DataFrame({'item':['Apple','Banana','Orange','Banana','Orange','Apple'],
                'price':[4,3,3,2.5,4,2],
               'color':['red','yellow','yellow','green','green','green'],
               'weight':[12,20,50,30,20,44]})


df.groupby(by='item').groups #groups返回分组结果
df.groupby(by='item').mean() #mean聚合操作只会对数值型的数据进行聚合
df.groupby(by='item').mean()['price'] #先分组、聚合,再提取某列
df.groupby(by='item')['price'].mean() #先分组、提取某列,再聚合

dic = mean_price_s.to_dict()	#series转字典
df['mean_price'] = df['item'].map(dic) #字典再映射回去

def myMean(p):
    sum = 0
    for i in p:
        sum += i
    return sum / len(p)
#transform 有多少行返回多少行,分组之后,每个值都会代回去原来那行
df.groupby(by='item')['price'].transform(myMean)
#apply 返回分组的结果,如果需要代回去,还需要变成dict 然后 map。不如直接transform
df.groupby(by='item')['price'].apply(myMean)

透视表

透视表像是直接帮你分组

#直接将对手和主客场做一个分组,默认求均值,然后有三列
df.pivot_table(index=['主客场','胜负'],values=['得分','篮板','助攻'])
df.pivot_table(index=['主客场','胜负'],values=['得分','篮板','助攻'],aggfunc='sum')	# 全做求和
df.pivot_table(index=['主客场','胜负'],aggfunc={'得分':'sum','篮板':'max'}) 			  #得分求和,篮板求最大值

#获取所有队主客场的总得分
df.pivot_table(index=['主客场'],values='得分',aggfunc='sum')
#查看主客场下的总得分的贡献各是多少
df.pivot_table(index=['主客场'],values='得分',aggfunc='sum',columns='对手',fill_value=0)

交叉表

#交叉表更像是,给定index 和 column,然后汇总

pd.crosstab(index=df.smoke,columns=df.sex) 	#求出各个性别抽烟的人数
pd.crosstab(df.age,df.smoke)				#求出各个年龄段抽烟人情况

一、引入模块

将pandas作为第三方库导入,我们一般为pandas取一个别名叫做pd

import pandas as pd 

二、导入数据

df = pd.read_csv(
    # 该参数为数据在电脑中的路径,可以不填写
    filepath_or_buffer='/Users/Weidu/Desktop/sz000002.csv',
    # 该参数代表数据的分隔符,csv文件默认是逗号。其他常见的是'\t'
    sep=',',
    # 该参数代表跳过数据文件的的第1行不读入
    skiprows=1,
    # nrows,只读取前n行数据,若不指定,读入全部的数据
    nrows=15,
    # 将指定列的数据识别为日期格式。若不指定,时间数据将会以字符串形式读入。一开始先不用。
    # parse_dates=['交易日期'],
    # 将指定列设置为index。若不指定,index默认为0, 1, 2, 3, 4...
    # index_col=['交易日期'],
    # 读取指定的这几列数据,其他数据不读取。若不指定,读入全部列
    usecols=['交易日期', '股票代码', '股票名称', '收盘价', '涨跌幅', '成交量', '新浪概念', 'MACD_金叉死叉'],
    # 当某行数据有问题时,报错。设定为False时即不报错,直接跳过该行。当数据比较脏乱的时候用这个。
    error_bad_lines=False,
    # 将数据中的null识别为空值
    na_values='NULL',
    header = None  #把第一行也作为数据都进来,就把header设置为None
)

三、查看数据常用操作

print(df.shape) 	# 输出dataframe有多少行、多少列。
print(df.shape[0])	# 取行数量,相应的列数量就是df.shape[1]
print(df.columns) 	# 顺序输出每一列的名字,演示如何for语句遍历。
print(df.index) 	# 顺序输出每一行的名字,可以for语句遍历。
print(df.dtypes) 	# 数据每一列的类型不一样,比如数字、字符串、日期等。该方法输出每一列变量类型
print(df.head(3))  	# 看前3行的数据,默认是5。与自然语言很接近
print(df.tail(3))  	# 看最后3行的数据,默认是5。
print(df.sample(n=3)) 	# 随机抽取3行,想要去固定比例的话,可以用frac参数
print(df.describe()) 	# 非常方便的函数,对每一列数据有直观感受;只会对数字类型的列有效

四、DataFrame太大,输出修正

pd.set_option('expand_frame_repr', False)  	# 当列太多时不换行
pd.set_option('max_colwidth', 8) 			
# 设定每一列的最大宽度,恢复原设置的方法,pd.reset_option('max_colwidth')

五、选取指定列

df['股票代码']  			  #根据列名称来选取,读取的数据是Series类型
df[['股票代码', '收盘价']]		#同时选取多列,需要两个括号,读取的数据是DataFrame类型
df[[0, 1, 2]]  				 #也可以通过列的position来选取

六、loc操作 显式索引读取数据

df.loc['12/12/2016'] 				# 选取指定的某一行,读取的数据是Series类型
df.loc['13/12/2016': '06/12/2016']  # 选取在此范围内的多行,和在list中slice操作类似,读取的数据是DataFrame类型

df.loc[:, '股票代码':'收盘价'] 		# 选取在此范围内的多列,读取的数据是DataFrame类型
df.loc['13/12/2016': '06/12/2016', '股票代码':'收盘价']  
									# 读取指定的多行、多列。逗号之前是行的范围,逗号之后是列的范围。读取的数据是DataFrame类型

df.loc[:, :]  						 # 读取所有行、所有列,读取的数据是DataFrame类型
df.at['12/12/2016', '股票代码']  	  # 使用at读取指定的某个元素。loc也行,但是at更高效。

七、iloc操作 隐式索引读取数据

df.iloc[0] 			# 以index选取某一行,读取的数据是Series类型
df.iloc[1:3] 		# 选取在此范围内的多行,读取的数据是DataFrame类型
df.iloc[:, 1:3] 	# 选取在此范围内的多列,读取的数据是DataFrame类型
df.iloc[1:3, 1:3]  	# 读取指定的多行、多列,读取的数据是DataFrame类型
df.iloc[:, :]  		# 读取所有行、所有列,读取的数据是DataFrame类型
df.iat[1, 1]  		# 使用iat读取指定的某个元素。使用iloc也行,但是iat更高效。

八、增加列,列运算

行列加减乘除

print(df['股票名称'] + '_地产')  	  # 字符串列可以直接加上字符串,对整列进行操作
print(df['收盘价'] * 100)  	    # 数字列直接加上或者乘以数字,对整列进行操作。
print(df['收盘价'] * df['成交量'])  # 两列之间可以直接操作。收盘价*成交量计算出的是什么?

新增一列

df['股票名称+行业'] = df['股票名称'] + '_地产'

九、统计函数,计量函数

print(df['收盘价'].mean())  	# 求一整列的均值,返回一个数。会自动排除空值。
print(df['收盘价'].max())  	# 最大值
print(df['收盘价'].min())  	# 最小值
print(df['收盘价'].std())  	# 标准差
print(df['收盘价'].count())  	# 非空的数据的数量
print(df['收盘价'].median())  	# 中位数
print(df['收盘价'].quantile(0.25))  # 25%分位数

十、shift类函数、删除列的方式

df['昨天收盘价'] = df['收盘价'].shift(-1)  # 读取上一行的数据,若参数设定为3,就是读取上三行的数据;若参数设定为-1,就是读取下一行的数据;

df['涨跌'] = df['收盘价'].diff(-1)  # 求本行数据和上一行数据相减得到的值

df.drop(['涨跌'], axis=1, inplace=True)  # 删除某一列

df['涨跌幅_计算'] = df['收盘价'].pct_change(-1)  # 类似于diff,但是求的是两个数直接的比例,相当于求涨跌幅

十一、cum(cumulative)类函数

df['成交量_cum'] = df['成交量'].cumsum()  # 该列的累加值
df[['成交量', '成交量_cum']]
(df['涨跌幅'] + 1.0).cumprod()  # 该列的累乘值,此处计算的就是资金曲线,假设初始1元钱。

十二、其他列函数rank,value_counts

df['收盘价_排名'] = df['收盘价'].rank(ascending=True, pct=False)  # 输出排名。ascending参数代表是顺序还是逆序。pct参数代表输出的是排名还是排名比例

print(df['股票代码'].value_counts())  # 计数。统计该列中每个元素出现的次数。返回的数据是Series

十三、筛选操作,根据指定的条件,筛选出相关拿数据

#dataFrame 可以通过布尔矩阵来选中值,所以就很帅。
s1 = df['ma5'] < df['ma30']
s2 = df['ma5'] > df['ma30']
death_dt = df.loc[s1 & s2.shift(1)].index 		#死叉
golden_dt = df.loc[~(s1 | s2.shift(1))].index	#金叉

十四、缺失值处理:原始数据中存在缺失值,如何处理?

查询缺失值

df.isnull().any(axis=1) 	#any可以检测df中的true和false的分布,如果行/列中只要存在一个true,则any就会返回true   这里返回布尔矩阵,对于每一行,只要存在一个True,则返回True,大小是行数

df.isnull()		#空则True
df.notnull()	#非空则True
df.notnull().all(axis=1)	#对每一行,若全部非空,则True
df.isnull().any(axis=1)		#对每一行,若存在一个非空,则True

df.dropna(axis=0) 		#删除空值所在行
df.fillna(value=666)	#空值填充666
df.fillna(axis=1,method='bfill') #空值用行的方式,用后一个填充前面的

df.isnull().any(axis=1).sum() 	#求和看看有多少行是存在空值的

for col in df.columns:			#循环把每个空值填充为该列的平均值
    if df[col].isnull().sum() > 0:
        #df[col]列中存在空值
        mean_value = df[col].mean()
        df[col].fillna(value=mean_value,inplace=True)

十五、排序函数

df.reset_index(inplace=True)
df.sort_values(by=['交易日期'], ascending=1)  # by参数指定按照什么进行排序,acsending参数指定是顺序还是逆序,1顺序,0逆序
df.sort_values(by=['股票名称', '交易日期'], ascending=[1, 1])  # 按照多列进行排序

十六、两个df上下合并操作,append操作

df.reset_index(inplace=True)
df1 = df.iloc[0:10][['交易日期', '股票代码', '收盘价', '涨跌幅']]
df2 = df.iloc[5:15][['交易日期', '股票名称', '收盘价', '涨跌幅']]

df1.append(df2)
df3 = df1.append(df2, ignore_index=True)  # ignore_index参数,用户重新确定index

十七、对数据进行去重drop_duplicates

#df3中有重复的行数,我们如何将重复的行数去除?
df3.drop_duplicates(
    subset=['收盘价', '交易日期'],  # subset参数用来指定根据哪类类数据来判断是否重复。若不指定,则用全部列的数据来判断是否重复
    keep='first',  # 在去除重复值的时候,我们是保留上面一行还是下面一行?first保留上面一行,last保留下面一行,False就是一行都不保留
    inplace=True
)

十八、其他常用重要函数 rename, empty, T转置

print(df.rename(columns={'MACD_金叉死叉': '金叉死叉', '涨跌幅': '涨幅'}))  # rename函数给变量修改名字。使用dict将要修改的名字传给columns参数
print(df.empty)  # 判断一个df是不是为空,此处输出不为空
print(pd.DataFrame().empty)  # pd.DataFrame()创建一个空的DataFrame,此处输出为空
print(df.T)  # 将数据转置,行变成列,很有用

十九、字符串处理

print(df['股票代码'])
print('sz000002'[:2])
print(df['股票代码'].str[:2])
print(df['股票代码'].str.upper())  # 加上str之后可以使用常见的字符串函数对整列进行操作
print(df['股票代码'].str.lower())
print(df['股票代码'].str.len())  # 计算字符串的长度,length
df['股票代码'].str.strip()  # strip操作,把字符串两边的空格去掉
print(df['股票代码'].str.contains('sh'))  # 判断字符串中是否包含某些特定字符
print(df['股票代码'].str.replace('sz', 'sh'))  # 进行替换,将sz替换成sh

split操作

print(df['新浪概念'].str.split(';'))  # 对字符串进行分割
print(df['新浪概念'].str.split(';').str[:2])  # 分割后取第一个位置
print(df['新浪概念'].str.split(';', expand=True))  # 分割后并且将数据分列

二十、时间处理

导入数据时将index参数注释掉
df['交易日期'] = pd.to_datetime(df['交易日期'])  # 将交易日期由字符串改为时间变量
print(df['交易日期'])
print(df.iloc[0]['交易日期'])
print(df.dtypes)
print(pd.to_datetime('1999年01月01日')) # pd.to_datetime函数:将字符串转变为时间变量
print(df.at[0, '交易日期'])
print(df['交易日期'].dt.year)  # 输出这个日期的年份。相应的month是月份,day是天数,还有hour, minute, second
print(df['交易日期'].dt.week)  # 这一天是一年当中的第几周
print(df['交易日期'].dt.dayofyear)  # 这一天是一年当中的第几天
print(df['交易日期'].dt.dayofweek) # 这一天是这一周当中的第几天,0代表星期一
print(df['交易日期'].dt.weekday)  # 和上面函数相同,更加常用
print(df['交易日期'].dt.weekday_name)  # 和上面函数相同,返回的是星期几的英文,用于报表的制作。
print(df['交易日期'].dt.days_in_month)  # 这一天是这一月当中的第几天
print(df['交易日期'].dt.is_month_end)  # 这一天是否是该月的开头,是否存在is_month_end?
print(df['交易日期'] + pd.Timedelta(days=1))  # 增加一天,Timedelta用于表示时间差数据
print((df['交易日期'] + pd.Timedelta(days=1)) - df['交易日期'])  # 增加一天然后再减去今天的日期

二十一、rolling、expanding操作

#计算'收盘价'这一列的均值
print(df['收盘价'].mean())

#如何得到每一天的最近3天收盘价的均值呢?即如何计算常用的移动平均线?
#使用rolling函数
df['收盘价_3天均值'] = df['收盘价'].rolling(5).mean()

#rolling(n)即为取最近n行数据的意思,只计算这n行数据。后面可以接各类计算函数,例如max、min、std等
print(df['收盘价'].rolling(3).max())
print(df['收盘价'].rolling(3).min())
print(df['收盘价'].rolling(3).std())

rolling可以计算每天的最近3天的均值,如果想计算每天的从一开始到至今为止的均值,应该如何计算?

#使用expanding操作
df['收盘价_至今均值'] = df['收盘价'].expanding().mean()

expanding即为取从头至今的数据。后面可以接各类计算函数

print(df['收盘价'].expanding().max())
print(df['收盘价'].expanding().min())
print(df['收盘价'].expanding().std())

二十二、输出

df.to_csv('output.csv', encoding='gbk', index=False)
posted @ 2021-08-31 17:56  my-island  阅读(133)  评论(0)    收藏  举报