2017-08-29 6 views
1

私は、特定の会社が収益日の1年以内にニュースに登場した回数を計算し、同じ期間の他の企業と比較します。私は2つのパンダのデータフレームを持っています.1つは収益の日付、もう1つはニュースです。私の方法は遅いです。より良いパンダ/ナンバーワンの方法がありますか?どのように私はこれを書き換えることができPandasは各行ごとに異なる時間枠で2つのデータフレームを結合します

import pandas as pd 

companies = pd.DataFrame({'CompanyName': ['A', 'B', 'C'], 'EarningsDate': ['2013/01/15', '2015/03/25', '2017/05/03']}) 
companies['EarningsDate'] = pd.to_datetime(companies.EarningsDate) 

news = pd.DataFrame({'CompanyName': ['A', 'A', 'A', 'B', 'B', 'C'], 
        'NewsDate': ['2012/02/01', '2013/01/10', '2015/05/13' , '2012/05/23', '2013/01/03', '2017/05/01']}) 
news['NewsDate'] = pd.to_datetime(news.NewsDate) 

companies

CompanyName EarningsDate 
0 A   2013-01-15 
1 B   2015-03-25 
2 C   2017-05-03 

newsのように見えますが

CompanyName NewsDate 
0 A  2012-02-01 
1 A  2013-01-10 
2 A  2015-05-13 
3 B  2012-05-23 
4 B  2013-01-03 
5 C  2017-05-01 

のように見えますか?これは動作しますが、各データフレームが> 500k行であるため非常に遅いです。

company_count = [] 
other_count = [] 

for _, company in companies.iterrows(): 
    end_date = company.EarningsDate 
    start_date = end_date - pd.DateOffset(years=1) 
    subset = news[(news.NewsDate > start_date) & (news.NewsDate < end_date)] 

    mask = subset.CompanyName==company.CompanyName 
    company_count.append(subset[mask].shape[0]) 
    other_count.append(subset[~mask].groupby('CompanyName').size().mean()) 

companies['12MonCompanyNewsCount'] = pd.Series(company_count) 
companies['12MonOtherNewsCount'] = pd.Series(other_count).fillna(0) 

最終結果、companies

CompanyName EarningsDate 12MonCompanyNewsCount 12MonOtherNewsCount 
0 A   2013-01-15  2      2 
1 B   2015-03-25  0      0 
2 C   2017-05-03  1      0 
+0

これを試してください:https://stackoverflow.com/questions/22391433/count-the-frequency-that-a-value-occurs-in-a-dataframe-column – RetardedJoker

+0

'value_counts()'はここでは機能しません。私は集計するために別のウィンドウで2つのデータフレームを結合する必要があります。 –

答えて

2

ここに行きます。

12MonCompanyNewsCountを得るために、あなたは本当にきちんとしている、merge_asofを使用することができます。

companies['12MonCompanyNewsCount'] = pd.merge_asof(
    news, 
    companies, 
    by='CompanyName', 
    left_on='NewsDate', 
    right_on='EarningsDate', 
    tolerance=pd.Timedelta('365D'), 
    direction='forward' 
).groupby('CompanyName').count().NewsDate 

があなたの現在の実装の約2倍速く動作します(と良くスケールします)12MonOtherNewsCountについて

をどの、私は物事を繰り返すことなくそれをする方法を実際には実現できませんでした。私はこれがもう少し簡潔だと思う:

companies['12MonOtherNewsCount'] = companies.apply(
    lambda x: len(
     news[ 
      (news.NewsDate.between(x.EarningsDate-pd.Timedelta('365D'), x.EarningsDate, inclusive=False)) 
      &(news.CompanyName!=x.CompanyName) 
     ] 
    ), 
    axis=1 
) 

それは少し速いようです。

+1

素晴らしい、 'merge_asof'はまさに私が探していたものです。バージョン0.19.0で新しくなったようです。私は私のパンダをアップグレードし、私は行くのが良いです!どうもありがとうございます! –

+1

最近「merge_asof」が私に紹介されました。それは本当に命を救う人です! –

1

のように私はcompanies行を反復処理しないようにする方法を見つけることができません見えます。ただし、開始日の列をcompaniesに設定し、行全体を反復してcompaniesを作成し、条件に合致する日付と会社名のブール値インデックスをnewsとして作成することができます。その後、ブール値のand演算を実行し、結果のブール値配列を合計します。

コードが表示されたら、それは意味があると私は誓っています。

# create the start date column and the 12 month columns, 
# fill the 12 month columns with zeros for now 
companies['startdate'] = companies.EarningsDate - pd.DateOffset(years=1) 
companies['12MonCompanyNewsCount'] = 0 
companies['12MonOtherNewsCount'] = 0 

# iterate the rows of companies and hold the index 
for i, row in companies.iterrows(): 
    # create a boolean index when the news date is after the start date 
    # and when the news date is before the end date 
    # and when the company names match 
    ix_start = news.NewsDate >= row.startdate 
    ix_end = news.NewsDate <= row.EarningsDate 
    ix_samename = news.CompanyName == row.CompanyName 
    # set the news count value for the current row of `companies` using 
    # boolean `and` operations on the indices. first when the names match 
    # and again when the names don't match. 
    companies.loc[i,'12MonCompanyNewsCount'] = (ix_start & ix_end & ix_samename).sum() 
    companies.loc[i,'12MonOtherNewsCount'] = (ix_start & ix_end & ~ix_samename).sum() 

companies 
#returns: 

    CompanyName EarningsDate startdate 12MonCompanyNewsCount \ 
0   A 2013-01-15 2012-01-15      1 
1   B 2015-03-25 2014-03-25      0 
2   C 2017-05-03 2016-05-03      1 

    12MonOtherNewsCount 
0     2 
1     1 
2     0 
関連する問題