كيفية تجنب حلقة في R:اختيار العناصر من القائمة

StackOverflow https://stackoverflow.com/questions/1355355

  •  20-09-2019
  •  | 
  •  

سؤال

يمكنني حل هذه المشكلة باستخدام الحلقات، لكنني أحاول التفكير في المتجهات، لذا سيكون الكود الخاص بي أكثر تصميمًا على طراز R.

لدي قائمة بالأسماءالتنسيق هو الاسم الأول_اسم العائلة.أريد أن أخرج من هذه القائمة قائمة منفصلة بالأسماء الأولى فقط.لا يبدو أنني أفكر في كيفية القيام بذلك.فيما يلي بعض الأمثلة على البيانات:

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- strsplit(t,"_")

الذي يبدو مثل هذا:

> tsplit
[[1]]
[1] "bob"   "smith"

[[2]]
[1] "mary" "jane"

[[3]]
[1] "jose"  "chung"

[[4]]
[1] "michael" "marx"   

[[5]]
[1] "charlie" "ivan"   

يمكنني الحصول على ما أريد باستخدام حلقات مثل هذا:

for (i in 1:length(tsplit)){
    if (i==1) {t_out <- tsplit[[i]][1]} else{t_out <- append(t_out, tsplit[[i]][1])} 
}

والذي من شأنه أن يعطيني هذا:

t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

إذن كيف يمكنني القيام بذلك بدون حلقات؟

هل كانت مفيدة؟

المحلول

ويمكنك استخدام apply (أو sapply)

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
f <- function(s) strsplit(s, "_")[[1]][1]
sapply(t, f)

bob_smith    mary_jane   jose_chung michael_marx charlie_ivan 

       "bob"       "mary"       "jose"    "michael"    "charlie" 

وانظر: نبذة مقدمة "تطبيق" في R

نصائح أخرى

واحد أكثر النهج:

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
pieces <- strsplit(t,"_")
sapply(pieces, "[", 1)

في الكلمات، السطر الأخير استخراج العنصر الأول من كل عنصر من القائمة ثم يبسط عليه في ناقلات.

وكيف يعمل هذا؟ حسنا، أنت بحاجة إلى أن ندرك وسيلة بديلة للكتابة x[1] هي "["(x, 1)، أي هناك وظيفة تسمى [ التي لا subsetting. تنطبق هذه الدعوة sapply المكالمات هذه الوظيفة مرة واحدة لكل عنصر من عناصر القائمة الأصلية، ويمر في حجتين، عنصر القائمة و1.

وميزة هذا النهج على الآخرين هو أنه يمكنك استخراج عناصر متعددة من القائمة دون الحاجة إلى إعادة حساب الانقسامات. على سبيل المثال، سوف sapply(pieces, "[", 2) اسم العائلة. وبمجرد أن تعتاد على هذا المصطلح، انها جميلة سهلة القراءة.

وماذا عن:

وtlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
fnames <- gsub("(_.*)$", "", tlist)
# _.* matches the underscore followed by a string of characters
# the $ anchors the search at the end of the input string
# so, underscore followed by a string of characters followed by the end of the input string

وللنهج باستخدام التعابير المنطقية؟

وماذا عن:

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")

sub("_.*", "", t)

وأشك في هذا هو الحل الأكثر أناقة، لكنه يتفوق حلقات:

t.df <- data.frame(tsplit)
t.df[1, ]

وتحويل القوائم لإطارات البيانات حول الطريقة الوحيدة التي يمكنني الحصول عليها أن تفعل ما أريد. إنني أتطلع إلى قراءة الإجابات من قبل الناس الذين يفهمون الواقع وكيفية التعامل مع القوائم.

لقد حصلت عليه تقريبًا.هو - هي حقًا هي مجرد مسألة

  1. باستخدام واحدة من *apply وظائف للتكرار على قائمتك الحالية، غالبًا ما أبدأ بها lapply وأحيانا التحول إلى sapply
  2. إضافة وظيفة مجهولة تعمل على أحد عناصر القائمة في المرة الواحدة
  3. كنت تعرف بالفعل أنه كان strsplit(string, splitterm) وأنك في حاجة إلى الغريب [[1]][1] لاختيار الفصل الأول من الجواب
  4. ما عليك سوى تجميع كل ذلك معًا، بدءًا من المتغير المفضل namene (حيث نبتعد عن t أو c والأصدقاء)

الذي يعطي

> tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan") 
> fnames <- sapply(tlist, function(x) strsplit(x, "_")[[1]][1]) 
> fnames 
  bob_smith    mary_jane   jose_chung michael_marx charlie_ivan   
      "bob"       "mary"       "jose"    "michael"    "charlie" 
>

هل يمكن استخدام unlist():

> tsplit <- unlist(strsplit(t,"_"))
> tsplit
 [1] "bob"     "smith"   "mary"    "jane"    "jose"    "chung"   "michael"
 [8] "marx"    "charlie" "ivan"   
> t_out <- tsplit[seq(1, length(tsplit), by = 2)]
> t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

ويمكن أن تكون هناك طريقة أفضل لسحب فقط الإدخالات الفردية فهرستها، ولكن على أي حال سوف لا يكون لديك حلقة.

والنهج الآخر، على أساس سبيل المثال إلغاء إدراج brentonk في ...

وtlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- unlist(strsplit(tlist,"_"))
fnames <- tsplit[seq(1:length(tsplit))%%2 == 1]

وأود أن استخدام إلغاء إدراج التالية () - طريقة مقرها:

> t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
> tsplit <- strsplit(t,"_")
> 
> x <- matrix(unlist(tsplit), 2)
> x[1,]
[1] "bob"     "mary"    "jose"    "michael" "charlie"

والميزة الكبرى لهذا الأسلوب هو أنه لا يحل مشكلة مماثلة لالألقاب في نفس الوقت:

> x[2,]
[1] "smith" "jane"  "chung" "marx"  "ivan" 

والجانب السلبي هو أن عليك أن تكون على يقين من أن جميع أسماء مطابقة لهيكل firstname_lastname. إن وجدت لا ثم هذه الطريقة سوف كسر.

ومن الأصلي الكائن قائمة tsplit بالنظر في البداية، وهذا الأمر به:

unlist(lapply(tsplit,function(x) x[1]))

وكان استخراج العنصر الأول من جميع عناصر القائمة، ثم يحول قائمة لناقلات. Unlisting أولا إلى المصفوفة، ثم استخراج العمود قبضة هو أيضا طيب، ولكن بعد ذلك كنت تعتمد على حقيقة أن جميع عناصر قائمة لها نفس الطول. هنا هو الإخراج:

> tsplit

[[1]]
[1] "bob"   "smith"

[[2]]
[1] "mary" "jane"

[[3]]
[1] "jose"  "chung"

[[4]]
[1] "michael" "marx"   

[[5]]
[1] "charlie" "ivan"   

> lapply(tsplit,function(x) x[1])

[[1]]
[1] "bob"

[[2]]
[1] "mary"

[[3]]
[1] "jose"

[[4]]
[1] "michael"

[[5]]
[1] "charlie"

> unlist(lapply(tsplit,function(x) x[1]))

[1] "bob"     "mary"    "jose"    "michael" "charlie"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top