2010-12-10 19 views
2

私は3列で始まるCSVを持っています。 Costs、Cost列、およびKeyword列の累積パーセンテージ列。 Rスクリプトは小さなファイルで動作しますが、実際のファイル(100万行)をフィードすると完全に終了しません。このスクリプトをより効率的にする手助けができますか? Token.Countは作成に問題があるものです。ありがとうございました!トークンの単語を数える最も効率的な方法

# Token Histogram 

# Import CSV data from Report Downloader API Feed 
Mydf <- read.csv("Output_test.csv.csv", sep=",", header = TRUE, stringsAsFactors=FALSE) 

# Helps limit the dataframe according the HTT 
# Change number to: 
# .99 for big picture 
# .8 for HEAD 
limitor <- Mydf$CumuCost <= .8 
# De-comment to ONLY measure TORSO 
#limitor <- (Mydf$CumuCost <= .95 & Mydf$CumuCost > .8) 
# De-comment to ONLY measure TAIL 
#limitor <- (Mydf$CumuCost <= 1 & Mydf$CumuCost > .95) 
# De-comment to ONLY measure Non-HEAD 
#limitor <- (Mydf$CumuCost <= 1 & Mydf$CumuCost > .8) 

# Creates a column with HTT segmentation labels 
# Creates a dataframe 
HTT <- data.frame() 
# Populates dataframe according to conditions 
HTT <- ifelse(Mydf$CumuCost <= .8,"HEAD",ifelse(Mydf$CumuCost <= .95,"TORSO","TAIL")) 
# Add the column to Mydf and rename it HTT 
Mydf <- transform(Mydf, HTT = HTT) 

# Count all KWs in account by using the dimension function 
KWportfolioSize <- dim(Mydf)[1] 

# Percent of portfolio 
PercentofPortfolio <- sum(limitor)/KWportfolioSize 

# Length of Keyword -- TOO SLOW 
# Uses the Tau package 
# My function takes the row number and returns the number of tokens 
library(tau) 
Myfun = function(n) { 
    sum(sapply(Mydf$Keyword.text[n], textcnt, split = "[[:space:][:punct:]]+", method = "string", n = 1L))} 
# Creates a dataframe to hold the results 
Token.Count <- data.frame() 
# Loops until last row and store it in data.frame 
for (i in c(1:dim(Mydf)[1])) {Token.Count <- rbind(Token.Count,Myfun(i))} 
# Add the column to Mydf 
Mydf <- transform(Mydf, Token.Count = Token.Count) 
# Not quite sure why but the column needs renaming in this case 
colnames(Mydf)[dim(Mydf)[2]] <- "Token.Count" 
+1

あなたはサンプルデータの一部にリンクすることができますか?あなたが速いかどうかを確かめるために、あなたのものに対して自分の方法をテストすることができるように、それを合成だけで十分に代表してください。 –

+0

CumuCost \tコスト\t Keyword.text 0.004394288 \t 678.5 \t北+顔+出口 0.006698245 \t 80.05 \tのKinectセンサ 0.008738991 \t 79.51 \t Xボックス360 250 – datayoda

+0

'data.frame':74231台のOBS。 5変数のうち $ CumuCost:num 0.00439 0.0067 0.00874 0.01067 0.01258 ... $費用:num 1678 880 780 736 731 ... $ Keyword.text:chr "north + face + outlet" "kinect sensor" "xボックス360 250 "... $ HTT:ファクタw/1レベル" HEAD ":1 1 1 1 1 1 1 1 1 1 ... $ Token.Count:int 3 2 4 1 4 2 2 2 2 1 ... – datayoda

答えて

2

ループでそれを埋める前に、ストレージを事前に割り当てます。 決してあなたがやっていることを行い、連結するか、r | cbindループ内のオブジェクト。 Rは、ループの各反復で、コピーや割り当てを増やす必要があります。これは、あなたのコードを損なうオーバーヘッドです。

Token.Countを十分な行数と列数で作成し、ループに入力します。以下のような何か:

Token.Count <- matrix(ncol = ?, nrow = nrow(Mydf)) 
for (i in seq_len(nrow(Mydf))) { 
    Token.Count[i, ] <- Myfun(i) 
} 
Token.Count <- data.frame(Token.Count) 

私はより具体的なことはできませんが、私はどのように多くの列Myfunリターンを知りません申し訳ありません。


アップデート1:textcntを見て撮影した、私はあなたがおそらく完全にループを避けることができると思います。あなたは、このデータフレームのようなもの

