1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 2 Python数据分析 Tushare双均线与金叉死叉日期 Pandas数据清洗 级联操作 合并操作

2 Python数据分析 Tushare双均线与金叉死叉日期 Pandas数据清洗 级联操作 合并操作

时间:2022-12-26 07:33:51

相关推荐

2 Python数据分析 Tushare双均线与金叉死叉日期 Pandas数据清洗 级联操作 合并操作

Python数据分析

1 Tushare股票分析

1.1 准备数据

平安银行[000001]

import tushare as tsimport numpy as npimport pandas as pdfrom pandas import Series, DataFramedf = ts.get_k_data(code='000001', start='-01')df.to_csv('pingan.csv')df = pd.read_csv('pingan.csv')df.drop(labels='Unnamed: 0', axis=1, inplace=True)df['date'] = pd.to_datetime(df['date'])df.set_index('date', inplace=True)df.head()'''openclose high low volumecodedate-01-048.1497.8808.1697.870241922.76 1-01-057.8937.7437.9437.560556499.82 1-01-067.7277.6107.7277.551412143.13 1-01-077.6107.5277.6607.444355336.85 1-01-087.4777.5117.5607.428288543.06 1'''

1.2 双均线分析

1.2.1 移动平均线介绍

移动平均线,Moving Average(MA),简称均线,将一定时期内的股票价格加以平均,并把不同时间的平均值连接起来,形成一根MA,是用以观察股票价格变动趋势的一种技术指标。

移动平均线常用的有5日、10日、30日、60日、120日和240日。

5日和10日的MA是短线操作的参照指标,称做日均线指标;

30日和60日的是中期均线指标,称做季均线指标;

120日和240日的是长期均线指标,称做年均线指标。

均线计算方法

MA = (C1 + C2 + C3 + … + Cn) / N

其中C为某日的收盘价,N为移动平均周期(天数)。

1.2.2 案例

需求:获取该股票历史数据的5日均线和30日均线。

1.2.2.1 时间窗函数rolling

窗口,就是将某个点扩大到包含这个点的一段区间,对区间来进行操作。

函数rolling的参数window表示时间窗的大小,可以用数字来表示向前观测数据的数量。

df['close'].rolling(5) # Rolling [window=5, center=False, axis=0]

对区间进行操作

前4条数据无法继续向前取5条数据,因此操作结果为NaN。

df['close'].rolling(5).mean().head(10)'''date-01-04 NaN-01-05 NaN-01-06 NaN-01-07 NaN-01-08 7.6542-01-11 7.5804-01-12 7.5240-01-13 7.3952-01-14 7.2836-01-15 7.2058Name: close, dtype: float64'''

1.2.2.2 绘制双均线

import matplotlib.pyplot as pltma5 = df['close'].rolling(5).mean()ma30 = df['close'].rolling(30).mean()plt.plot(ma5)plt.plot(ma30)

1.3 金叉日期与死叉日期

1.3.1 金叉与死叉介绍

叉指的是股票分析中短期均线与长期均线的交叉的交叉点。

如果短期均线主动向上穿越了长期均线,这个交叉点称为金叉;

如果短期均线主动向下穿越了长期均线,这个交叉点称为死叉。

但如果长期均线向下或变缓,同时短期均线向上穿越了长期均线,这个交叉点就不能叫金叉,死叉也如此。

出现金叉时,短期线从下向上突破长期线是买入信号,趋向买入,

出现死叉时,短期线从上向下跌穿过长期线是卖出信号,则趋向卖出。

1.3.2 案例1

需求:获取至今所有金叉日期和死叉日期。

ma5 = df['close'].rolling(5).mean()ma30 = df['close'].rolling(30).mean()s1 = ma5 < ma30s2 = ma5 > ma30

分析

金叉的左侧短期均线ma5低于长期均线ma30,金叉的右侧ma5高于长期均线ma30,因此金叉的左侧s1为True,s2为False,金叉的左侧s1为False,s2为True。当s1由True变为False时会出现金叉,当s1由False变为True时会出现死叉。

# 死叉df.loc[s1 & s2.shift(1)] # 死叉对应的数据death_date = df.loc[s1 & s2.shift(1)].index # 死叉出现的日期# 金叉df.loc[~(s1 | s2.shift(1))] # 金叉对应的数据golden_date = df.loc[~(s1 | s2.shift(1))].index # 金叉出现的日期

1.3.3 案例2

如果从1月1日开始,初始资金为100000元,金叉尽量买入,死叉全部卖出,分析截止到今天炒股收益。

取出指定时间段的数据

df_new = df['':'']

获取金叉日期和死叉日期

注意,前29日的ma30无法计算,为NaN,因此需要除去。

ma5_new = df_new['close'].rolling(5).mean()ma30_new = df_new['close'].rolling(30).mean()ma5_new = ma5_new[29:] ma30_new = ma30_new[29:] s1_new = ma5_new < ma30_new s2_new = ma5_new > ma30_new# 死叉日期death_date_new = df_new[29:].loc[s1_new & s2_new.shift(1)].index# 金叉日期golden_date_new = df_new[29:].loc[~(s1_new | s2_new.shift(1))].index

金叉尽量买入,死叉全部卖出。

买卖股票单价使用开盘价。

特殊情况:

如果昨天为金叉,则只能买入不能卖出;如果手里有剩余股票,需要将剩余股票价值计算到总收益中。

将金叉日期和死叉日期分别存储到两个Series中,将日期作为索引,将1和0分别设置为值,其中1对应的日期为金叉日期,0对应的日期为死叉日期。

golden_date_series = Series(data=1, index=golden_date_new)death_date_series = Series(data=0, index=death_date_new)

拼接两张表

all_series = golden_date_series.append(death_date_series).sort_index().sort_index()

计算总收益

initial_money = 100000 # 初始本金(固定)hold_money = initial_money # 手中持有金额(可变,开始时等于初始本金)hold_shares = 0 # 持有股票支数(可变,开始时为0)for date in all_series.index:# date是all_series的显式索引if all_series[date] == 1: # 当日为金叉,需要买入股票。price = df_new['open'][date] # 股票单价,开盘价# 尽量消耗持有本金所能购买的最大股票支数max_purchases = hold_money // (price * 100)hold_shares += max_purchases * 100hold_money -= (hold_shares * price)else: # 当日为死叉,需要卖出股票。price = df_new['open'][date] # 股票单价,开盘价hold_money += (price * hold_shares)hold_shares = 0 # 计算剩余股票价值(可以根据持有股票支数hold_shares判断是否有剩余股票)hold_shares_money = hold_shares * df_new['open'][-1]print(hold_shares_money)# 计算总收益print(hold_money - initial_money) # -36499.500000000466

2 Pandas数据清洗

2.1 介绍

数据清洗(Data cleaning)对数据进行重新审查和校验的过程,目的在于删除重复信息、处理无效值和缺失值等。

2.2 处理缺失数据

2.2.1 缺失数据类型

导入包

import numpy as npimport pandas as pdfrom pandas import DataFrame

Pandas中存在两种缺失数据类型:Nonenp.nan

区别:

None不能参与计算,否则直接报错(TypeError);

np.nan属于float类型,可以参与计算,结果为nan。

type(None) # NoneTypetype(np.nan) # floatnp.nan + 1 # nan

数据分析中会使用某些运算来处理原始数据,如果原数数据中的空值为nan,则不会干扰或者中断运算。

如果遇到了None形式的空值,Pandas会自动将其转换成nan。

df = DataFrame(data=np.random.randint(0, 100, size=(3, 4)))df.iloc[1,1] = Nonedf.iloc[0,0] = np.nan'''0 1 230NaN 31.09281117.0NaN 884238.049.03388'''

2.2.2 Pandas处理缺失数据
2.2.2.1 判断是否存在缺失数据 isnull,notnull, any, all
isnull,notnull

用于判断某个元素是否为缺失数据。

df.isnull() # 缺失值为True,非缺失值为False。'''0 1 2 30TrueFalseFalseFalse1FalseTrueFalseFalse2FalseFalseFalseFalse'''df.notnull() # 缺失值为False,非缺失值为True。'''0 1 2 30FalseTrueTrueTrue1TrueFalseTrueTrue2TrueTrueTrueTrue'''

any, all

any:序列中存在一个True就返回True,否则为False;

all:序列中所有的值均为True才返回True,否则为False。

isnull/notnull 配合 any/all,用于判断每一个行/列中是否存在缺失数据。

axis=0 检测列(默认)中是否存在空值,

