كيفية تجنب حلقة في R:اختيار العناصر من القائمة
سؤال
يمكنني حل هذه المشكلة باستخدام الحلقات، لكنني أحاول التفكير في المتجهات، لذا سيكون الكود الخاص بي أكثر تصميمًا على طراز 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, ]
وتحويل القوائم لإطارات البيانات حول الطريقة الوحيدة التي يمكنني الحصول عليها أن تفعل ما أريد. إنني أتطلع إلى قراءة الإجابات من قبل الناس الذين يفهمون الواقع وكيفية التعامل مع القوائم.
لقد حصلت عليه تقريبًا.هو - هي حقًا هي مجرد مسألة
- باستخدام واحدة من
*apply
وظائف للتكرار على قائمتك الحالية، غالبًا ما أبدأ بهاlapply
وأحيانا التحول إلىsapply
- إضافة وظيفة مجهولة تعمل على أحد عناصر القائمة في المرة الواحدة
- كنت تعرف بالفعل أنه كان
strsplit(string, splitterm)
وأنك في حاجة إلى الغريب[[1]][1]
لاختيار الفصل الأول من الجواب - ما عليك سوى تجميع كل ذلك معًا، بدءًا من المتغير المفضل 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"