r - स्तंभों के एकाधिक सेट इकट्ठा करें




reshape dplyr (4)

मेरे पास एक ऑनलाइन सर्वेक्षण से डेटा है जहां उत्तरदाता 1-3 बार प्रश्नों के लूप से गुज़रते हैं। सर्वे सॉफ़्टवेयर (क्वालिटिक्स) इस डेटा को कई कॉलम में रिकॉर्ड करता है-अर्थात, सर्वेक्षण में Q3.2 में कॉलम Q3.2.1. , Q3.2.2. , और Q3.2.3. :

df <- data.frame(
  id = 1:10,
  time = as.Date('2009-01-01') + 0:9,
  Q3.2.1. = rnorm(10, 0, 1),
  Q3.2.2. = rnorm(10, 0, 1),
  Q3.2.3. = rnorm(10, 0, 1),
  Q3.3.1. = rnorm(10, 0, 1),
  Q3.3.2. = rnorm(10, 0, 1),
  Q3.3.3. = rnorm(10, 0, 1)
)

# Sample data

   id       time    Q3.2.1.     Q3.2.2.    Q3.2.3.     Q3.3.1.    Q3.3.2.     Q3.3.3.
1   1 2009-01-01 -0.2059165 -0.29177677 -0.7107192  1.52718069 -0.4484351 -1.21550600
2   2 2009-01-02 -0.1981136 -1.19813815  1.1750200 -0.40380049 -1.8376094  1.03588482
3   3 2009-01-03  0.3514795 -0.27425539  1.1171712 -1.02641801 -2.0646661 -0.35353058
...

मैं सभी QN.N * कॉलम को साफ-अलग व्यक्तिगत QN.N कॉलम में जोड़ना चाहता हूं, आखिरकार इस तरह कुछ खत्म हो रहा हूं:

   id       time loop_number        Q3.2        Q3.3
1   1 2009-01-01           1 -0.20591649  1.52718069
2   2 2009-01-02           1 -0.19811357 -0.40380049
3   3 2009-01-03           1  0.35147949 -1.02641801
...
11  1 2009-01-01           2 -0.29177677  -0.4484351
12  2 2009-01-02           2 -1.19813815  -1.8376094
13  3 2009-01-03           2 -0.27425539  -2.0646661
...
21  1 2009-01-01           3 -0.71071921 -1.21550600
22  2 2009-01-02           3  1.17501999  1.03588482
23  3 2009-01-03           3  1.11717121 -0.35353058
...

tidyr लाइब्रेरी में gather() फ़ंक्शन है, जो कॉलम के एक सेट को संयोजित करने के लिए बहुत अच्छा काम करता है:

library(dplyr)
library(tidyr)
library(stringr)

df %>% gather(loop_number, Q3.2, starts_with("Q3.2")) %>% 
  mutate(loop_number = str_sub(loop_number,-2,-2)) %>%
  select(id, time, loop_number, Q3.2)


   id       time loop_number        Q3.2
1   1 2009-01-01           1 -0.20591649
2   2 2009-01-02           1 -0.19811357
3   3 2009-01-03           1  0.35147949
...
29  9 2009-01-09           3 -0.58581232
30 10 2009-01-10           3 -2.33393981

परिणामी डेटा फ्रेम में 30 पंक्तियां हैं, जैसा कि अपेक्षित है (10 व्यक्तियों, 3 लूप प्रत्येक)। हालांकि, कॉलम का दूसरा सेट इकट्ठा करना सही ढंग से काम नहीं करता है-यह सफलतापूर्वक दो संयुक्त कॉलम Q3.2 और Q3.3 , लेकिन 30 की बजाय 90 पंक्तियों के साथ समाप्त होता है (10 व्यक्तियों के सभी संयोजन, Q3.2 के 3 loops , और Q3.3 के 3 loops; वास्तविक डेटा में कॉलम के प्रत्येक समूह के लिए संयोजन काफी हद तक बढ़ेगा):

df %>% gather(loop_number, Q3.2, starts_with("Q3.2")) %>% 
  gather(loop_number, Q3.3, starts_with("Q3.3")) %>%
  mutate(loop_number = str_sub(loop_number,-2,-2))


   id       time loop_number        Q3.2        Q3.3
1   1 2009-01-01           1 -0.20591649  1.52718069
2   2 2009-01-02           1 -0.19811357 -0.40380049
3   3 2009-01-03           1  0.35147949 -1.02641801
...
89  9 2009-01-09           3 -0.58581232 -0.13187024
90 10 2009-01-10           3 -2.33393981 -0.48502131

क्या इस तरह gather() करने के लिए एकाधिक कॉल का उपयोग करने का कोई तरीका है gather() इस तरह के स्तंभों की सही संख्या को बनाए रखते हुए इस तरह के स्तंभों के छोटे सबसेट को संयोजित करना?


