Dplyr के साथ कई कॉलम में योग करें


98

मेरे प्रश्न में एक डेटा फ्रेम के कई कॉलमों में मानों को समेटना और इस समन का उपयोग करके एक नया कॉलम बनाना शामिल है dplyr। कॉलम में डेटा प्रविष्टियां बाइनरी (0,1) हैं। मैं के एक पंक्ति-वार एनालॉग summarise_eachया mutate_eachफ़ंक्शन के बारे में सोच रहा हूं dplyr। नीचे डेटा फ्रेम का एक न्यूनतम उदाहरण है:

library(dplyr)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))

> df
   x1 x2 x3 x4 x5
1   1  1  0  1  1
2   0  1  1  0  1
3   0 NA  0 NA NA
4  NA  1  1  1  1
5   0  1  1  0  1
6   1  0  0  0  1
7   1 NA NA NA NA
8  NA NA NA  0  1
9   0  0  0  0  0
10  1  1  1  1  1

मैं कुछ का उपयोग कर सकता है जैसे:

df <- df %>% mutate(sumrow= x1 + x2 + x3 + x4 + x5)

लेकिन इसमें प्रत्येक कॉलम के नाम लिखना शामिल होगा। मुझे 50 कॉलम पसंद हैं। इसके अलावा, कॉलम के नाम लूप के विभिन्न पुनरावृत्तियों पर बदलते हैं जिसमें मैं इस ऑपरेशन को लागू करना चाहता हूं, इसलिए मैं किसी भी कॉलम नाम देने से बचने की कोशिश करना चाहूंगा।

मैं इसे सबसे कुशलता से कैसे कर सकता हूं? किसी भी सहायता की काफी सराहना की जाएगी।


11
क्यों dplyr? df$sumrow <- rowSums(df, na.rm = TRUE)आधार आर से सिर्फ एक सरल क्यों नहीं ? या df$sumrow <- Reduce(`+`, df)यदि आप उस सटीक चीज़ को दोहराना चाहते हैं जो आपने किया था dplyr
बजे डेविड अर्नबर्ग

7
आप दोनों के साथ या साथ में dplyrभी कर सकते हैंdf %>% mutate(sumrow = Reduce(`+`, .))df %>% mutate(sumrow = rowSums(.))
डेविड अर्नबर्ग

2
नवीनतम dplyrसंस्करण में अपडेट करें और यह काम करेगा।
डेविड अर्नबर्ग

1
डेविड Arenburg द्वारा सुझावों @DavidArenburg dplyr अद्यतन करने पैकेज के बाद से काम किया
एमो

1
@boern डेविड अर्गेनबर्ग टिप्पणी सबसे अच्छा जवाब और सबसे प्रत्यक्ष समाधान था। आपका उत्तर काम करेगा लेकिन इसमें NA मानों को शून्य के साथ प्रतिस्थापित करने का एक अतिरिक्त चरण शामिल है जो कुछ मामलों में उपयुक्त नहीं हो सकता है।
एमो

जवाबों:


112

कैसा रहेगा

प्रत्येक कॉलम को योग करें

df %>%
   replace(is.na(.), 0) %>%
   summarise_all(funs(sum))

प्रत्येक पंक्ति को योग करें

df %>%
   replace(is.na(.), 0) %>%
   mutate(sum = rowSums(.[1:5]))

8
summarise_eachप्रत्येक पंक्ति के साथ नीचे की ओर sums, जबकि आवश्यक है प्रत्येक पंक्ति के साथ योग है
amo

1
मैं वही हासिल करने की कोशिश कर रहा हूं, लेकिन मेरे डीएफ में एक कॉलम है जो एक चरित्र है, इसलिए मैं सभी कॉलमों को जोड़ नहीं सकता। मुझे लगता है कि मुझे (.[1:5])भाग को संशोधित करना चाहिए , लेकिन दुर्भाग्य से मैं सिंटैक्स से परिचित नहीं हूं और न ही मुझे पता है कि इस पर सहायता कैसे प्राप्त करें। कोशिश की mutate(sum = rowSums(is.numeric(.)))लेकिन साथ काम नहीं किया।
१२:०६ पर ccamara

5
समझा। आप df %>% replace(is.na(.), 0) %>% select_if(is.numeric) %>% summarise_each(funs(sum))एक शॉट देना चाहते हो सकता है ?
बोर्न

2
summarise_allइसके बजाय उपयोग के summarise_eachरूप में यह पदावनत किया गया है।
हैमसेन

2
mutate(sum = rowSums(.[,-1]))यदि आप नहीं जानते हैं कि आपको कितने कॉलमों से निपटने की आवश्यकता है, तो सिंटैक्स काम में आ सकता है।
पाउलो एस। अब्रेउ

