数据分析 day02

3.DataFrame基础操作巩固-股票分析

In [42]:

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import tushare as ts#财经数据接口包
import matplotlib.pyplot as plt

需求:股票分析

  • 使用tushare包获取某股票的历史行情数据。
  • 输出该股票所有收盘比开盘上涨3%以上的日期。
  • 输出该股票所有开盘比前日收盘跌幅超过2%的日期。
  • 假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?

In [4]:

df = ts.get_k_data('600519',start='2000-01-01')
df.to_csv('./maotai.csv')

In [50]:

df = pd.read_csv('./maotai.csv')
df.head()

Out[50]:

Unnamed: 0 date open close high low volume code
0 0 2001-08-27 5.392 5.554 5.902 5.132 406318.00 600519
1 1 2001-08-28 5.467 5.759 5.781 5.407 129647.79 600519
2 2 2001-08-29 5.777 5.684 5.781 5.640 53252.75 600519
3 3 2001-08-30 5.668 5.796 5.860 5.624 48013.06 600519
4 4 2001-08-31 5.804 5.782 5.877 5.749 23231.48 600519

In [51]:

df.drop(labels='Unnamed: 0',axis=1,inplace=True)

In [7]:

df.head(3)

Out[7]:

date open close high low volume code
0 2001-08-27 5.392 5.554 5.902 5.132 406318.00 600519
1 2001-08-28 5.467 5.759 5.781 5.407 129647.79 600519
2 2001-08-29 5.777 5.684 5.781 5.640 53252.75 600519

In [8]:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4386 entries, 0 to 4385
Data columns (total 7 columns):
date      4386 non-null object
open      4386 non-null float64
close     4386 non-null float64
high      4386 non-null float64
low       4386 non-null float64
volume    4386 non-null float64
code      4386 non-null int64
dtypes: float64(5), int64(1), object(1)
memory usage: 239.9+ KB

In [10]:

df.describe()#聚合操作

Out[10]:

open close high low volume code
count 4386.000000 4386.000000 4386.000000 4386.000000 4386.000000 4386.0
mean 198.346553 198.656232 201.125280 195.931863 27921.072905 600519.0
std 260.048946 260.403673 263.249482 257.143597 24503.505290 0.0
min 4.049000 4.045000 4.068000 4.012000 238.100000 600519.0
25% 27.526000 27.536750 27.820250 27.093000 11310.195000 600519.0
50% 113.967500 113.987500 115.515500 112.401000 23793.000000 600519.0
75% 194.410000 193.878000 197.158500 191.120750 37651.250000 600519.0
max 1231.000000 1233.750000 1241.610000 1228.060000 406318.000000 600519.0

In [52]:

#将date列的数据转成时间序列且将其作为源数据的行索引
df['date'] = pd.to_datetime(df['date'])

In [53]:

df.set_index('date',inplace=True)

In [54]:

df.head()

Out[54]:

open close high low volume code
date
2001-08-27 5.392 5.554 5.902 5.132 406318.00 600519
2001-08-28 5.467 5.759 5.781 5.407 129647.79 600519
2001-08-29 5.777 5.684 5.781 5.640 53252.75 600519
2001-08-30 5.668 5.796 5.860 5.624 48013.06 600519
2001-08-31 5.804 5.782 5.877 5.749 23231.48 600519
  • 输出该股票所有收盘比开盘上涨3%以上的日期。
  • 输出该股票所有开盘比前日收盘跌幅超过2%的日期。

In [18]:

df.loc[(df['close'] - df['open'])/df['open'] >  0.03 ].index

. . .

In [21]:

df.loc[(df['open'] - df['close'].shift(1))/df['close'].shift(1) < -0.02].index

. . .

  • 假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?

In [22]:

data = df['2010':'2020']
data.head()

. . .

In [31]:

data_monthly = data.resample('M').first()
cost_money = data_monthly['open'].sum()*100

In [32]:

data_yearly = data.resample('A').last()[:-1]
recv_money = data_yearly['open'].sum()*1200

In [33]:

