最近、Jiyouは私にタスクを与えました:上級管理チームのステータスに基づいてチームの安定性を計算することです。
彼が提供する安定性を計算するための2つのアルゴリズムがあります。1つ目は、Crutchley et al。(2002)、Yu Dongzhi and Chi Guohua(2004)の方法に基づいており、次の式を使用します。
t年からt + 1年までのチームの安定性を示します。STMTの値の範囲は[0,1]です。1に近いほど、チームの安定性が高くなります。表しオフィスでの役員の総数におけるt年を、表した幹部の数オフィスで中t年が、t年+ 1に(外出)左を、と表した幹部の数年間で、オフィスではありませんがtが、t + 1で在職していた(新しく追加された)人数。
2番目は次のようにわずかに変更されます。
t年からt + i年までの安定性を表します。
友人と話し合ったところ、いくつかの状況の定義は次のとおりです。
- 「上級管理職」の定義:幹部の数は、従業員の数ではなく、役職の数をカウントします(たとえば、1人の人が複数の「上級管理職」と見なされる複数の仕事をしている場合があります)。
- 「上級管理職」の定義:彼が私に提供した情報は、「社外取締役および独立取締役を除く、会長、取締役、部長、副部長などを含む」と述べていました。これには具体的に何が含まれますか。言うのは難しいですが、データを確認して、キャッシャー、会計士、工場長、チームリーダーなど、1,000人を超えるポジションがエグゼクティブとしてカウントされない可能性がありますが、フィルタリングするにはポジションが多すぎることを確認してください。便宜上、上級管理職を、上記のすべての役職を含め、社外取締役および独立取締役を除くすべての役職に設定します。
- 以下のためにオフィス、新しい、出て行くには、三つの状態を定義します。このようやな出発時刻は、2014年12月にあった場合は、その後、2014年に彼はまだすべてのそれのではないでしょうか?すべての後、私は2014年に数ヶ月のためにオフィスにされている。2015年11月に新たな予定の日付に似ては、2015以下のようにベース友人と相談した後、3つの状態が定義されているオフィスでは考慮されています?新しい予定年、出発年オフィスでもカウントされます。
- 新しい予約時間と出発時間の空またはN / Aの定義:私の友人は彼らが無料またはN / A削除されていることを示唆していますが、計算の安定性は個人の履歴書と在職期間に直接関係していないと思います。年次報告書の新しい任命/辞任時間は、新しい任命/辞任に関係なく、報告年の在職者と見なされます。
- 異常なデータ:1。企業が1年以内に複数の期間に何度も報告し、報告の内容が重複、異なる、または変更されているという問題があります。2.一部のデータを含む出発時刻は、報告時刻(報告時刻)の後です。つまり、報告時刻が2014年12月31日で、出発時刻が2015年の特定の日であると仮定すると、これは予想される辞任として理解されます。しかし、2014年のレポートでは2015年に辞任した人がいますが、2015年のレポートでは辞任する時間がありません。
属性名 | 証券コード | 統計の締め切り | 個人ID | 名前 | 特定の職務 | 開始日 | 終了日 | 雇われていますか | 任期 |
説明 | 会社を表すために使用される一意の識別子 | 会社が報告書を提出するとき | すべての従業員の一意のIDを示します | - | 開催された役職の名前 | 対応するジョブの開始時間 | 対応するジョブの終了時間 | レポートが送信されたときにその人がその位置にいるかどうかを示します | 任命の開始から統計的期限までの任期、 |
範囲 | 空ではない6桁 | 空ではない日付形式 | 空ではない可変長の数値 | 空ではなく、繰り返す可能性があります | メッセージには投稿が1つしかなく、空ではありませんが、複数の表現の問題があります | 日付形式、空またはN / Aの場合があります | 期間形式、空またはN / Aの場合があります | 0(現在機能していない)または1(現在機能している) | 単位は月です。正の整数または空(用語の開始日が空またはN / Aの場合) |
名前の重複の問題がある可能性があるため、個人IDは独立した個人を表すために使用されます。役職と任期が以前の属性から導き出せるかどうかにかかわらず、そうしないことを選択できます。ただし、1年以内に複数回データを送信するという問題があるため、重複を防ぐために、次の構造を使用して結果を保存します。
証券コード:年:人員ID:[現在のポジションテーブル:[ポジション1、ポジション2 、、 ...]、新しいポジションテーブル:[ポジション1、ポジション2 、、 ...]、発信ポジションテーブル:[ポジション1 、位置2 、、 ...]]
特定の会社の特定の年における特定の従業員の在職、新規任命および辞任を示すために使用され、毎年の在職、新規任命および辞任の詳細なステータスを示すために使用されます。
アイデア:各情報を読んで、会社の銘柄コード、統計期限、人員ID、および特定の役職を取得します。役職が独立取締役または社外取締役の場合は、直接スキップします(続行します)。統計的期限は))会社の従業員が現職テーブルにポジションを持っていない場合は、現職ポジションテーブルを追加します。ポジションの開始日を取得します。空でないかN / Aでない場合は、文字列をに変換します。日付形式、対応する年を抽出し、対応する年に会社の従業員の新しい現職のフォームにポジションを追加し(すでに存在する場合はスキップします)、同じ方法で仕事を辞めます。このように、予約日、新規予約日、報告日の関係を区別する必要はありません。保存後、各企業の在職者数、出向者数、新規予定数を毎年取得し、リストMに保存するのは簡単です。2つの式に大きな違いはありません。今回は2番目の式(SI)を計算します。 。各社の各年のSI(2014年から2019年まで、式ではiを1とする)では、その年の在職者数をMt、その年の辞任者数を、、翌年の在職者数はMt + 1で表され、翌年の新規追加数はで表されます。
import xlrd
import datetime
import xlwt
READ=True
PREPROCESS=True
CAL=True
WRITE=True
if READ:
table=xlrd.open_workbook('高管团队任职情况.xlsx')
t=table.sheet_by_index(0)
N=t.nrows
#计算在t年在任在第t+1年离任的人数 没用到
#计算第t年的高管总人数
#计算第t年不在任 第t+1年新任的人数
#股票代码用string 存储
position_out=['外部董事','独立董事']
M=dict() #公司每年的在任/离任/新任人数 格式: 公司号(股票代号):年份:[在任人数,离任,新任]
SI=dict()
#同年离任/新任也算在任
#数据出现问题
if PREPROCESS:
Detail=dict()#详细表 公司号:年份:员工id:{在任:[],离任:[].新任:[]}
for l in range(3,N):#第3行开始为数据
stkcd=str(int(t.cell_value(l,0)))
Reptdt=str(t.cell_value(l,1))#统计截止日期
PersonID=str(int(t.cell_value(l,2)))
Position=t.cell_value(l,4)
if Position in position_out:
#不在其位,不谋其政
continue
StartDate=str(t.cell_value(l,5))
EndDate=str(t.cell_value(l,6))
Tenure_value=str(t.cell_value(l,8))#没用到
ReptYear=Reptdt[:4]#取字符串的前四位,表示年份
if stkcd not in Detail:#如果不存在则创建
Detail[stkcd]=dict()
if ReptYear not in Detail[stkcd]:
Detail[stkcd][ReptYear]=dict()
if PersonID not in Detail[stkcd][ReptYear]:
Detail[stkcd][ReptYear][PersonID]={0:[],-1:[],1:[]}#0:在任,1:新任,-1:离任
ReptDateTime=datetime.datetime.strptime(Reptdt,'%Y-%m-%d')
if Position not in Detail[stkcd][ReptYear][PersonID][0]:
Detail[stkcd][ReptYear][PersonID][0].append(Position)#不在表内则添加
if len(StartDate)>4:#如果长度大于4(不为空或N/A)
StartDateTime=datetime.datetime.strptime(StartDate,'%Y-%m-%d')
if str(StartDateTime.year) not in Detail[stkcd]:
Detail[stkcd][str(StartDateTime.year)]=dict()
if PersonID not in Detail[stkcd][str(StartDateTime.year)]:
Detail[stkcd][str(StartDateTime.year)][PersonID]={0:[],-1:[],1:[]}
if Position not in Detail[stkcd][str(StartDateTime.year)][PersonID][1]:#新任
Detail[stkcd][str(StartDateTime.year)][PersonID][1].append(Position)
if Position not in Detail[stkcd][str(StartDateTime.year)][PersonID][0]:#在任
Detail[stkcd][str(StartDateTime.year)][PersonID][0].append(Position)
if len(EndDate)>4:#离任同理
EndDateTime=datetime.datetime.strptime(EndDate,'%Y-%m-%d')
if str(EndDateTime.year) not in Detail[stkcd]:
Detail[stkcd][str(EndDateTime.year)]=dict()
if PersonID not in Detail[stkcd][str(EndDateTime.year)]:
Detail[stkcd][str(EndDateTime.year)][PersonID]={0:[],-1:[],1:[]}
if Position not in Detail[stkcd][str(EndDateTime.year)][PersonID][-1]:
Detail[stkcd][str(EndDateTime.year)][PersonID][-1].append(Position)
if Position not in Detail[stkcd][str(EndDateTime.year)][PersonID][0]:
Detail[stkcd][str(EndDateTime.year)][PersonID][0].append(Position)
if CAL:
for stkcd in Detail:
M[stkcd]=dict()
for year in Detail[stkcd]:
M[stkcd][year]=[0,0,0]#初始化
for PersonID in Detail[stkcd][year]:
M[stkcd][year][0]+=len(Detail[stkcd][year][PersonID][0])#统计
M[stkcd][year][1]+=len(Detail[stkcd][year][PersonID][1])
M[stkcd][year][2]+=len(Detail[stkcd][year][PersonID][-1])
for stkcd in M:
SI[stkcd]=dict()
for year in M[stkcd]:
if int(year)<=2013 or int(year)>=2019:#指定年份
continue
NextYear=str(int(year)+1)
Mj=M[stkcd][year][0]
if NextYear not in M[stkcd]:
SI[stkcd][year]=0
continue
Mjp1=M[stkcd][NextYear][0]
S1=M[stkcd][year][2] #在j年是 但j+1不是 计算离任
S2=M[stkcd][NextYear][1] #在j年不是但j+1是 计算新任
SI[stkcd][year]=(Mj-S1)/Mj*(Mjp1)/(Mj+Mjp1)+(Mjp1-S2)/Mjp1*Mj/(Mj+Mjp1)
if WRITE:
workspace=xlwt.Workbook(encoding='ascii')
excel=workspace.add_sheet('sheet1',cell_overwrite_ok=True)#添加第一张表
excel.write(0,0,'证券代码')
excel.write(0,1,'2014-2015')
excel.write(0,2,'2015-2016')
excel.write(0,3,'2016-2017')
excel.write(0,4,'2017-2018')
excel.write(0,5,'2018-2019')
c=1
for item in SI:
excel.write(c,0,item)
for year in range(2014,2019):
if str(year) in SI[item]:
excel.write(c,year-2013,SI[item][str(year)])
else:#如果没有该年的数据,则写入0
excel.write(c,year-2013,'0')
c=c+1
workspace.save('answer.xls')
それから私の友人は私が浙江大学から男のコードをどこで手に入れたのか知りませんでした。パンダを使用してテーブル全体を直接操作します:(彼は去った年を同じ年として数えないようで、stmtアルゴリズムを使用しています。私はISを使用しているため、2つの結果は異なります)
# -*- coding: utf-8 -*-
"""
Created on Fri May 15 17:03:55 2020
@author: hp
"""
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
df=pd.read_excel("Executives.xlsx")
df.columns=['Stkcd', 'Reptdt', 'Name', 'Position_type', 'Position', 'StartDate', 'EndDate','Note']
#有的列名是乱的代码要修改一下
df.drop([0,1],axis=0,inplace=True)
df.head()
#预处理
df['Reptdt']=pd.to_datetime(df['Reptdt'])
df['re_year']=df['Reptdt'].map(lambda x:x.year)
#将一行内的不同入职、离职日期合并
def min_date(x):
if x is None:
return None
else:
c=np.array(x.split(',')).astype(str)
return np.min(pd.to_datetime(c))
def max_date(x):
if x is None:
return None
else:
c=np.array(x.split(',')).astype(str)
return np.max(pd.to_datetime(c))
df['StartDate']=df['StartDate'].astype(str).map(min_date)
df['EndDate']=df['EndDate'].astype(str).map(max_date)
df['Reptdt2']=df['Reptdt']
import datetime
#由于统计时间的不同,同一个人会出现多次,把这多条记录合并
data=df.groupby(['Stkcd','Name']).agg({'Reptdt2':'max','Reptdt':'min',
'StartDate':'min','EndDate':'max'}).reset_index()
data['EndDate']=data['EndDate'].fillna(pd.to_datetime('2020-01-01'))
data['StartDate']=data['StartDate'].fillna(data['StartDate'].min())
#这里再进行缺失日期的填补,注意这里可能引入误差
data['st_year']=data['StartDate'].map(lambda x:x.year)
data['end_year']=data['EndDate'].map(lambda x:x.year)
data['re_min']=data['Reptdt'].map(lambda x:x.year)
data['re_max']=data['Reptdt2'].map(lambda x:x.year)
#计算部分
def stmt(df):
#先处理年份,从统计年份的最小年算到最大年
y1=df['re_min'].min()
y2=df['re_max'].max()
if y1==y2:
return None
stmt_list=[]
for i in range(y1,y2):#对每一年计算stmt
#入职时间小于等于当年,离职时间大于当年的记为在位(或入职离职均为当年的)
da=((df['st_year']<=i)&(df['end_year']>i))|((df['st_year']==i)&(df['end_year']==i))
m1=np.sum(da)
da=((df['st_year']<=i+1)&(df['end_year']>i+1))|((df['st_year']==i+1)&(df['end_year']==i+1))
m2=np.sum(da)
da=(df['st_year']<=i)&(df['end_year']==i+1)
s1=np.sum(da)#i年在位但下一年离任
da=(df['st_year']==i+1)
s2=np.sum(da)#i+1年新入职
if (m1==0)|(m2==0):
stmt_list.append(0)
else:
stmt12=(m1-s1)/m1*m2/(m1+m2)+(m2-s2)/m2*m1/(m1+m2)
stmt_list.append(stmt12)
return pd.DataFrame({'year':range(y1,y2),'stmt':stmt_list})
df_result=data.groupby(['Stkcd']).apply(stmt).reset_index()
df_result.drop(['level_1'],axis=1,inplace=True)
df_result['Stkcd']=df_result['Stkcd'].astype(str)
df_result.to_excel("stmt_result.xlsx")
その後、データの最初のバージョンが1年以内に複数の送信に対して存在し、2019年のデータが比較的小さいため、値の多くが0であり、ジョブ情報が混乱しているため、新しいバージョンが与えられましたこのバージョンのデータでは、会社は各年の終わり(12月31日)にのみデータを送信し、同じ人物の複数の役職の名前、開始時刻、および終了時刻が1つのメッセージに表示されます( 1行)。以下に示すように
(画像のアップロードがハングします。サーバーに小さな問題がある可能性があります)
最初のデータと比較して、データは元の従業員番号を名前に置き換え、任期と彼らが在職しているかどうかをキャンセルします。処理方法は最初の方法と同様です。つまり、位置を文字列に分割した後、対応する開始時刻と終了時刻を順番に取得し、新しいデータ、既存のデータ、および送信データを追加できます。
import xlrd
import datetime
import xlwt
READ=True
PREPROCESS=True
CAL=True
WRITE=True
if READ:
table=xlrd.open_workbook('高管团队稳定性指标11(1).xlsx')
t=table.sheet_by_index(0)
N=t.nrows
#计算在t年在任在第t+1年离任的人数 没用到
#计算第t年的高管总人数
#计算第t年不在任 第t+1年新任的人数
#股票代码用string 存储
position_out=['外部董事','独立董事']
M=dict() #公司每年的在任/离任/新任人数 格式: 公司号(股票代号):年份:[在任人数,离任,新任]
SI=dict()
#同年离任/新任也算在任
#数据出现问题
if PREPROCESS:
Detail=dict()#详细表 公司号:年份:员工id:{在任:[],离任:[].新任:[]}
for l in range(3,N):
stkcd=str(int(t.cell_value(l,0)))
Reptdt=str(t.cell_value(l,1))#统计截止日期
PersonID=(t.cell_value(l,2))
Positions=t.cell_value(l,4)
StartDates=str(t.cell_value(l,5))
EndDates=str(t.cell_value(l,6))
PositionList=Positions.split(',')#由于分割符单一,可以直接使用str.split代替re.split
StartDateList=StartDates.split(',')
EndDateList=EndDates.split(',')
ReptDateTime=datetime.datetime.strptime(Reptdt,'%Y-%m-%d')
Year=str(ReptDateTime.year)
if stkcd not in Detail:
Detail[stkcd]=dict()
if Year not in Detail[stkcd]:
Detail[stkcd][Year]=dict()
if PersonID not in Detail[stkcd][Year]:
Detail[stkcd][Year][PersonID]={0:[],-1:[],1:[]}
for Position in PositionList:
if Position in position_out:
#不在其位,不谋其政
continue
Detail[stkcd][Year][PersonID][0].append(Position)
if len(StartDates)>=6:
if PositionList.index(Position)<len(StartDateList):
StartDate=StartDateList[PositionList.index(Position)]
else:
continue
# StartDate=StartDateList[0]
if len(StartDate)>4:
StartDateTime=datetime.datetime.strptime(StartDate,'%Y-%m-%d')
StartYear=str(StartDateTime.year)
if StartYear not in Detail[stkcd]:
Detail[stkcd][StartYear]=dict()
if PersonID not in Detail[stkcd][StartYear]:
Detail[stkcd][StartYear][PersonID]={0:[],-1:[],1:[]}
if Position not in Detail[stkcd][StartYear][PersonID][1]:
Detail[stkcd][StartYear][PersonID][1].append(Position)
if Position not in Detail[stkcd][StartYear][PersonID][0]:
Detail[stkcd][StartYear][PersonID][0].append(Position)
if len(EndDates)>=6:
if PositionList.index(Position)<len(EndDateList):
EndDate=EndDateList[PositionList.index(Position)]
else:
continue
# EndDate=EndDateList[0]
if len(EndDate)>4:
EndDateTime=datetime.datetime.strptime(EndDate,'%Y-%m-%d')
EndYear=str(EndDateTime.year)
if EndYear not in Detail[stkcd]:
Detail[stkcd][EndYear]=dict()
if PersonID not in Detail[stkcd][EndYear]:
Detail[stkcd][EndYear][PersonID]={0:[],-1:[],1:[]}
if Position not in Detail[stkcd][EndYear][PersonID][1]:
Detail[stkcd][EndYear][PersonID][1].append(Position)
if Position not in Detail[stkcd][EndYear][PersonID][0]:
Detail[stkcd][EndYear][PersonID][0].append(Position)
if CAL:
for stkcd in Detail:
M[stkcd]=dict()
for year in Detail[stkcd]:
M[stkcd][year]=[0,0,0]
for PersonID in Detail[stkcd][year]:
M[stkcd][year][0]+=len(Detail[stkcd][year][PersonID][0])
M[stkcd][year][1]+=len(Detail[stkcd][year][PersonID][1])
M[stkcd][year][2]+=len(Detail[stkcd][year][PersonID][-1])
for stkcd in M:
SI[stkcd]=dict()
for year in M[stkcd]:
if int(year)<=2013 or int(year)>=2019:
continue
NextYear=str(int(year)+1)
Mj=M[stkcd][year][0]
if NextYear not in M[stkcd]:
SI[stkcd][year]=0
continue
Mjp1=M[stkcd][NextYear][0]
S1=M[stkcd][year][2] #在j年是 但j+1不是 计算离任
S2=M[stkcd][NextYear][1] #在j年不是但j+1是 计算新任
SI[stkcd][year]=(Mj-S1)/Mj*(Mjp1)/(Mj+Mjp1)+(Mjp1-S2)/Mjp1*Mj/(Mj+Mjp1)
if WRITE:
workspace=xlwt.Workbook(encoding='ascii')
excel=workspace.add_sheet('sheet1',cell_overwrite_ok=True)#添加第一张表
excel.write(0,0,'证券代码')
excel.write(0,1,'2014-2015')
excel.write(0,2,'2015-2016')
excel.write(0,3,'2016-2017')
excel.write(0,4,'2017-2018')
excel.write(0,5,'2018-2019')
c=1
for item in SI:
excel.write(c,0,item)
for year in range(2014,2019):
if str(year) in SI[item]:
excel.write(c,year-2013,SI[item][str(year)])
else:
excel.write(c,year-2013,'-1')
c=c+1
workspace.save('answer_new_data_3.xls')
データの別の人のコード(私はそれを実行しませんでした)
# -*- coding: utf-8 -*-
"""
Created on Fri May 15 17:03:55 2020
@author: hp
"""
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
df=pd.read_excel("Executives.xlsx")
df.columns=['Stkcd', 'Reptdt', 'Name', 'Position_type', 'Position', 'StartDate', 'EndDate','Note']
#有的列名是乱的代码要修改一下
df.drop([0,1],axis=0,inplace=True)
df.head()
#预处理
df['Reptdt']=pd.to_datetime(df['Reptdt'])
df['re_year']=df['Reptdt'].map(lambda x:x.year)
#将一行内的不同入职、离职日期合并
def min_date(x):
if x is None:
return None
else:
c=np.array(x.split(',')).astype(str)
return np.min(pd.to_datetime(c))
def max_date(x):
if x is None:
return None
else:
c=np.array(x.split(',')).astype(str)
return np.max(pd.to_datetime(c))
df['StartDate']=df['StartDate'].astype(str).map(min_date)
df['EndDate']=df['EndDate'].astype(str).map(max_date)
df['Reptdt2']=df['Reptdt']
import datetime
#由于统计时间的不同,同一个人会出现多次,把这多条记录合并
data=df.groupby(['Stkcd','Name']).agg({'Reptdt2':'max','Reptdt':'min',
'StartDate':'min','EndDate':'max'}).reset_index()
data['EndDate']=data['EndDate'].fillna(pd.to_datetime('2020-01-01'))
data['StartDate']=data['StartDate'].fillna(data['StartDate'].min())
#这里再进行缺失日期的填补,注意这里可能引入误差
data['st_year']=data['StartDate'].map(lambda x:x.year)
data['end_year']=data['EndDate'].map(lambda x:x.year)
data['re_min']=data['Reptdt'].map(lambda x:x.year)
data['re_max']=data['Reptdt2'].map(lambda x:x.year)
#计算部分
def stmt(df):
#先处理年份,从统计年份的最小年算到最大年
y1=df['re_min'].min()
y2=df['re_max'].max()
if y1==y2:
return None
stmt_list=[]
for i in range(y1,y2):#对每一年计算stmt
#入职时间小于等于当年,离职时间大于当年的记为在位(或入职离职均为当年的)
da=((df['st_year']<=i)&(df['end_year']>i))|((df['st_year']==i)&(df['end_year']==i))
m1=np.sum(da)
da=((df['st_year']<=i+1)&(df['end_year']>i+1))|((df['st_year']==i+1)&(df['end_year']==i+1))
m2=np.sum(da)
da=(df['st_year']<=i)&(df['end_year']==i+1)
s1=np.sum(da)#i年在位但下一年离任
da=(df['st_year']==i+1)
s2=np.sum(da)#i+1年新入职
if (m1==0)|(m2==0):
stmt_list.append(0)
else:
stmt12=(m1-s1)/m1*m2/(m1+m2)+(m2-s2)/m2*m1/(m1+m2)
stmt_list.append(stmt12)
return pd.DataFrame({'year':range(y1,y2),'stmt':stmt_list})
df_result=data.groupby(['Stkcd']).apply(stmt).reset_index()
df_result.drop(['level_1'],axis=1,inplace=True)
df_result['Stkcd']=df_result['Stkcd'].astype(str)
df_result.to_excel("stmt_result.xlsx")
概要:パンダパッケージを使用してテーブル全体を操作する方がはるかに高速であると感じています.xlwt / xlrdを使用して1つずつ読み取り、操作する習慣がありますが、適切に調査し、冗長性を大幅に簡素化する必要もあります。あなたはそれを正しく学びそして使うことができます/