DF <- data.frame(CumuCost = c(0.00439, 0.0067), Cost = c(1678, 880), 
       Keyword.text = c("north+face+outlet", "kinect sensor"), 
       stringsAsFactors = FALSE) 

我々は

keywrds <- with(DF, as.list(Keyword.text)) 
head(keywrds) 

をキーワードを取り除くと、それをリストに変換する場合はその後、我々は内の単語をカウントするために、このリストに再帰的にtextcntを呼び出すことができますがあります各リストコンポーネント。

countKeys <- textcnt(keywrds, split = "[[:space:][:punct:]]+", method = "string", 
        n = 1L, recursive = TRUE) 
head(countKeys) 

上記のあなたは、私が個別に入力ベクトルのそれぞれを治療するためのrecursive = TRUEを追加除いて、持っていたものはほとんどです。

> sapply(countKeys, sum) 
[1] 3 2 

あなたがループし、機能を達成しようとしているかのように見える:最後のステップは、単語の数を取得するためにcountKeyssum機能をsapplyすることです。私はこの権利を持っていますか?


アップデート2:は、ベクトル化の方法でtextcntを使用事前割り当ての問題を修正した場合 OKは、まだあなたが希望ほど迅速ではありませんが、私たちは言葉をカウントする他の方法を調べることができます。 textcntのすべての機能が必要なことをする必要はない可能性もあります。 [以下のソリューションがすべてのデータに対して機能するかどうかを確認することはできませんが、それはずっと迅速です。]

一つの潜在的解決策は、最初の要素の上にのみ発生keywrdsを使用して、例えば、作り付けstrsplit関数を使用して単語にKeyword.textベクトルを分割することである。

> length(unlist(strsplit(keywrds[[1]], split = "[[:space:][:punct:]]+"))) 
[1] 3 

このアイデアを使用することが多分に容易ですユーザ関数でラップ:

私たちは、その後keywrdsリストに適用することができます
fooFun <- function(x) { 
    length(unlist(strsplit(x, split = "[[:space:][:punct:]]+"), 
        use.names = FALSE, recursive = FALSE)) 
} 

> sapply(keywrds, fooFun) 
[1] 3 2 

この単純な例のデータセットでは、同じ結果が得られます。計算時間はどうですか?第1更新からステップのうちの2つを組み合わせるtextcntを用いて溶液のための:

> system.time(replicate(10000, sapply(textcnt(keywrds, 
+          split = "[[:space:][:punct:]]+", 
+          method = "string", n = 1L, 
+          recursive = TRUE), sum))) 
    user system elapsed 
    4.165 0.026 4.285 

、次いでアップデート2溶液のための:だからも、この小さなサンプル用

​​

textcntを呼び出す際にかなりのオーバーヘッドがありますが、両方のアプローチを完全なデータセットに適用するときにこの相違が成立するかどうかは、まだわかりません。

最後に、我々はstrsplitアプローチがDFにベクトルKeyword.text上で直接動作するようにベクトル化することができることを注意してください。

> sapply(strsplit(DF$Keyword.text, split = "[[:space:][:punct:]]+"), length) 
[1] 3 2 

他の二つのアプローチと同じ結果を与え、そしてよりわずかに速くなりますstrsplitの非ベクトル使用:

> system.time(replicate(10000, sapply(strsplit(DF$Keyword.text, 
+        split = "[[:space:][:punct:]]+"), length))) 
    user system elapsed 
    0.732 0.001 0.734 

あなたの完全なデータセットに速くこれらのいずれかいますか?

マイナーアップデート:データの130行を与えることDFを複製し、3つのアプローチのタイミングと、最後は(strsplit()をベクトル化)ことを示唆しているより良いスケール:

> DF2 <- rbind(DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF,DF) 
> dim(DF2) 
[1] 130 3 
> system.time(replicate(10000, sapply(textcnt(keywrds2, split = "[[:space:][:punct:]]+", method = "string", n = 1L, recursive = TRUE), sum))) 
    user system elapsed 
238.266 1.790 241.404 
> system.time(replicate(10000, sapply(keywrds2, fooFun))) 
    user system elapsed 
28.405 0.007 28.511 
> system.time(replicate(10000, sapply(strsplit(DF2$Keyword.text,split = "[[:space:][:punct:]]+"), length))) 
    user system elapsed 
    7.497 0.011 7.528 
+0

照明は高速ではありませんが動作します。ありがとう! – datayoda

関連する問題