axis=1 检测行中是否存在空值。

df.isnull().any()df.isnull().any(axis=0) # 列'''0True1True2False3Falsedtype: bool'''df.isnull().any(axis=1) # 行'''0False1False2Truedtype: bool'''

结合df.loc

取出不存在缺失数据的行及行号

df.loc[df.notnull().all(axis=1)] # 行'''0123238.049.03388'''df.loc[df.notnull().all(axis=1)].index# Int64Index([2], dtype='int64')

取出存在缺失数据的行及行号

df.loc[df.isnull().any(axis=1)]'''01230NaN31.09281117.0NaN884'''df.loc[df.isnull().any(axis=1)].index# Int64Index([0, 1], dtype='int64')

2.2.2.2 清除缺失数据 dropna
清除指定行号的行

nan_indexs = df.loc[df.isnull().any(axis=1)].indexdf.drop(labels=nan_indexs, axis=0)'''0123238.049.03388'''

直接删除存在缺失值的行/列

注意,drop系列函数中axis=0表示行,axis=1表示列。

df.dropna(axis=0) # 行'''0123238.049.03388'''df.dropna(axis=1) # 列'''2309281188423388'''

2.2.2.3 填充缺失数据 fillna
使用指定值填充缺失值。

df.fillna(value=0)'''012300.031.09281117.00.0884238.049.03388'''

使用近邻值填充缺失值。

method=ffill表示用缺失值的前一个值去填充缺失值,

method=bfill表示用缺失值的后一个值去填充缺失值。

axis={0 or ‘index’, 1 or ‘columns’},0表示在列方向上下填充,1表示在行方向左右填充。

参数axis需要配合参数method使用,一般会使用缺失值所在列中的前一个/后一个值来填充缺失值,因此需要axis=0来指定列。

df'''01230NaN84.04314128.0NaN6725266.094.04824'''df.fillna(method='ffill', axis=0) df.fillna(method='ffill', axis='index') # 用缺失值的前一个值去填充缺失值。'''01230NaN84.04314128.084.06725266.094.04824'''df.fillna(method='bfill', axis=0) df.fillna(method='bfill', axis='index') # 用缺失值的后一个值去填充缺失值。'''0123028.084.04314128.094.06725266.094.04824'''

2.2.3 处理缺失数据案例

数据说明:数据是1个冷库的温度数据,1-7对应7个温度采集设备,1分钟采集一次。

数据来源:/download/qq_36565509/12619016

观察数据

raw_data = pd.read_excel('./testData.xlsx')raw_data.head()'''time none 1 2 3 4 none1 5 6 70-01-27 17:00:00 NaN-24.8-18.2-20.8-18.8NaN NaN NaN NaN1-01-27 17:01:00 NaN-23.5-18.8-20.5-19.8NaN-15.2-14.5-16.02-01-27 17:02:00 NaN-23.2-19.2 NaN NaNNaN-13.0 NaN-14.03-01-27 17:03:00 NaN-22.8-19.2-20.0-20.5NaN NaN-12.2 -9.84-01-27 17:04:00 NaN-23.2-18.5-20.0-18.8NaN-10.2-10.8 -8.8'''

删除列none和none1

raw_data = pd.read_excel('./testData.xlsx')data = raw_data.drop(labels=['none', 'none1'], axis=1)data.shape # (1060, 8)

方案1:删除存在缺失值的行

data1 = data.dropna(axis=0)data1.shape # (927, 8)

方案2:使用近邻值填充缺失值

data2 = data.fillna(method='ffill', axis=0).fillna(method='bfill', axis=0)

2.2.4 处理重复数据
2.2.4.1 准备数据

df = DataFrame(data=np.random.randint(0, 100, size=(6, 8)))df.iloc[1] = [1,1,1,1,1,1,1,1]df.iloc[3] = [1,1,1,1,1,1,1,1]df.iloc[5] = [1,1,1,1,1,1,1,1]'''01234567037947853367236691111111112686288953835483111111114842874762299240511111111'''

2.2.4.2 duplicated

duplicated函数用于标记Series或DataFrame中的行数据是否重复,重复为True,否则为False。

pandas.DataFrame.duplicated(self, subset=None, keep='first')

subset:用于识别重复的列标签或列标签序列,默认为所有列标签;

keep=‘frist’:第一次出现外,其余相同的均被标记为重复;