यदि आप मेरे जैसे हैं, और extract लिए "कैप्चरिंग समूहों के साथ नियमित अभिव्यक्ति" का उपयोग कैसे करें, तो निम्न कोड हैडली के जवाब में extract(...) लाइन को दोहराता है:

df %>% 
    gather(question_number, value, starts_with("Q3.")) %>%
    mutate(loop_number = str_sub(question_number,-2,-2), question_number = str_sub(question_number,1,4)) %>%
    select(id, time, loop_number, question_number, value) %>% 
    spread(key = question_number, value = value)

यहां समस्या यह है कि प्रारंभिक संग्रह एक महत्वपूर्ण स्तंभ बनाता है जो वास्तव में दो कुंजी का संयोजन होता है। मैंने इस कॉलम को समकक्ष जानकारी, एक loop_number कॉलम और एक loop_number कॉलम के साथ दो स्तंभों में विभाजित करने के लिए टिप्पणियों में अपने मूल समाधान में mutate का उपयोग करना चुना। spread उपयोग लंबे फॉर्म डेटा को बदलने के लिए किया जा सकता है, जो कि विस्तृत (question_number, value) डेटा (question_number, value) विस्तृत रूप डेटा में हैं।


यह "tidyr" और "dplyr" से संबंधित नहीं है, लेकिन यहां पर विचार करने का एक और विकल्प है: मेरे "splitstackshape" पैकेज , v1.4.0 और ऊपर से merged.stack।

library(splitstackshape)
merged.stack(df, id.vars = c("id", "time"), 
             var.stubs = c("Q3.2.", "Q3.3."),
             sep = "var.stubs")
#     id       time .time_1       Q3.2.       Q3.3.
#  1:  1 2009-01-01      1. -0.62645381  1.35867955
#  2:  1 2009-01-01      2.  1.51178117 -0.16452360
#  3:  1 2009-01-01      3.  0.91897737  0.39810588
#  4:  2 2009-01-02      1.  0.18364332 -0.10278773
#  5:  2 2009-01-02      2.  0.38984324 -0.25336168
#  6:  2 2009-01-02      3.  0.78213630 -0.61202639
#  7:  3 2009-01-03      1. -0.83562861  0.38767161
# <<:::SNIP:::>>
# 24:  8 2009-01-08      3. -1.47075238 -1.04413463
# 25:  9 2009-01-09      1.  0.57578135  1.10002537
# 26:  9 2009-01-09      2.  0.82122120 -0.11234621
# 27:  9 2009-01-09      3. -0.47815006  0.56971963
# 28: 10 2009-01-10      1. -0.30538839  0.76317575
# 29: 10 2009-01-10      2.  0.59390132  0.88110773
# 30: 10 2009-01-10      3.  0.41794156 -0.13505460
#     id       time .time_1       Q3.2.       Q3.3.

यह दृष्टिकोण मेरे लिए बहुत स्वाभाविक प्रतीत होता है:

df %>%
  gather(key, value, -id, -time) %>%
  extract(key, c("question", "loop_number"), "(Q.\\..)\\.(.)") %>%
  spread(question, value)

पहले सभी प्रश्न कॉलम इकट्ठा करें, question और loop_number में अलग करने के लिए extract() का उपयोग करें, फिर कॉलम में वापस प्रश्न spread()

#>    id       time loop_number         Q3.2        Q3.3
#> 1   1 2009-01-01           1  0.142259203 -0.35842736
#> 2   1 2009-01-01           2  0.061034802  0.79354061
#> 3   1 2009-01-01           3 -0.525686204 -0.67456611
#> 4   2 2009-01-02           1 -1.044461185 -1.19662936
#> 5   2 2009-01-02           2  0.393808163  0.42384717

melt.data.table के हालिया अपडेट के साथ, अब हम कई कॉलम पिघल सकते हैं। इसके साथ, हम कर सकते हैं:

require(data.table) ## 1.9.5
melt(setDT(df), id=1:2, measure=patterns("^Q3.2", "^Q3.3"), 
     value.name=c("Q3.2", "Q3.3"), variable.name="loop_number")
 #    id       time loop_number         Q3.2        Q3.3
 # 1:  1 2009-01-01           1 -0.433978480  0.41227209
 # 2:  2 2009-01-02           1 -0.567995351  0.30701144
 # 3:  3 2009-01-03           1 -0.092041353 -0.96024077
 # 4:  4 2009-01-04           1  1.137433487  0.60603396
 # 5:  5 2009-01-05           1 -1.071498263 -0.01655584
 # 6:  6 2009-01-06           1 -0.048376809  0.55889996
 # 7:  7 2009-01-07           1 -0.007312176  0.69872938

आप here से विकास संस्करण प्राप्त कर सकते here





tidyr