मान लें कि मेरे पास निम्न सरलीकृत तालिका है जिसमें गतिशील कॉलम a_x है (जहां x एक इंडेक्स है जैसे 0, 1, 2, 3, 4 ...) और b_x क्रमशः। a स्तंभों की संख्या हमेशा b स्तंभों की संख्या के बराबर होती है लेकिन स्तंभों की कुल संख्या गतिशील हो सकती है (हमेशा 3 a और 3 b नहीं)। इसे स्पष्ट करने के लिए निम्नलिखित उदाहरण मेरे डेटा की संरचना को दर्शाता है:

> d <- read.table(text = "10 20 25 0.3 0.23 0.34 
                          40 20 30 0.25 0.4 0.45")
> names(d) <- c("a_0", "a_1", "a_2", "b_0", "b_1", "b_2")
> d
   a_0 a_1 a_2  b_0  b_1  b_2
1  10  20  25   0.30 0.23 0.34
2  40  20  30   0.25 0.40 0.45

मैं a कॉलम को संबंधित b कॉलम से विभाजित करना चाहता हूं और परिणामों को नए c कॉलम में सहेजना चाहता हूं। डिवीजनों को करने के लिए मैं इस तरह से ट्रांसफॉर्म() फ़ंक्शन (हार्ड-कोडेड कॉलनेम के साथ) का उपयोग करता हूं:

transform(d, c_0 = as.numeric(as.character(a_0)) / as.numeric(as.character(b_0)))

इस तथ्य को देखते हुए कि मेरे इनपुट डेटा के कॉलम की संख्या हमेशा समान नहीं होती है, मैं इस चरण को स्वचालित रूप से (शायद) कॉलनामों में एक पैटर्न का उपयोग करके कैसे कर सकता हूं।

किसी भी सहायता की सराहना की जाएगी

r
2
gkoul 22 जिंदा 2020, 17:20
यह तेजी से बढ़ा :P
 – 
Sotos
22 जिंदा 2020, 17:59

6 जवाब

सबसे बढ़िया उत्तर

यहाँ कई दृष्टिकोण हैं। (1) और (1ए) सबसे अच्छे लगते हैं लेकिन अन्य अलग-अलग दृष्टिकोण दिखाते हैं। उनके पास एक ही कॉलम नाम और क्रम है जैसा कि प्रश्न में (1 ए) और (2) को छोड़कर है, लेकिन यदि कोई समस्या हो तो उन्हें आसानी से ठीक किया जा सकता है। (4a) को छोड़कर किसी भी पैकेज का उपयोग नहीं किया जाता है।

1) रूपांतरित करें

ix <- grep("a", names(d))
cbind(d, setNames(d[ix] / d[-ix], sub("a", "c", names(d)[ix])))
##   a_0 a_1 a_2  b_0  b_1  b_2       c_0      c_1      c_2
## 1  10  20  25 0.30 0.23 0.34  33.33333 86.95652 73.52941
## 2  40  20  30 0.25 0.40 0.45 160.00000 50.00000 66.66667

1a) यह (1) का एक रूपांतर है;

transform(d, c = setNames(d[ix], ix-1) / d[-ix])  # ix is from above
##   a_0 a_1 a_2  b_0  b_1  b_2       c.0      c.1      c.2
## 1  10  20  25 0.30 0.23 0.34  33.33333 86.95652 73.52941
## 2  40  20  30 0.25 0.40 0.45 160.00000 50.00000 66.66667

2) फिर से आकार दें लंबे रूप में कनवर्ट करें, विभाजन निष्पादित करें और वापस विस्तृत रूप में कनवर्ट करें।

varying <- split(names(d), sub("_.*", "", names(d)))
long <- reshape(d, dir = "long", varying = varying, v.names = names(varying))
reshape(transform(long, c = a / b), dir = "wide", idvar = "id")[-1]
##     a.1  b.1       c.1 a.2  b.2      c.2 a.3  b.3      c.3
## 1.1  10 0.30  33.33333  20 0.23 86.95652  25 0.34 73.52941
## 2.1  40 0.25 160.00000  20 0.40 50.00000  30 0.45 66.66667

3) लागू करें हम एक 3d सरणी में कनवर्ट कर सकते हैं और फिर apply का उपयोग कर सकते हैं।

nr <- nrow(d)
nc <- ncol(d)
cc <- apply(array(as.matrix(d), c(nr, nc / 2, 2)), 1:2, function(x) x[1] / x[2])
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
##   a_0 a_1 a_2  b_0  b_1  b_2       c_0      c_1      c_2
## 1  10  20  25 0.30 0.23 0.34  33.33333 86.95652 73.52941
## 2  40  20  30 0.25 0.40 0.45 160.00000 50.00000 66.66667

4) diff d के लॉग को ट्रांसपोज़ करें, डिफ़्स लें और एक्सप ट्रांसपोज़ करके लॉग ट्रांसपोज़ को उल्टा करें। फिर इसे d से जोड़ दें। यह समाधान मानता है कि सभी प्रविष्टियां सख्ती से सकारात्मक हैं (जो प्रश्न में मामला है) ताकि हम लॉग ले सकें।

nc <- ncol(d)
cc <- t(exp(-diff(t(log(d)), nc/2)))
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
##   a_0 a_1 a_2  b_0  b_1  b_2       c_0      c_1      c_2
## 1  10  20  25 0.30 0.23 0.34  33.33333 86.95652 73.52941
## 2  40  20  30 0.25 0.40 0.45 160.00000 50.00000 66.66667