keep=‘last’:最后一次出现外,其余相同的均被标记为重复;

keep=False:所有相同的都被标记为重复。

2.2.4.3 判断是否为重复行数据

第一次出现外,其余相同的行均被标记为重复。

df.duplicated(keep='first')'''0 False1 False2 False3True4 False5Truedtype: bool'''

2.2.4.4 获取非重复行数据

df.loc[~df.duplicated(keep='first')]'''01234567037947853367236691111111112686288953835484842874762299240'''

2.2.4.5 直接删除重复行数据 drop_duplicates

df.drop_duplicates(keep='first')'''01234567037947853367236691111111112686288953835484842874762299240'''

2.2.5 处理异常数据

目标:自定义一个1000行3列(A,B,C)取值范围为0-1的数据,然后对C列中值大于其两倍标准差的异常值进行清洗。

2.2.5.1 准备数据

df = DataFrame(data=np.random.random(size=(1000, 3)), columns=['A', 'B', 'C'])df.head()'''A B C00.1189900.6495050.97847210.8309280.1205020.74348920.0815530.6487530.95213030.9947360.4084370.01122040.9593290.8653920.110883'''

2.2.5.2 清洗数据

计算C列标准差

df['C'].std() # 0.28356614551282616

异常数据条件:C列中值大于其两倍标准差的数据。

twice_std = df['C'].std() * 2 # 0.5671322910256523df['C'] > twice_std'''0 True1 True2 True3False4False...'''

df.loc[~(df['C'] > twice_std)]'''30.5373460.3396870.27661140.4147940.1793210.09495850.3971690.6103160.42082470.7407180.7301600.302804...'''

3 级联操作与合并操作

3.1 级联操作

3.1.1 concat

import pandas as pdpd.concat(object, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False)

重要参数说明

object:series,dataframe或则是panel构成的序列list;

axis:指定合并连接的轴,0表示行,1表示列;

join:指定连接方式,inner或outer。

3.1.2 准备数据

import numpy as npimport pandas as pddf1 = pd.DataFrame(data=np.random.randint(0, 100, size=(5, 3)), columns=['A', 'B', 'C'])df1_copy = pd.DataFrame(data=np.random.randint(0, 100, size=(5, 3)), columns=['A', 'B', 'C'])df2 = pd.DataFrame(data=np.random.randint(0, 100, size=(5, 3)), columns=['A', 'D', 'C'])

3.1.3 级联种类
3.1.3.1 匹配级联

匹配级联:行索引和列索引完全一致。

pd.concat((df1, df1_copy), axis=0)'''ABC07417118084612599374380595247248065011307013248401136348294969391'''

3.1.3.2 非匹配级联

非匹配级联:级联维度的索引不一致,即纵向级联时列索引不一致,横向级联时行索引不一致。

非匹配级联有两种连接方式:内连接inner 和 外连接outer。

inner:inner方式只会对匹配的项进行连接;

outer:无论是否匹配,outer方式会将所有的项进行连接,将不存在的值设置为nan。

使用参数join指定连接方式,默认为外连接outer。

外连接outer

pd.concat((df1, df2), axis=0)pd.concat((df1, df2), axis=0, join='outer')'''ABCD06761.036NaN16763.011NaN28043.052NaN35939.018NaN4775.021NaN049NaN 9797.0165NaN 2189.0264NaN4288.0332NaN6242.0458NaN1266.0'''

内连接inner

pd.concat((df1, df2), axis=0, join='inner')'''AC0673616711280523591847210499716521264423326245812'''

3.1.2 append

append方法无法指定级联方向,只能在列方向上进行级联。

df1.append(df2)'''ABCD06761.036NaN16763.011NaN28043.052NaN35939.018NaN4775.021NaN049NaN 9797.0165NaN 2189.0264NaN4288.0332NaN6242.0458NaN1266.0'''

3.2 合并操作

3.2.1 merge

merge函数可以将不同数据集依照某些字段(属性)进行合并操作,得到一个新的数据集。

pd.merge(left=DataFrame1, right=DataFrame2, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=(’_x’, ‘_y’))

参数说明

how:inner(默认),outer,left,right;

on:指定根据某列进行合并,必须存在于两个DateFrame中;

left_on:左连接,指定根据DataFrame1中的某列进行合并;

