2016-12-29 18 views
1

このデータETLをPythonで処理できました。しかし、私はRと統合する必要があり、私はRを初めて使うので、ここで質問を投稿します。私はタイプSTART_DATEとEND_DATEに基づいて、日付を爆発したいと変数の「種類」ダミー変数の累積合計をR

元のデータが変数名START_DATE、END_DATEと3列があり、由来ダミー変数の上に合計する累積頻度を行う

start_date, end_date, type 
1/1/2016, 1/3/2016, A 
1/2/2016, 1/2/2016, B 
1/2/2016, 1/3/2016, A 

ここで私が達成しようとしたことの説明です。

レコードの1行目の場合、A型は毎日1/1から1/3(開始日と終了日が含まれます)に表示されます。

2行目には、B型が1/2にのみ表示されます。

これまでのところ、1/1には「A」、1/2には「A」と「B」、1/3には「A」が1つあります。

このようなプロセスは残りのレコードに対して繰り返されます。実際には、私は変数 "タイプ"で多くの行と異なる値を持っています

基本的には、変数 "タイプ"のすべての変数の頻度カウントを毎日行い、変数「型」のすべての固有変数のインデックス列としての日付と対応する頻度カウントのデータフレーム。それが明確になることを願っています。

私は予想通りティファニーのソリューションが動作しませんでした@それはそう

date,  A,  B 
1/1/2016, 1,  0 
1/2/2016, 2,  1 
1/3/2016, 2,  0 

新しいヘッダーとして最初の行では、次の形式のデータフレームを必要とします。彼/彼女の入れ子にされたループコード部分は私の次のサンプルコードのために分解する。

start_date end_date type 
1/1/16 1/3/16 A 
1/1/16 1/3/16 A 
1/1/16 1/8/16 B 
1/1/16 1/14/16 B 
1/5/16 1/19/16 B 
1/7/16 1/13/16 C 
1/9/16 1/18/16 A 
1/13/16 1/19/16 D 
1/13/16 1/19/16 A 
1/14/16 1/22/16 B 
1/15/16 1/29/16 B 
1/16/16 1/22/16 D 

正しい部分がある:事前に助けを

results <- data.frame(date = dates) 

for(t in unique(df$type)) { 
    for(d in dates) { 
    results[results$date == d, t] <- 
     length(df[df$start_date <= d & df$end_date >= d & df$type == t],'type') 
    } 
} 

感謝。私はstackoverフローコミュニティの精神で怠惰はないです表示するには、これは私が書いたPythonのバージョンです:

import pandas as pd 

df = pd.read_csv("dates.csv") 

factor_type = list(df['type'].unique()) 

columns = ['date'] 
columns.extend(factor_type) 


result = [] 

dates_dict = {} 
i = 0 


for index,row in df.iterrows(): 
    start_end = pd.date_range(row['start_date'], row['end_date']) 
    factor = row['variable_type'] 
    factor_index = factor_type.index(factor) 
    for x in start_end: 
     date_obj = x.date() 
     date_str = '%s/%s/%s' % (date_obj.month, date_obj.day,date_obj.year) 
     if date_str in dates_dict: 
      row_index = dates_dict[date_str] 
      result[row_index+1][factor_index+1]+=1 
     else: 
      dummy_row = [0]*len(factor_type) 
      dummy_row[factor_index]=1 
      result.append([date_str]+dummy_row) 
      dates_dict[date_str]=i+1 


result_df = pd.DataFrame(result,columns=columns) 
+0

dcastを使用して、あなたの入力と所望の出力との間のマッピングは明らかではありません。解説してください。 – MichaelChirico

+0

'A'カラムは2行目に1を入れてはいけませんか?もしそうなら、次のオプションは' library(data.table); by = c( "indx"、 "value"))、value〜type) 'dx(Dx) –

+0

ここでは、start_dateとend_dateの両方がカウントに含まれています。言い換えれば、両端の閉じた間隔です。 – Jin

答えて

4

ここでは、データテーブルを使用する2つの方法があります.1つは効率的ですが読みにくく、2つ目は効率が悪いが読みやすくなります。

まず、適切な日付クラスに両方の列を変換

library(data.table) 
cols <- c("start_date", "end_date") 
setDT(df)[, (cols) := lapply(.SD, as.IDate, format = "%m/%d/%Y"), .SDcols = cols] 

あまり効率的で溶液(Iはdata.tablesを使用している内部整数表現、むしろ数値いずれかのas.IDate機能)

シンプルな(しかしそれほど効率的ではない)方法は、(既に提供されていた)行単位で日付を展開してから、単純にdcastを実行することです。どちらも非常に効率的であり、あなたは、このソリューションではなくfoverlaps機能を使用して日付の全体的な範囲で動作し、ローの操作で必要としないtype

res <- df[, .(Date = seq.int(start_date, end_date, 1L), type), by = 1:nrow(df)] 
dcast(res, Date ~ type, length) 
# Using 'type' as value column. Use 'value.var' to override 
#   Date A B 
# 1: 2016-01-01 1 0 
# 2: 2016-01-02 2 1 
# 3: 2016-01-03 2 0 

より効率的なソリューション

を持っています。これで、すべての残っている最初のステップ(また、既に提供されたように)、全体的な範囲を作成し、開始と終了の範囲として設定し、(さらなる操作のため)キーを設定することである

Intervals <- data.table(start_date = df[, seq.int(min(start_date), max(end_date), 1L)]) # overall range 
Intervals[, end_date := start_date] # set start/end ranges as same values 
setkey(Intervals, start_date, end_date) # key 

foverlapsを実行することですそしてワイドフォーマットへの変換は、あなたのPythonコードの上に慎重に熟読せずに再

dcast(foverlaps(df, Intervals), start_date ~ type, length) 
# Using 'type' as value column. Use 'value.var' to override 
# start_date A B 
# 1: 2016-01-01 1 0 
# 2: 2016-01-02 2 1 
# 3: 2016-01-03 2 0 
1

私は、私は完全にあなたが探しているものを理解していないが、(あなたが言う「累積合計」 )実際に開いているアイテムの数を数えたいと思っています。

これが当てはまる場合は、最初の開始日とあなたの間の各日付最新のend_date。

library(lubridate) 
start_date <- c("1/1/2016", "1/2/2016", "1/2/2016") 
end_date <- c("1/3/2016", "1/2/2016", "1/3/2016") 
type <- c("A", "B", "A") 

次に来るものを簡単にするために文字列を日付に変換します。

df <- data.frame(start_date, end_date, type) 
df$start_date <- as.Date(mdy(df$start_date)) 
df$end_date <- as.Date(mdy(df$end_date)) 

あなたの最も古い開始日と最新の終了日の間の日付のベクトルを作成します。

dates <- seq(from = min(c(df$start_date, df$end_date)), 
      to = max(c(df$start_date, df$end_date)), 
      by = 1) 

あなたが望む形式でデータを取得する:あなたができるタイプの任意の数については、

results <- data.frame(date = dates, openA = NA, openB = NA) 
for(d in dates) { 
    results$openA[results$date == d] <- 
    length(df[df$start_date <= d & df$end_date >= d & df$type == "A"]) 

    results$openB[results$date == d] <- 
    length(df[df$start_date <= d & df$end_date >= d & df$type == "B"]) 
} 

results <- data.frame(date = dates) 

for(t in unique(df$type)) { 
    for(d in dates) { 
    results[results$date == d, t] <- 
     length(df[df$start_date <= d & df$end_date >= d & df$type == t]) 
    } 
} 
+0

ご意見ありがとうございます。ここで私はちょうどサンプルの小さなスナップショットを与えています。実際には、変数 "type"にはユニークな値がたくさんあるので、これらの値すべてを扱うループを使用する方が良いでしょうか? – Jin

+0

上記の代わりにタイプの外部ループを追加しました。 – tiffany

+0

あなたのコードにいくつかのバグがあるようです。より多くのサンプルデータと問題がどこにあるのか、私の変更された投稿をご覧ください。 – Jin

0

私はdplyr-ソリューションを提供したいです。

まず、データフレームdfを構築するためのティファニーの仕事を喜んで借ります。その後

  • df3<-bind_rows(apply(df2,1,function(x){ 
            data.frame(Date = unlist(x$dates))%>%mutate(type=x$type[1]) 
        }))%>% 
         group_by(Date)%>% 
         summarise(A = sum(type=="A"), 
           B = sum(type=="B")) 
    
日付と合計することによって、グループ、右の種類を添付して、すべてのこれらの日付

df2<-df%>% 
     rowwise()%>% 
     mutate(dates = list(as_date(start_date:end_date))) 
  • リストを開始から終了までの日付を持つリストを作成

  • +0

    これは、日付ごとにタイプごとに開始または終了がカウントされるため、異なる結果が得られると考えています。私。開始日と終了日が同じであるケースを2回カウントし、開始日と終了日の間の日付を無視します。 日付やタイプがたくさんある場合は、何らかのベクトル化(つまり適用)を強くお勧めします。 – tiffany

    +0

    @tiffanyあなたは正しいです。私は答えを書き直した – Dries