last_money = data['open'][-1] * 100

In [34]:

last_money+recv_money-cost_money

Out[34]:

567728.6999999997

需求:双均线策略制定

  • 使用tushare包获取某股票的历史行情数据

In [ ]:


  • 计算该股票历史数据的5日均线和30日均线
    • 什么是均线?
      • 对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为一条线,就叫做N日移动平均线。移动平均线常用线有5天、10天、30天、60天、120天和240天的指标。
        • 5天和10天的是短线操作的参照指标,称做日均线指标;
        • 30天和60天的是中期均线指标,称做季均线指标;
        • 120天和240天的是长期均线指标,称做年均线指标。
    • 均线计算方法:MA=(C1+C2+C3+...+Cn)/N C:某日收盘价 N:移动平均周期(天数)

In [64]:

#ma表示的是均线
ma5 = df['close'].rolling(5).mean()
ma30 = df['close'].rolling(30).mean()

In [65]:

#将ma5和ma30汇总到源数据中
df['ma5'] = ma5
df['ma30'] = ma30
df

. . .

  • 可视化历史数据的收盘价和两条均线

In [46]:

plt.plot(ma5[50:100],c='red')
plt.plot(ma30[50:100],c='blue')

Out[46]:

[<matplotlib.lines.Line2D at 0x1b084f37550>]

img

  • 分析输出所有金叉日期和死叉日期
    • 股票分析技术中的金叉和死叉,可以简单解释为:
      • 分析指标中的两根线,一根为短时间内的指标线,另一根为较长时间的指标线。
      • 如果短时间的指标线方向拐头向上,并且穿过了较长时间的指标线,这种状态叫“金叉”;
      • 如果短时间的指标线方向拐头向下,并且穿过了较长时间的指标线,这种状态叫“死叉”;
      • 一般情况下,出现金叉后,操作趋向买入;死叉则趋向卖出。当然,金叉和死叉只是分析指标之一,要和其他很多指标配合使用,才能增加操作的准确性。

In [ ]:


  • 如果我从假如我从2010年1月1日开始,初始资金为100000元,金叉尽量买入,死叉全部卖出,则到今天为止,我的炒股收益率如何?

In [68]:

df = df['2010':'2020']
df

. . .

In [74]:

sr1 = df['ma5'] < df['ma30']
sr2 = df['ma5'] >= df['ma30']

  • 让sr1和sr2.shift(1)进行与操作或者或操作,返回的结果定位到金叉和死叉

In [77]:

df.loc[sr1 & sr2.shift(1)] #死叉对应的行数据
death_dates = df.loc[sr1 & sr2.shift(1)].index

In [79]:

df.loc[~(sr1 | sr2.shift(1))]#金叉对应的行数据
golden_dates = df.loc[~(sr1 | sr2.shift(1))].index

In [80]:

golden_dates

. . .

In [96]:

#基于金叉和死叉买卖股票计算收益
first_money = 100000
money = first_money
hold = 0 #持有股票的数量(股)

s1 = Series(1,index=golden_dates)#1标识金叉日期
s2 = Series(0,index=death_dates)#0表示死叉日期
s = s1.append(s2) #存储的是所有的金叉和死叉日期
s = s.sort_index() #根据索引排序

for i in s.index:
    #开盘价作为买卖的单价
    price = df.loc[i]['open']
    if s[i] == 1:#金叉:买入
        hand_cost = 100 * price#1手股票花费的钱数
        hand_count = money // hand_cost #最多买入了多少手股票
        hold = hand_count * 100 #买入的多少只股票
        money -= hold*price
    else:
        money += hold * price
        hold = 0
        
#如果最后一天为金叉,最后一天买入股票,没有卖出。剩余的股票也要计算到总收益中
last_money = hold * df['open'][-1]
print(money + last_money - first_money)
1501254.9999999995

4.基于pandas的数据清洗

Python 3

Not Trusted

Run

处理丢失数据

  • 有两种丢失数据:
    • None
    • np.nan(NaN)

In [1]:

import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import tushare as ts#财经数据接口包
import matplotlib.pyplot as plt

  • 两种丢失数据的区别

In [2]:

type(np.nan)

Out[2]:

float

In [5]:

np.nan + 3

Out[5]:

nan

In [3]:

type(None)

Out[3]:

NoneType

  • pandas中的None和NAN

In [10]:

df = DataFrame(data=np.random.randint(0,100,size=(8,5)))
df

Out[10]:

0 1 2 3 4
0 44 91 92 51 55
1 23 22 92 35 83
2 21 52 40 63 29
3 94 51 24 70 59
4 27 78 1 21 17
5 94 57 5 43 22
6 87 31 58 30 82
7 93 28 54 7 93

In [12]:

df.iloc[1,2] = None
df.iloc[3,4] = None
df.iloc[4,1] = None
df.iloc[7,4] = np.nan

In [13]:

df

Out[13]:

0 1 2 3 4
0 44 91.0 92.0 51 55.0
1 23 22.0 NaN 35 83.0
2 21 52.0 40.0 63 29.0
3 94 51.0 24.0 70 NaN
4 27 NaN 1.0 21 17.0
5 94 57.0 5.0 43 22.0
6 87 31.0 58.0 30 82.0
7 93 28.0 54.0 7 NaN

pandas处理空值操作

  • isnull
  • notnull
  • any
  • all
  • dropna
  • fillna

In [16]:

df.isnull()

Out[16]:

0 1 2 3 4
0 False False False False False
1 False False True False False
2 False False False False False
3 False False False False True
4 False True False False False
5 False False False False False
6 False False False False False
7 False False False False True
  • 检测出原始数据中哪些行中存在空值

In [20]:

df.isnull()

Out[20]:

0 1 2 3 4
0 False False False False False
1 False False True False False
2 False False False False False
3 False False False False True
4 False True False False False
5 False False False False False
6 False False False False False
7 False False False False True
  • any和all可以帮我们检测df中哪些行列中存在空值
  • isnull->any(axis=1)
  • notnull->all(axis=1)

In [24]:

~df.isnull().any(axis=1)
df.loc[~df.isnull().any(axis=1)]

Out[24]:

0 1 2 3 4
0 44 91.0 92.0 51 55.0
2 21 52.0 40.0 63 29.0
5 94 57.0 5.0 43 22.0
6 87 31.0 58.0 30 82.0

In [28]:

df.notnull().all(axis=1)
df.loc[df.notnull().all(axis=1)]

Out[28]:

0 1 2 3 4
0 44 91.0 92.0 51 55.0
2 21 52.0 40.0 63 29.0
5 94 57.0 5.0 43 22.0
6 87 31.0 58.0 30 82.0

In [29]:

df.dropna(axis=0)  #将空值对应的行数据删除

Out[29]:

0 1 2 3 4
0 44 91.0 92.0 51 55.0
2 21 52.0 40.0 63 29.0
5 94 57.0 5.0 43 22.0
6 87 31.0 58.0 30 82.0

In [32]:

df

Out[32]:

0 1 2 3 4
0 44 91.0 92.0 51 55.0
1 23 22.0 NaN 35 83.0
2 21 52.0 40.0 63 29.0
3 94 51.0 24.0 70 NaN
4 27 NaN 1.0 21 17.0
5 94 57.0 5.0 43 22.0
6 87 31.0 58.0 30 82.0
7 93 28.0 54.0 7 NaN

In [33]:

#fillna将空值进行覆盖
df.fillna(method='ffill',axis=0) #使用紧邻值填充空值

Out[33]:

0 1 2 3 4
0 44 91.0 92.0 51 55.0
1 23 22.0 92.0 35 83.0
2 21 52.0 40.0 63 29.0
3 94 51.0 24.0 70 29.0
4 27 51.0 1.0 21 17.0
5 94 57.0 5.0 43 22.0
6 87 31.0 58.0 30 82.0
7 93 28.0 54.0 7 82.0