right_on:左连接,指定根据DataFrame2中的某列进行合并;

left_index:是否根据DataFrame1的行索引进行合并;

right_index:是否根据DataFrame2的行索引进行合并;

sort:是否对合并后的数据根据连接键进行排序;

suffixes:如果两个数据集中出现重复列,新数据集中加上后缀_x,_y进行区别。

3.2.2 merge与concat的区别

merge需要指定某列进行数据合并

concat只是在行/列方向上进行表格拼接

3.2.3 合并操作
3.2.3.1 一对一合并

from pandas import DataFramedf1 = DataFrame({'employee': ['Bob', 'Jake', 'Lisa'],'group': ['Accounting', 'Engineering', 'Engineering'],})'''employeegroup0 Bob Accounting1Jake Engineering2Lisa Engineering'''df2 = DataFrame({'employee': ['Lisa', 'Bob', 'Jake'],'hire_date': [, , ],})'''employeehire_date0Lisa1 Bob2Jake '''

参数on:指定根据某列进行合并,必须存在于两个DateFrame中。

pd.merge(df1, df2, on='employee')'''employeegrouphire_date0 Bob Accounting 1Jake Engineering 2Lisa Engineering '''

如果不指定参数,默认根据两表中相同列进行合并,df1和df2的相同列是employee。

pd.merge(df1, df2)'''employeegrouphire_date0 Bob Accounting 1Jake Engineering 2Lisa Engineering '''

3.2.3.2 一对多合并

df3 = DataFrame({'employee': ['Lisa', 'Jake'],'group': ['Accounting', 'Engineering'],'hire_date': [, ],})'''employee grouphire_date0LisaAccounting 1Jake Engineering '''df4 = DataFrame({'group': ['Accounting', 'Engineering', 'Engineering'],'supervisor': ['Carly', 'Guido', 'Steve'],})'''groupsupervisor0 Accounting Carly1Engineering Guido2Engineering Steve'''

pd.merge(df3, df4) # 相同列为group'''employee grouphire_datesupervisor0Lisa Accounting Carly1Jake Engineering Guido2Jake Engineering Steve'''

3.2.3.3 多对多合并

参数how:inner(默认),outer,left,right。

df1 = DataFrame({'employee': ['Bob', 'Jake', 'Lisa'],'group': ['Accounting', 'Engineering', 'Engineering'],})'''employeegroup0 Bob Accounting1Jake Engineering2Lisa Engineering'''df5 = DataFrame({'group': ['Engineering', 'Engineering', 'HR'],'supervisor': ['Carly', 'Guido', 'Steve'],})'''groupsupervisor0Engineering Carly1Engineering Guido2 HRSteve'''

pd.merge(df1, df5, how='inner')'''employeegroupsupervisor0Jake Engineering Carly1Jake Engineering Guido2Lisa Engineering Carly3Lisa Engineering Guido'''pd.merge(df1, df5, how='outer')'''employeegroupsupervisor0 Bob Accounting NaN1Jake Engineering Carly2Jake Engineering Guido3Lisa Engineering Carly4Lisa Engineering Guido5 NaN HR Steve'''pd.merge(df1, df5, how='left')'''employeegroupsupervisor0 Bob Accounting NaN1Jake Engineering Carly2Jake Engineering Guido3Lisa Engineering Carly4Lisa Engineering Guido'''pd.merge(df1, df5, how='right')'''employeegroupsupervisor0Jake Engineering Carly1Jake Engineering Guido2Lisa Engineering Carly3Lisa Engineering Guido4 NaN HR Steve'''

3.2.3.4 key规范化

当两张表没有相同列时,可使用参数left_on和right_on分别指定左右表中的列作为连接列进行合并。

df1 = DataFrame({'employee': ['Bob', 'Jake', 'Lisa'],'group': ['Accounting', 'Engineering', 'Engineering'],})'''employeegroup0 Bob Accounting1Jake Engineering2Lisa Engineering'''df6 = DataFrame({'name': ['Lisa', 'Bob', 'Bill'],'hire_date': [1998, , ],})'''namehire_date0Lisa 19981 Bob 2Bill '''

pd.merge(df1, df6, left_on='employee', right_on='name')'''employeegroupnamehire_date0 Bob Accounting Bob 1Lisa EngineeringLisa 1998'''

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。