(4a) diff.zoo एक ज्यामितीय अंतर का समर्थन करता है जो घटाव के बजाय एक विभाजन करता है। (चिड़ियाघर के वर्तमान संस्करण में diff.zoo की आवश्यकता है कि इनपुट के तत्व सख्ती से सकारात्मक हों लेकिन चिड़ियाघर के विकास संस्करण में यह प्रतिबंध हटा दिया गया है।)

library(zoo)

nc <- ncol(d)
cc <- 1 / t(diff(zoo(t(d)), nc/2, arith = FALSE))
colnames(cc) <- paste("c", seq(0, length = ncol(cc)), sep = "_")
cbind(d, cc)
##     a_0 a_1 a_2  b_0  b_1  b_2       c_0      c_1      c_2
## x.1  10  20  25 0.30 0.23 0.34  33.33333 86.95652 73.52941
## x.2  40  20  30 0.25 0.40 0.45 160.00000 50.00000 66.66667
4
G. Grothendieck 24 जिंदा 2020, 16:09

हम नामों से अंडरस्कोर के बाद सब कुछ हटा सकते हैं, उन्हें विभाजित कर सकते हैं और एक-एक करके विभाजित कर सकते हैं, अर्थात।

Reduce(`/`, split.default(d, gsub('_.*', '', names(d))))
#        a_0      a_1      a_2
#1  33.33333 86.95652 73.52941
#2 160.00000 50.00000 66.66667
2
Sotos 22 जिंदा 2020, 17:24

आप "ए" और "बी" कॉलम खोजने के लिए grep का उपयोग कर सकते हैं, और परिणाम को अपने transform में अच्छे setNames के साथ मैट्रिक्स के रूप में जोड़ सकते हैं।

transform(d, ind=setNames(d[, grep("a", names(d))] / d[, grep("b", names(d))], 
                          gsub(".*(\\D)", "", grep("a", names(d), value=T))))
#   a_0 a_1 a_2  b_0  b_1  b_2     ind.0    ind.1    ind.2
# 1  10  20  25 0.30 0.23 0.34  33.33333 86.95652 73.52941
# 2  40  20  30 0.25 0.40 0.45 160.00000 50.00000 66.66667
1
jay.sf 22 जिंदा 2020, 17:30

dplyr वाला एक विकल्प हो सकता है:

rename_all(select(d, starts_with("a"))/select(d, -starts_with("a")), 
           ~ paste("c", 1:(ncol(d)/2), sep = "_"))

        c_1      c_2      c_3
1  33.33333 86.95652 73.52941
2 160.00000 50.00000 66.66667
1
tmfmnk 22 जिंदा 2020, 17:38

tidyr के पास वास्तव में इसके लिए एक बहुत अच्छा नया कार्य है। इसे pivot_longer कहा जाता है जो gather फ़ंक्शन का अधिक परिष्कृत संस्करण है

d$id <- 1:nrow(d)
d.new <- d %>% pivot_longer(a_0:b_2, #what to pivot
               names_to = c(".value", "index"), #how names will change
               names_pattern = "(.)_(.)") #where to match names_to in the column names
d.new
# A tibble: 6 x 4
     id index     a     b
  <int> <chr> <int> <dbl>
1     1 0        10  0.3 
2     1 1        20  0.23
3     1 2        25  0.34
4     2 0        40  0.25
5     2 1        20  0.4 
6     2 2        30  0.45

यहां से आप जो चाहते हैं उसे करने से दूर एक साधारण उत्परिवर्तित हैं

d.new <- d.new %>%
    mutate(c = a/b)

pivot_wider नाम का एक सिस्टर फंक्शन भी है जो मूल्यों को वापस उसी में बदल सकता है जो वे थे।

d <- d.new %>%
    pivot_wider(everything(), names_from = c(index), values_from = c(a,b,c))
d
# A tibble: 2 x 10
     id   a_0   a_1   a_2   b_0   b_1   b_2   c_0   c_1   c_2
  <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     1    10    20    25  0.3   0.23  0.34  33.3  87.0  73.5
2     2    40    20    30  0.25  0.4   0.45 160    50    66.7

आईडी कॉलम को फेंक दिया गया था ताकि pivot_wider पंक्ति मानों को अलग करने के बारे में भ्रमित न हो। इन दोनों कार्यों में tidyselection का उपयोग किया जाता है, इसलिए यदि आपको यह नहीं पता कि कॉलम में कितने अनुक्रमणिका कहने के बजाय थे pivot_longer(a_0:b_2, आप pivot_longer(-id कह सकते हैं और id को छोड़कर सभी कॉलम pivot_longer फ़ंक्शन में उपयोग किए जाएंगे।

0
Justin Landis 22 जिंदा 2020, 18:43

आप a या b को sub वाले नामों से हटा सकते हैं और paste0 का उपयोग करके सभी इंडेक्स प्राप्त कर सकते हैं और कॉलम प्राप्त कर सकते हैं। कॉलम को क्रमबद्ध करने की कोई आवश्यकता नहीं है।

x <- substring(grep("^a_\\d+$", names(d), value = TRUE), 2)
cbind(d, setNames(d[paste0("a",x)] / d[paste0("b",x)], paste0("c",x)))
#  a_0 a_1 a_2  b_0  b_1  b_2       c_0      c_1      c_2
#1  10  20  25 0.30 0.23 0.34  33.33333 86.95652 73.52941
#2  40  20  30 0.25 0.40 0.45 160.00000 50.00000 66.66667
0
GKi 27 जिंदा 2020, 12:05