medik

需求一:使用tushare包获取某股票的历史行情数据。

复制代码
# 获取行情
df = ts.get_k_data(code="600519",start=\'2000-01-01\')
# 保存到本地
df.to_csv(\'./maotai.csv\')
# 读取本地csv文件数据
df = pd.read_csv(\'./maotai.csv\')
# 删除 Unnamed: 0 这一列,将 date 列转为时间类型,并设置为 index 列
df.drop(labels=\'Unnamed: 0\',axis=1,inplace=True)
df[\'date\'] = pd.to_datetime(df[\'date\'])
df.set_index(\'date\',inplace=True)
print(df.info())    # 查看整个数据集合中各个数据类型
print(df)
复制代码

需求二:输出该股票所有收盘比开盘上涨3%以上的日期。

复制代码
# (收盘-开盘)/开盘 > 0.03  返回值为 boolean 值,将 boolean 作为行索引来使用

# 在分析的过程中如果产生了boolean值则下一步马上将布尔值作为源数据的行索引
# 如果布尔值作为df的行索引,则可以取出true对应的行数据,忽略false对应的行数据
# print((df[\'close\'] - df[\'open\'])/df[\'open\'] > 0.03)   # 获取了True对应的行数据(满足需求的行数据)
print(df.loc[(df[\'close\'] - df[\'open\']) / df[\'open\'] > 0.03].index)
复制代码

需求三:输出该股票所有开盘比前日收盘跌幅超过2%的日期。

# (今日开盘价-昨日收盘价)/昨日收盘价 < -0.02
# print(df[\'close\'].shift(1))    # 使 df[\'close\'] 列整体下移一位
print(df.loc[(df[\'open\'] - df[\'close\'].shift(1)) / df[\'close\'].shift(1) < -0.02].index)

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

- 分析:
  - 时间节点:2010-2020
  - 一手股票:100支股票
  - 买:
    - 一个完整的年需要买入1200支股票
  - 卖:
    - 一个完整的年需要卖出1200支股票
  -买卖股票的单价:
    - 开盘价

复制代码
# 买股票:找每个月的第一个交易日对应的行数据(捕获到开盘价)==》每月的第一行数据
# 根据月份从原始数据中提取指定的数据
# 每月第一个交易日对应的行数据
new_df = df[\'2010-01-01\':]
mairu = new_df.resample(\'M\').first()[\'open\'].sum() * 100  # 数据的重新取样,取出每月的第一支股票
maichu = new_df.resample(\'A\').last()[\'open\'][:-1].sum() * 1200  # 取出每年最后一个交易日的收盘价
yu = new_df[\'close\'][-1] * 600  # 剩余股票价值

# print(new_df.resample(\'M\').first()[\'open\']*100)
# print(new_df.resample(\'A\').last()[\'close\'][:-1] * 100)

print(maichu - mairu + yu)
复制代码

 

双均线策略

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

复制代码
df = ts.get_k_data(code="600519", start=\'2000-01-01\')
df.to_csv(\'./maotai.csv\')
df = pd.read_csv(\'./maotai.csv\')
df.drop(labels=\'Unnamed: 0\',axis=1,inplace=True)
df[\'date\'] = pd.to_datetime(df[\'date\'])
df.set_index(\'date\',inplace=True)

ma5 = df[\'close\'].rolling(5).mean()     # 5日均线
ma30 = df[\'close\'].rolling(30).mean()     # 30日均线

plt.rcParams[\'font.sans-serif\'] = [\'SimHei\']  # 用来正常显示中文标签
plt.rcParams[\'axes.unicode_minus\'] = False  # 用来正常显示负号
plt.plot(ma5[20:80],\'h-r\', label=\'ma5\')
plt.plot(ma30[20:80],\'h-b\', label=\'ma30\')
plt.legend()
plt.show()
复制代码

需求二:

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

复制代码
# 分析输出所有金叉日期和死叉日期                                                     
df = pd.read_csv(\'./maotai.csv\')                                      
df.drop(labels=\'Unnamed: 0\', axis=1, inplace=True)                    
df[\'date\'] = pd.to_datetime(df[\'date\'])                               
df.set_index(\'date\', inplace=True)                                    
                                                                      
ma5 = df[\'close\'].rolling(5).mean()                                   
ma30 = df[\'close\'].rolling(30).mean()                                 
s5 = ma5[30:] < ma30[30:]                                             
s30 = ma5[30:] > ma30[30:]                                            
df = df[30:]                                                          
                                                                      
down = s5 & s30.shift(1)                                                
print(df.loc[down].index)       # 死叉                                     
                                                                      
up = ~(s5 | s30.shift(1))                                           
print(df.loc[up].index)    # 金叉  
复制代码

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

复制代码
df = pd.read_csv(\'./maotai.csv\')
df.drop(labels=\'Unnamed: 0\', axis=1, inplace=True)
df[\'date\'] = pd.to_datetime(df[\'date\'])
df.set_index(\'date\', inplace=True)

ma5 = df[\'close\'].rolling(5).mean()
ma30 = df[\'close\'].rolling(30).mean()
s5 = ma5[30:] < ma30[30:]
s30 = ma5[30:] > ma30[30:]
df = df[30:]

up = ~(s5 | s30.shift(1))  # 金叉
down = s5 & s30.shift(1)  # 死叉

up_code = Series(data=1, index=(df.loc[up].index))
down_code = Series(data=0, index=(df.loc[down].index))
s = up_code.append(down_code)
s = s.sort_index()[\'2010-01-01\']

first_monry = 100000  # 本金,不变
money = first_monry  # 可变的,买股票话的钱和卖股票收入的钱都从该变量中进行操作
hold = 0  # 持有股票的数量(股数:100股=1手)

for i in range(0, len(s)):  # i表示的s这个Series中的隐式索引
    # i = 0(死叉:卖) = 1(金叉:买)
    if s[i] == 1:  # 金叉的时间
        # 基于100000的本金尽可能多的去买入股票
        # 获取股票的单价(金叉时间对应的行数据中的开盘价)
        time = s.index[i]  # 金叉的时间
        p = df.loc[time][\'open\']  # 股票的单价
        hand_count = money // (p * 100)  # 使用100000最多买入多少手股票
        hold = hand_count * 100

        money -= (hold * p)  # 将买股票话的钱从money中减去
    else:
        # 将买入的股票卖出去

        # 找出卖出股票的单价
        death_time = s.index[i]
        p_death = df.loc[death_time][\'open\']  # 卖股票的单价
        money += (p_death * hold)  # 卖出的股票收入加入到money
        hold = 0

# 如何判定最后一天为金叉还是死叉
last_monry = hold * df[\'close\'][-1]  # 剩余股票的价值

# 总收益
money + last_monry - first_monry
print(money)
复制代码

 

人口分析项目

复制代码
- 需求:
    - 导入文件,查看原始数据
    - 将人口数据和各州简称数据进行合并
    - 将合并的数据中重复的abbreviation列进行删除
    - 查看存在缺失数据的列
    - 找到有哪些state/region使得state的值为NaN,进行去重操作
    - 为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN
    - 合并各州面积数据areas
    - 我们会发现area(sq.mi)这一列有缺失数据,找出是哪些行
    - 去除含有缺失数据的行
    - 找出2010年的全民人口数据
    - 计算各州的人口密度
    - 排序,并找出人口密度最高的州
复制代码
复制代码
# 导入文件,查看原始数据
abb = pd.read_csv(r\'H:\py\课件\2-课件\2_数据分析\课件\data\state-abbrevs.csv\') #state(州的全称)abbreviation(州的简称)
area = pd.read_csv(r\'H:\py\课件\2-课件\2_数据分析\课件\data\state-areas.csv\') #state州的全称,area (sq. mi)州的面积
pop = pd.read_csv(r\'H:\py\课件\2-课件\2_数据分析\课件\data\state-population.csv\')#state/region简称,ages年龄,year时间,population人口数量

# 将人口数据和各州简称数据进行合并
abb_pop = pd.merge(abb,pop,left_on=\'abbreviation\',right_on=\'state/region\')
abb_pop

# 将合并的数据中重复的abbreviation列进行删除
abb_pop2.drop(labels=\'abbreviation\',axis=1,inplace=True)
abb_pop2

# 查看存在缺失数据的列
abb_pop2.isnull().any(axis=0)

# 找到有哪些state/region使得state的值为NaN,进行去重操作
abb_pop.loc[abb_pop[\'state\'].isnull()][\'state/region\'].unique()

# 为找到的这些state/region的state项补上正确的值,从而去除掉state这一列的所有NaN
# 合并各州面积数据areas
# 我们会发现area(sq.mi)这一列有缺失数据,找出是哪些行
# 去除含有缺失数据的行
# 找出2010年的全民人口数据
# 计算各州的人口密度
# 排序,并找出人口密度最高的州
复制代码

消费记录分析

数据文件:消费记录数据

第一部分

复制代码
第一部分:数据类型处理
    - 数据加载
        - 字段含义:
            - user_id:用户ID
            - order_dt:购买日期
            - order_product:购买产品的数量
            - order_amount:购买金额
    - 观察数据
        - 查看数据的数据类型
        - 数据中是否存储在缺失值
        - 将order_dt转换成时间类型
        - 查看数据的统计描述
            - 计算所有用户购买商品的平均数量
            - 计算所有用户购买商品的平均花费
        - 在源数据中添加一列表示月份:astype(\'datetime64[M]\')
复制代码
import pandas as pd
from pandas import DataFrame
# 数据加载
df = pd.read_csv(r\'H:\py\高级\数据分析\科学计算基础包-numpy\CDNOW_master.txt\',header=None,sep=\'\s+\',names=[\'user_id\',\'order_dt\',\'order_product\',\'order_amount\'])
df

# 查看数据的数据类型
df.info()

# 数据中是否存储在缺失值
# df.isnull().any()
df.notnull().all()

# 将 order_amount 转换成时间类型
df[\'order_dt\'] = pd.to_datetime(df[\'order_dt\'],format=\'%Y%m%d\')
df

# 查看数据的统计描述
df.describe()

# 在源数据中添加一列表示月份:astype(\'datetime64[M]\')
df[\'month\'] = df[\'order_dt\'].astype(\'datetime64[M]\')
df

 

 

第二部分

复制代码
第二部分:按月数据分析
    - 用户每月花费的总金额
        - 绘制曲线图展示
    - 所有用户每月的产品购买量
    - 所有用户每月的消费总次数
    - 统计每月的消费人数
复制代码

代码实现

# 用户每月花费的总金额
df.groupby(by=\'month\')[\'order_amount\'].sum()

# 绘制曲线图展示
import matplotlib.pyplot as plt
plt.plot(df.groupby(by=\'month\')[\'order_amount\'].sum())
df.groupby(by=\'month\')[\'order_amount\'].sum().plot()

# 所有用户每月的产品购买量
df.groupby(by=\'month\')[\'order_product\'].sum()

# 所有用户每月的消费总次数
df.groupby(by=\'month\')[\'user_id\'].count()

# 统计每月的消费人数
df.groupby(by=\'month\')[\'user_id\'].nunique()

第三部分

第三部分:用户个体消费数据分析
    - 用户消费总金额和消费总次数的统计描述
    - 用户消费金额和消费产品数量的散点图
    - 各个用户消费总金额的直方分布图(消费金额在1000之内的分布)
    - 各个用户消费的总数量的直方分布图(消费商品的数量在100次之内的分布)

代码实现

# 用户消费总金额和消费总次数的统计描述
df.groupby(\'user_id\')[\'order_amount\'].sum()
df.groupby(\'user_id\')[\'order_product\'].count()

# 用户消费金额和消费产品数量的散点图
order_amount = df.groupby(\'user_id\')[\'order_amount\'].sum()
order_product = df.groupby(\'user_id\')[\'order_product\'].sum()
plt.scatter(order_amount,order_product)

# 各个用户消费总金额的直方分布图(消费金额在1000之内的分布)
df.groupby(by=\'user_id\').sum().query(\'order_amount <= 1000\')[\'order_amount\'].hist()

# 各个用户消费的总数量的直方分布图(消费商品的数量在100次之内的分布)
df.groupby(by=\'user_id\').sum().query(\'order_product <= 100\')[\'order_product\'].hist()

 

第四部分

复制代码
第四部分:用户消费行为分析
    - 用户第一次消费的月份分布,和人数统计
        - 绘制线形图
    - 用户最后一次消费的时间分布,和人数统计
        - 绘制线形图
    - 新老客户的占比
        - 消费一次为新用户
        - 消费多次为老用户
            - 分析出每一个用户的第一个消费和最后一次消费的时间
                - agg([\'func1\',\'func2\']):对分组后的结果进行指定聚合
            - 分析出新老客户的消费比例
    - 用户分层
        - 分析得出每个用户的总购买量和总消费金额and最近一次消费的时间的表格rfm
        - RFM模型设计
            - R表示客户最近一次交易时间的间隔。
                - /np.timedelta64(1,\'D\'):去除days
            - F表示客户购买商品的总数量,F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。
            - M表示客户交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低。
            - 将R,F,M作用到rfm表中
        - 根据价值分层,将用户分为:
            - 重要价值客户
            - 重要保持客户
            - 重要挽留客户
            - 重要发展客户
            - 一般价值客户
            - 一般保持客户
            - 一般挽留客户
            - 一般发展客户
                - 使用已有的分层模型即可rfm_func
复制代码

代码实现

import pandas as pd
from pandas import DataFrame

# 读取数据
df = pd.read_csv(r\'H:\py\高级\数据分析\科学计算基础包-numpy\CDNOW_master.txt\',sep=\'\s+\',header=None,names=[\'user_id\',\'order_dt\',\'order_product\',\'order_amount\'])

# 转为时间格式
df[\'order_dt\'] = pd.to_datetime(df[\'order_dt\'],format=\'%Y%m%d\')

# 增加月份一列
df[\'month\'] = df[\'order_dt\'].astype(\'datetime64[M]\')

# 用户第一次消费的月份分布,和人数统计,绘制线形图
df.groupby(by=\'user_id\')[\'month\'].min().value_counts().plot()

# 用户最后一次消费的时间分布,和人数统计,绘制线形图
df.groupby(by=\'user_id\')[\'month\'].max().value_counts().plot()

# 新老客户的占比
new_old_user = df.groupby(by=\'user_id\')[\'order_dt\'].agg([\'min\',\'max\'])
val = (new_old_user[\'min\'] == new_old_user[\'max\']).value_counts()
# 新用户占比
val[True]/(val[True] + val[False])
# 老用户占比
val[False]/(val[True] + val[False])

  构建 RFM 数据表

# 分析得出每个用户的总购买量和总消费金额and最近一次消费的时间的表格rfm
rfm = df.pivot_table(index=\'user_id\',aggfunc={\'order_product\':\'sum\',\'order_amount\':\'sum\',\'order_dt\':\'max\'})
rfm

# R表示客户最近一次交易时间的间隔
import numpy as np
new_date = df[\'order_dt\'].max() # 数据中最大时间,假设为当前时间
rfm[\'R\'] = -(rfm.groupby(by=\'user_id\')[\'order_dt\'].max()-new_date)/np.timedelta64(1,\'D\')
rfm

# F表示客户购买商品的总数量,F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃
# M表示客户交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低
# 将R,F,M作用到rfm表中

# 删除 order_dt 列
rfm.drop(labels=\'order_dt\',axis=1,inplace=True)

# 对列进行重命名
rfm.columns = [\'M\',\'F\',\'R\']
rfm

用户分层

def rfm_func(x):
    level = x.map(lambda x:\'1\' if x>=0 else \'0\')
    val = level.R + level.F + level.M
    dit = {
        \'111\':\'重要价值客户\',
        \'011\':\'重要保持客户\',
        \'101\':\'重要挽留客户\',
        \'001\':\'重要发展客户\',
        \'110\':\'一般价值客户\',
        \'010\':\'一般保持客户\',
        \'100\':\'一般挽留客户\',
        \'000\':\'一般发展客户\',
    }
    respons = dit[val]
    return respons
rfm[\'level\'] = rfm.apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm

 第五部分:用户生命周期

第五部分:用户的生命周期
    - 将用户划分为活跃用户和其他用户
        - 统计每个用户每个月的消费次数
        - 统计每个用户每个月是否消费,消费为 1 否则为 0
            - 知识点:DataFrame的apply和applymap的区别
                - applymap:返回df
                - 将函数做用于DataFrame中的所有元素(elements)
                - apply:返回Series
                - apply()将一个函数作用于DataFrame中的每个行或者列
        - 将用户按照每一个月份分成:
            - unreg:观望用户(前两月没买,第三个月才第一次买,则用户前两个月为观望用户)
            - unactive:首月购买后,后序月份没有购买则在没有购买的月份中该用户的为非活跃用户
            - new:当前月就进行首次购买的用户在当前月为新用户
            - active:连续月份购买的用户在这些月中为活跃用户
            - return:购买之后间隔n月再次购买的第一个月份为该月份的回头客

代码实现

import pandas as pd
from pandas import DataFrame
df = pd.read_csv(r\'H:\py\高级\数据分析\科学计算基础包-numpy\CDNOW_master.txt\',sep=\'\s+\',header=None,names=[\'user_id\',\'order_dt\',\'order_product\',\'order_amount\'])
df[\'order_dt\'] = pd.to_datetime(df[\'order_dt\'],format=\'%Y%m%d\')
df[\'month\'] = df[\'order_dt\'].astype(\'datetime64[M]\')
df

# 统计每个用户每个月的消费次数
month_sum = df.pivot_table(index=\'user_id\',values=\'order_dt\',aggfunc=\'count\',columns=\'month\').fillna(0)

# 统计每个用户每个月是否消费,消费为 1 否则为 0
month_sum = df.pivot_table(index=\'user_id\',values=\'order_dt\',aggfunc=\'count\',columns=\'month\').fillna(0)
df_purchase = month_sum.applymap(lambda x:1 if x>0 else 0 )
df_purchase

区分用户类别

#将df_purchase中的原始数据0和1修改为new,unactive......,返回新的df叫做df_purchase_new
#固定算法
month_sum = df.pivot_table(index=\'user_id\',values=\'order_dt\',aggfunc=\'count\',columns=\'month\').fillna(0)
one_zero = month_sum.applymap(lambda x:\'1\' if x>0 else \'0\' )

def active_status(data):
    status = []#某个用户每一个月的活跃度
    for i in range(18):
        
        #若本月没有消费
        if data[i] == 0:
            if len(status) > 0:
                if status[i-1] == \'unreg\':
                    status.append(\'unreg\')
                else:
                    status.append(\'unactive\')
            else:
                status.append(\'unreg\')
                    
        #若本月消费
        else:
            if len(status) == 0:
                status.append(\'new\')
            else:
                if status[i-1] == \'unactive\':
                    status.append(\'return\')
                elif status[i-1] == \'unreg\':
                    status.append(\'new\')
                else:
                    status.append(\'active\')
    return status

pivoted_status = df_purchase.apply(active_status,axis=1)


# 转为 list 格式
pivoted_status_list = pivoted_status.values.tolist()

# 生成新的数据表
# new_start_info = DataFrame(data=start_list)
# 生成新的数据表并更换回原 index
new_start_info = DataFrame(data=pivoted_status_list,index=month_sum.index,columns=month_sum.columns)
new_start_info

每月【不同活跃】用户的计数
  - purchase_status_ct = df_purchase_new.apply(lambda x : pd.value_counts(x)).fillna(0)
  - 转置进行最终结果的查看

new_start_info_ct = new_start_info.apply(lambda x : pd.value_counts(x)).fillna(0)
new_start_info_ct

new_start_info_ct.T

 

分类:

技术点:

相关文章: