একটি আর ডাটাফ্রেমে প্রতিটি সারির জন্য


173

আমার একটি ডেটাফ্রেম রয়েছে এবং সেই ডাটাফ্রেমের প্রতিটি সারির জন্য আমাকে কিছু জটিল লুকআপ করতে হবে এবং একটি ফাইলে কিছু ডেটা যুক্ত করতে হবে।

জৈবিক গবেষণায় ব্যবহৃত 96 টি ভাল প্লেট থেকে নির্বাচিত কূপগুলির জন্য বৈজ্ঞানিক ফলাফল ডেটা ফ্রেমের রয়েছে যাতে আমি এর মতো কিছু করতে চাই:

for (well in dataFrame) {
  wellName <- well$name    # string like "H1"
  plateName <- well$plate  # string like "plate67"
  wellID <- getWellID(wellName, plateName)
  cat(paste(wellID, well$value1, well$value2, sep=","), file=outputFile)
}

আমার পদ্ধতিগত বিশ্বে আমি এমন কিছু করব:

for (row in dataFrame) {
    #look up stuff using data from the row
    #write stuff to the file
}

এটি করার জন্য "আর ওয়ে" কী?


আপনার প্রশ্ন এখানে কি? একটি ডাটা.ফ্রেম একটি দ্বি-মাত্রিক বস্তু এবং সারিগুলির উপরে লুপ করা কাজগুলি করার এক সাধারণ স্বাভাবিক উপায় কারণ সারিগুলি প্রতিটি কলামে সাধারণত 'ভেরিয়েবলের' পর্যবেক্ষণের সেট হয়।
ডার্ক এডেলবুয়েটেল

16
আমি যেটি শেষ করছি তা হ'ল: (1 ইনডেক্স: ন্রো (ডেটা ফ্রেম)) {সারি = ডেটা ফ্রেম [সূচক,]; # সারি দিয়ে স্টাফ করুন - যা আমার কাছে কখনও সুন্দর লাগেনি।
কার্ল কোরিয়েল-মার্টিন

1
GetWellID একটি ডাটাবেস বা কিছু কল? অন্যথায়, জনাথন সম্ভবত সঠিক এবং আপনি এটি ভেক্টরাইজ করতে পারেন।
শেন

উত্তর:


103

আপনি এটি ব্যবহার করতে পারেন, apply()ফাংশন ব্যবহার করে

> d
  name plate value1 value2
1    A    P1      1    100
2    B    P2      2    200
3    C    P3      3    300

> f <- function(x, output) {
 wellName <- x[1]
 plateName <- x[2]
 wellID <- 1
 print(paste(wellID, x[3], x[4], sep=","))
 cat(paste(wellID, x[3], x[4], sep=","), file= output, append = T, fill = T)
}

> apply(d, 1, f, output = 'outputfile')

76
সাবধান থাকুন, যেমন ডেটাফ্রেমটি ম্যাট্রিক্সে রূপান্তরিত হয় এবং আপনি কী ( x) দিয়ে শেষ করেন তা ভেক্টর। এই কারণেই উপরের উদাহরণটিতে সংখ্যার সূচকগুলি ব্যবহার করতে হবে; () পদ্ধতির সাহায্যে আপনাকে একটি ডেটা ফ্রেম দেয় যা আপনার কোডটিকে আরও দৃ rob় করে তোলে।
ড্যারেন কুক

আমার জন্য কাজ করে না। প্রয়োগ ফাংশনটি প্রতি x কে চ এর সাথে একটি বর্ণের মান হিসাবে দেয় এবং একটি সারি নয় not
জাহি

3
আপনি খেয়াল করুন যে আপনি নাম অনুসারে কলামগুলি উল্লেখ করতে পারেন। সুতরাং: wellName <- x[1]হতে পারে wellName <- x["name"]
ফান্ডড্রামা

1
যখন ড্যারেন দৃust়তার কথা উল্লেখ করেছিলেন, তখন তিনি কলামগুলির ক্রম সরিয়ে দেওয়ার মতো কিছু বোঝাতে চেয়েছিলেন। এই উত্তরটি কাজ করবে না যেখানে () সহ উত্তর এখনও কাজ করবে।
হ্যালো ওয়ার্ল্ড

120

আপনি by()ফাংশনটি ব্যবহার করতে পারেন :

by(dataFrame, 1:nrow(dataFrame), function(row) dostuff)

তবে সারিগুলির উপরে সরাসরি এটির পুনরাবৃত্তি আপনি যা চান তা খুব কমই হয়; পরিবর্তে আপনার ভেক্টরাইজ করার চেষ্টা করা উচিত। আমি জিজ্ঞাসা করতে পারি লুপের আসল কাজটি কী করছে?


5
ডেটা ফ্রেমে 0 টি সারি থাকলে 1:0খালি নয় এটি কার্যকর হবে না
এসডিস

10
0 সারির ক্ষেত্রে সহজে ফিক্স হ'ল seq_len () ব্যবহার করা , তার seq_len(nrow(dataFrame))জায়গায় .োকানো1:nrow(dataFrame)
জিম

13
আপনি কীভাবে বাস্তবায়ন করবেন (সারি)? এটি কি ডেটাফ্রেম $ কলাম? dataframe [somevariableNamehere]? আপনি আসলে এটি কীভাবে বলবেন। সিউডোকোড "ফাংশন (সারি) ডুস্টফ" এটি আসলে কীভাবে দেখবে?
uh_big_mike_boi

1
@ মাইক, dostuffএই উত্তরটির পরিবর্তন করুন str(row) আপনি "'ডেটা.ফ্রেম': এক্স ভেরিয়েবলের 1 টি ওবস দিয়ে শুরু করে কনসোলে একাধিক লাইন মুদ্রিত দেখতে পাবেন " " কিন্তু সতর্কতা অবলম্বন করা আবশ্যক পরিবর্তন dostuffকরতে rowসামগ্রিকভাবে বাইরের ম ফাংশনের জন্য একটি data.frame বস্তুর ফেরত দেয় না। পরিবর্তে এটি এক সারি ডেটা-ফ্রেমের একটি তালিকা ফেরত দেয়।
pwilcox

91

প্রথমত, ভেক্টরাইজিং সম্পর্কে জোনাথনের বক্তব্যটি সঠিক। যদি আপনার getWellID () ফাংশনটি ভেক্টরাইজড হয়, তবে আপনি লুপটি এড়িয়ে যেতে পারেন এবং কেবল বিড়াল বা রাইট সিএসভি ব্যবহার করতে পারেন:

write.csv(data.frame(wellid=getWellID(well$name, well$plate), 
         value1=well$value1, value2=well$value2), file=outputFile)

যদি getWellID () ভেক্টরাইজড না হয়, তবে জোনাথনের byপরামর্শ বা knguyen এর পরামর্শ কার্যকর করা applyউচিত।

অন্যথায়, আপনি যদি সত্যিই ব্যবহার করতে চান তবে আপনি forএই জাতীয় কিছু করতে পারেন:

for(i in 1:nrow(dataFrame)) {
    row <- dataFrame[i,]
    # do stuff with row
}

আপনি foreachপ্যাকেজটি ব্যবহার করার চেষ্টা করতে পারেন , যদিও এটির জন্য আপনাকে সেই সিনট্যাক্সের সাথে পরিচিত হওয়া প্রয়োজন। এখানে একটি সাধারণ উদাহরণ:

library(foreach)
d <- data.frame(x=1:10, y=rnorm(10))
s <- foreach(d=iter(d, by='row'), .combine=rbind) %dopar% d

চূড়ান্ত বিকল্পটি হ'ল plyrপ্যাকেজটির বাইরে কোনও ফাংশন ব্যবহার করা, এই ক্ষেত্রে কনভেনশনটি প্রয়োগ ফাংশনের সাথে খুব মিল।

library(plyr)
ddply(dataFrame, .(x), function(x) { # do stuff })

শেন, আপনাকে ধন্যবাদ। আমি কীভাবে ভেক্টরাইজড getWellID লিখতে হবে তা নিশ্চিত নই। এখনই আমার যা করা দরকার তা হ'ল তালিকাগুলির বিদ্যমান তালিকাগুলিটি অনুসন্ধান করতে বা এটি একটি ডেটাবেস থেকে টেনে আনতে dig
কার্ল কোরিয়েল-মার্টিন

নিখরচায় getWellID প্রশ্ন পোস্ট করুন (অর্থাত্ এই ফাংশনটি ভেক্টরাইজ করা যায়?) এবং আমি নিশ্চিত যে আমি (বা অন্য কেউ) এর উত্তর দেব।
শেন

2
এমনকি getWellID ভেক্টরাইজড না হলেও, আমি মনে করি আপনার এই সমাধানটি নিয়ে যাওয়া উচিত, এবং getWellId এর সাথে প্রতিস্থাপন করা উচিত mapply(getWellId, well$name, well$plate)
জোনাথন চ্যাং

এমনকি যদি আপনি এটি একটি ডাটাবেস থেকে টানেন, আপনি একবারে এগুলি সবগুলি টানতে পারেন এবং তারপরে ফলাফলটি আর এ ফিল্টার করতে পারেন; এটি একটি পুনরাবৃত্ত ফাংশনের চেয়ে দ্রুত হবে।
শেন

+1 এর জন্য foreach- আমি এর মধ্যে নরকটি ব্যবহার করতে যাচ্ছি।
জোশ বোদে

20

আমি মনে করি বেসিক আর এর সাথে এটি করার সর্বোত্তম উপায় হ'ল:

for( i in rownames(df) )
   print(df[i, "column1"])

ওভার সুবিধা for( i in 1:nrow(df))-approach আপনি কষ্ট পাবেন না যদি dfখালি এবং nrow(df)=0


17

আমি এই সাধারণ ইউটিলিটি ফাংশনটি ব্যবহার করি:

rows = function(tab) lapply(
  seq_len(nrow(tab)),
  function(i) unclass(tab[i,,drop=F])
)

বা একটি দ্রুত, কম পরিষ্কার ফর্ম:

rows = function(x) lapply(seq_len(nrow(x)), function(i) lapply(x,"[",i))

এই ফাংশনটি কেবল একটি ডাটা.ফ্রেমে সারিগুলির তালিকায় বিভক্ত করে। তারপরে আপনি এই তালিকার উপরে একটি "সাধারণ" তৈরি করতে পারেন:

tab = data.frame(x = 1:3, y=2:4, z=3:5)
for (A in rows(tab)) {
    print(A$x + A$y * A$z)
}        

প্রশ্ন থেকে আপনার কোড একটি ন্যূনতম পরিবর্তন সহ কাজ করবে:

for (well in rows(dataFrame)) {
  wellName <- well$name    # string like "H1"
  plateName <- well$plate  # string like "plate67"
  wellID <- getWellID(wellName, plateName)
  cat(paste(wellID, well$value1, well$value2, sep=","), file=outputFile)
}

কোনও সোজা তালিকার পরে ডেটা.ফ্রেমে অ্যাক্সেস করা দ্রুত।
iewআনিউস্কি-ওভেক

1
ডাবল ল্যাপ্লি দিয়ে একই জিনিসটি তৈরি করা আরও দ্রুত উপলব্ধি হয়েছে: সারি = ফাংশন (এক্স) ল্যাপ্লি (সিক_এলএন (নরো (এক্স)), ফাংশন (i) ল্যাপলি (এক্স, ফাংশন (সি) সি [i]))
Ł Iewানিউস্কি-ওওক

সুতরাং অভ্যন্তরটি lapplyপুরো ডেটাসেটের কলামগুলির উপরে পুনরাবৃত্তি করে xপ্রতিটি কলামকে নাম দেয় cএবং তারপরে iসেই কলামের ভেক্টর থেকে মঞ্চ প্রবেশ করে entry এটা কি সঠিক?
অ্যারন ম্যাকডেইড

খুব সুন্দর! আমার ক্ষেত্রে, আমি "ফ্যাক্টর" মান থেকে অন্তর্নিহিত মূল্য রূপান্তর ছিল: wellName <- as.character(well$name)
স্টিভ পিচারস

9

অ-ভেক্টরাইজড বিকল্পগুলির সময় পারফরম্যান্স সম্পর্কে আমি কৌতূহল ছিলাম। এই উদ্দেশ্যে, আমি knguyen দ্বারা সংজ্ঞায়িত f ফাংশনটি ব্যবহার করেছি

f <- function(x, output) {
  wellName <- x[1]
  plateName <- x[2]
  wellID <- 1
  print(paste(wellID, x[3], x[4], sep=","))
  cat(paste(wellID, x[3], x[4], sep=","), file= output, append = T, fill = T)
}

এবং তার উদাহরণের মতো ডেটাফ্রেম:

n = 100; #number of rows for the data frame
d <- data.frame( name = LETTERS[ sample.int( 25, n, replace=T ) ],
                  plate = paste0( "P", 1:n ),
                  value1 = 1:n,
                  value2 = (1:n)*10 )

বিড়ালের () পদ্ধতির সাথে একটি রাইট.টেবিল () এর সাথে তুলনা করার জন্য আমি দুটি ভেক্টরিযুক্ত ফাংশন (অন্যদের চেয়ে দ্রুত নিশ্চিত করার জন্য) অন্তর্ভুক্ত করেছি ...

library("ggplot2")
library( "microbenchmark" )
library( foreach )
library( iterators )

tm <- microbenchmark(S1 =
                       apply(d, 1, f, output = 'outputfile1'),
                     S2 = 
                       for(i in 1:nrow(d)) {
                         row <- d[i,]
                         # do stuff with row
                         f(row, 'outputfile2')
                       },
                     S3 = 
                       foreach(d1=iter(d, by='row'), .combine=rbind) %dopar% f(d1,"outputfile3"),
                     S4= {
                       print( paste(wellID=rep(1,n), d[,3], d[,4], sep=",") )
                       cat( paste(wellID=rep(1,n), d[,3], d[,4], sep=","), file= 'outputfile4', sep='\n',append=T, fill = F)                           
                     },
                     S5 = {
                       print( (paste(wellID=rep(1,n), d[,3], d[,4], sep=",")) )
                       write.table(data.frame(rep(1,n), d[,3], d[,4]), file='outputfile5', row.names=F, col.names=F, sep=",", append=T )
                     },
                     times=100L)
autoplot(tm)

ফলস্বরূপ চিত্রটি দেখায় যে প্রয়োগটি একটি নন-ভেক্টরাইজড সংস্করণটির জন্য সেরা পারফরম্যান্স দেয়, যেখানে Writ.table () বিড়ালটিকে ছাড়িয়ে গেছে বলে মনে হয় ()। ForEachRunningTime


6

আপনি এর জন্য by_rowপ্যাকেজ থেকে ফাংশনটি ব্যবহার করতে পারেন purrrlyr:

myfn <- function(row) {
  #row is a tibble with one row, and the same 
  #number of columns as the original df
  #If you'd rather it be a list, you can use as.list(row)
}

purrrlyr::by_row(df, myfn)

ডিফল্টরূপে, থেকে প্রাপ্ত ফেরত মানটি ডিএফ-তে myfnনতুন তালিকার কলামে স্থাপন করা হয় .out

আপনি যদি ইচ্ছা করেন তবে এটি আপনি লিখতে পারেন purrrlyr::by_row(df, myfn)$.out


2

ঠিক আছে, যেহেতু আপনি আর অন্য ভাষার সমতুল্য চেয়েছিলেন তাই আমি এটি করার চেষ্টা করেছি। কাজটি দেখে মনে হচ্ছে যদিও আমি আর টেকনিকটি আর-তে আরও দক্ষ really

> myDf <- head(iris)
> myDf
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
> nRowsDf <- nrow(myDf)
> for(i in 1:nRowsDf){
+ print(myDf[i,4])
+ }
[1] 0.2
[1] 0.2
[1] 0.2
[1] 0.2
[1] 0.2
[1] 0.4

শ্রেণীবদ্ধ কলামগুলির জন্য, এটি আপনাকে একটি ডেটা ফ্রেম এনেছে যা আপনি প্রয়োজনে as.character () ব্যবহার করে টাইপকাস্ট করতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.