32

यदि आप केवल कुछ कॉलमों का योग करना चाहते हैं, तो मैं कुछ इस तरह का उपयोग करूंगा:

library(dplyr)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))
df %>% select(x3:x5) %>% rowSums(na.rm=TRUE) -> df$x3x5.total
head(df)

इस तरह आप dplyr::selectसिंटैक्स का उपयोग कर सकते हैं ।


मैं दूसरों के ऊपर इस दृष्टिकोण को पसंद करता हूं क्योंकि उसे 0 से
माइकल बेलहाउस

और grep से बेहतर है क्योंकि x4: x11 जैसी चीजों से निपटना आसान है
Dov Rosenberg

32

मैं कुछ पैटर्न नामों के साथ चर पर योग करने के लिए नियमित अभिव्यक्ति मिलान का उपयोग करूंगा। उदाहरण के लिए:

df <- df %>% mutate(sum1 = rowSums(.[grep("x[3-5]", names(.))], na.rm = TRUE),
                    sum_all = rowSums(.[grep("x", names(.))], na.rm = TRUE))

इस तरह आप अपने डेटा फ्रेम के चर के कुछ समूह के योग के रूप में एक से अधिक चर बना सकते हैं।


महान समाधान! मैं एक हाल ही में रिलीज में ऐसा करने के लिए एक विशिष्ट सपने देखने वाले कार्य की तलाश कर रहा था, लेकिन इसे खोजने के लिए नहीं
agenis

यह समाधान महान है। यदि ऐसे कॉलम हैं जिन्हें आप शामिल नहीं करना चाहते हैं तो आपको एक विशिष्ट पैटर्न से मेल खाते कॉलम का चयन करने के लिए grep () स्टेटमेंट को डिजाइन करने की आवश्यकता है।
ट्रेंटन हॉफमैन

1
@TrentonHoffman यहाँ एक विशिष्ट पैटर्न से थोड़ा अचयनित कॉलम है। बस -संकेत चाहिए:rowSums(.[-grep("x[3-5]", names(.))], na.rm = TRUE)
alexb523

22

मैं अक्सर इस समस्या का सामना करता हूं, और ऐसा करने का सबसे आसान तरीका apply()एक mutateकमांड के भीतर फ़ंक्शन का उपयोग करना है ।

library(tidyverse)
df=data.frame(
  x1=c(1,0,0,NA,0,1,1,NA,0,1),
  x2=c(1,1,NA,1,1,0,NA,NA,0,1),
  x3=c(0,1,0,1,1,0,NA,NA,0,1),
  x4=c(1,0,NA,1,0,0,NA,0,0,1),
  x5=c(1,1,NA,1,1,1,NA,1,0,1))

df %>%
  mutate(sum = select(., x1:x5) %>% apply(1, sum, na.rm=TRUE))

यहाँ आप इस्तेमाल कर सकते हैं जो कुछ भी आप मानक का उपयोग कर स्तंभों का चयन करना चाहते हैं dplyrचाल (जैसे starts_with()या contains())। एक ही mutateआदेश के भीतर सभी काम करने से , यह कार्रवाई dplyrप्रसंस्करण चरणों की एक धारा के भीतर कहीं भी हो सकती है । अंत में, apply()फ़ंक्शन का उपयोग करके , आपके पास अपने स्वयं के उद्देश्य से निर्मित सारांश फ़ंक्शन सहित, जो भी सारांश की आवश्यकता है, उसका उपयोग करने का लचीलापन है।

वैकल्पिक रूप से, यदि एक गैर-विचित्र फ़ंक्शन का उपयोग करने का विचार अनुचित है, तो आप कॉलम को इकट्ठा कर सकते हैं, उन्हें संक्षेप में प्रस्तुत कर सकते हैं और अंत में परिणाम को मूल डेटा फ़्रेम में वापस जोड़ सकते हैं।

df <- df %>% mutate( id = 1:n() )   # Need some ID column for this to work

df <- df %>%
  group_by(id) %>%
  gather('Key', 'value', starts_with('x')) %>%
  summarise( Key.Sum = sum(value) ) %>%
  left_join( df, . )

यहां मैंने starts_with()कॉलम का चयन करने के लिए फ़ंक्शन का उपयोग किया और राशि की गणना की और आप जो चाहें NAमानों के साथ कर सकते हैं । इस दृष्टिकोण के लिए नकारात्मक पक्ष यह है कि यह बहुत लचीला है, यह वास्तव dplyrमें डेटा सफाई चरणों की एक धारा में फिट नहीं है ।