面试题

  • 数据说明:
    • 数据是1个冷库的温度数据,1-7对应7个温度采集设备,1分钟采集一次。
  • 数据处理目标:
    • 用1-4对应的4个必须设备,通过建立冷库的温度场关系模型,预估出5-7对应的数据。
    • 最后每个冷库中仅需放置4个设备,取代放置7个设备。
    • f(1-4) --> y(5-7)
  • 数据处理过程:
    • 1、原始数据中有丢帧现象,需要做预处理;
    • 2、matplotlib 绘图;
    • 3、建立逻辑回归模型。
  • 无标准答案,按个人理解操作即可,请把自己的操作过程以文字形式简单描述一下,谢谢配合。
  • 测试数据为testData.xlsx

In [ ]:


处理重复数据

In [ ]:


处理异常数据

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

5.DataFrame的级联and合并操作

级联操作

  • pd.concat, pd.append

pandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:

objs
axis=0
keys
join='outer' / 'inner':表示的是级联的方式,outer会将所有的项进行级联(忽略匹配和不匹配),而inner只会将匹配的项级联到一起,不匹配的不级联
ignore_index=False

  • 匹配级联

In [ ]:


  • 不匹配级联

    • 不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致
    • 有2种连接方式:
      • 外连接:补NaN(默认模式)
      • 内连接:只连接匹配的项
  • append函数的使用

合并操作

  • merge与concat的区别在于,merge需要依据某一共同列来进行合并
  • 使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
  • 注意每一列元素的顺序不要求一致

一对一合并

In [ ]:

df1 = DataFrame({'employee':['Bob','Jake','Lisa'],
                'group':['Accounting','Engineering','Engineering'],
                })


In [ ]:

df2 = DataFrame({'employee':['Lisa','Bob','Jake'],
                'hire_date':[2004,2008,2012],
                })

一对多合并

In [ ]:

df3 = DataFrame({
    'employee':['Lisa','Jake'],
    'group':['Accounting','Engineering'],
    'hire_date':[2004,2016]})

In [ ]:

df4 = DataFrame({'group':['Accounting','Engineering','Engineering'],
                       'supervisor':['Carly','Guido','Steve']
                })


多对多合并

In [ ]:

df1 = DataFrame({'employee':['Bob','Jake','Lisa'],
                 'group':['Accounting','Engineering','Engineering']})


In [ ]:

df5 = DataFrame({'group':['Engineering','Engineering','HR'],
                'supervisor':['Carly','Guido','Steve']
                })


key的规范化

  • 当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名

In [ ]:

df1 = DataFrame({'employee':['Jack',"Summer","Steve"],
                 'group':['Accounting','Finance','Marketing']})


In [ ]:

df2 = DataFrame({'employee':['Jack','Bob',"Jake"],
                 'hire_date':[2003,2009,2012],
                'group':['Accounting','sell','ceo']})


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

In [ ]:

df1 = DataFrame({'employee':['Bobs','Linda','Bill'],
                'group':['Accounting','Product','Marketing'],
               'hire_date':[1998,2017,2018]})

In [ ]:

df5 = DataFrame({'name':['Lisa','Bobs','Bill'],
                'hire_dates':[1998,2016,2007]})


内合并与外合并:out取并集 inner取交集

In [ ]:

df6 = DataFrame({'name':['Peter','Paul','Mary'],
               'food':['fish','beans','bread']}
               )
df7 = DataFrame({'name':['Mary','Joseph'],
                'drink':['wine','beer']})


In [ ]:

df6 = DataFrame({'name':['Peter','Paul','Mary'],
               'food':['fish','beans','bread']}
               )
df7 = DataFrame({'name':['Mary','Joseph'],
                'drink':['wine','beer']})


In [ ]:

#合并df1和df2
dic1={
    
    'name':['tom','jay','helly'],
    'age':[11,12,33],
    'classRoom':[1,2,3]
}
df1=DataFrame(data=dic1)
df2=DataFrame(data=np.random.randint(60,100,size=(3,3)),
              index=['jay','tom','helly'],
             columns=['java','python','c'])


原文地址:https://www.cnblogs.com/bky20061005/p/12192443.html