3
लगता applyहै कि जब यह क्या के rowSumsलिए डिजाइन किया गया था का उपयोग करने के लिए मूर्खतापूर्ण है ।
zacdav

6
इस मामले में rowSumsवास्तव में के रूप में अच्छी तरह से काम करता है rowMeans, लेकिन मैं हमेशा थोड़ा अजीब के बारे में सोच रहा था "क्या होगा अगर मुझे गणना करने की आवश्यकता एक योग या एक मतलब नहीं है?" हालाँकि, 99% समय मुझे ऐसा कुछ करना पड़ता है, यह या तो एक योग या एक applyसाधन है, इसलिए हो सकता है कि सामान्य फ़ंक्शन का उपयोग करने में लचीलेपन का अतिरिक्त थोड़ा भी वार न हो।
डेरेक सोंडेगर

22

का प्रयोग reduce()से purrrथोड़ा तेज की तुलना में है rowSumsऔर निश्चित रूप से तेजी से apply, जब से तुम बार-बार दोहराना सभी पंक्तियों पर से बचने और बस vectorized संचालन का लाभ लें:

library(purrr)
library(dplyr)
iris %>% mutate(Petal = reduce(select(., starts_with("Petal")), `+`))

इसे समय के लिए देखें


मुझे यह पसंद है लेकिन जब आप की आवश्यकता होगी तो आप इसे कैसे करेंगेna.rm = TRUE
14

@ देखें 24 मुझे यकीन नहीं है कि मुझे पता है कि आपका क्या मतलब है। यह रकम वैक्टर + b + c, सभी की लंबाई समान है। चूंकि प्रत्येक वेक्टर विभिन्न स्थानों में NA है या नहीं हो सकता है, आप उन्हें अनदेखा नहीं कर सकते। यह वैक्टर को अलिखित बना देगा। यदि आप NA मूल्यों को हटाना चाहते हैं, तो आपको इसे बाद में करना होगा, उदाहरण के लिए, drop_na
skd

मैंने rowSums(select(., matches("myregex")) , na.rm = TRUE))एनए को नजरअंदाज करने के संदर्भ में जरूरत के हिसाब से ऐसा करना शुरू कर दिया। इसलिए यदि संख्याएं sum(NA, 5)परिणाम हैं 5. तो आपने कहा कि कम करना बेहतर है rowSumsइसलिए मैं सोच रहा था कि क्या इस स्थिति में इसका उपयोग करने का कोई तरीका है?
24

समझा। यदि आप योग चाहते हैं और NA मानों को अनदेखा करना चाहते हैं तो निश्चित रूप से rowSumsसंस्करण सबसे अच्छा है। मुख्य नुकसान यह है कि केवल rowSumsऔर rowMeansउपलब्ध हैं (यह कम से कम धीमी है, लेकिन बहुत अधिक नहीं है)। यदि आपको एक और ऑपरेशन करने की आवश्यकता है (योग नहीं) तो reduceसंस्करण शायद एकमात्र विकल्प है। बस applyइस मामले में उपयोग करने से बचें ।
स्कद

1

के नए संस्करण में dplyrआप उपयोग कर सकते हैं rowwise()के साथ c_acrossकाम करता है विशिष्ट पंक्ति-वार वेरिएंट की जरूरत नहीं है कि के लिए पंक्ति-वार एकत्रीकरण प्रदर्शन करने के लिए, लेकिन अगर पंक्ति-वार संस्करण मौजूद है यह तेजी से होना चाहिए।

चूँकि rowwise()समूह बनाने का एक विशेष रूप है और जिस तरह से क्रिया के काम में बदलाव आता है, आप ungroup()अपने पंक्ति-वार ऑपरेशन को करने के बाद उसे पाइप करना चाहेंगे ।

पंक्तियों की एक श्रृंखला का चयन करने के लिए:

df %>%
  dplyr::rowwise() %>% 
  dplyr::mutate(sumrange = sum(dplyr::c_across(x1:x5), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()

प्रकार से पंक्तियों का चयन करने के लिए:

df %>%
  dplyr::rowwise() %>% 
  dplyr::mutate(sumnumeric = sum(c_across(where(is.numeric)), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()

आपके विशिष्ट मामले में एक पंक्ति-वार संस्करण मौजूद है, इसलिए आप निम्न कार्य कर सकते हैं ( acrossइसके बजाय नोट का उपयोग करें ):

df %>%
  dplyr::mutate(sumrow = rowSums(dplyr::across(x1:x5), na.rm = T))
# %>% dplyr::ungroup() # you'll likely want to ungroup after using rowwise()

अधिक जानकारी के लिए पेज को rowwise पर देखें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.