डेटा की प्रत्येक पंक्ति को दोहराएँ। एक कॉलम में निर्दिष्ट समय की संख्या को समायोजित करें


150
df <- data.frame(var1 = c('a', 'b', 'c'), var2 = c('d', 'e', 'f'),
                 freq = 1:3)

प्रत्येक पंक्ति को डेटा के पहले दो कॉलमों का विस्तार करने का सबसे सरल तरीका है। ऊपर दिए गए कॉलम, ताकि प्रत्येक पंक्ति कॉलम 'फ्रीक' में निर्दिष्ट समय की संख्या को दोहराया जाए?

दूसरे शब्दों में, इस से जाना:

df
  var1 var2 freq
1    a    d    1
2    b    e    2
3    c    f    3

इसके लिए:

df.expanded
  var1 var2
1    a    d
2    b    e
3    b    e
4    c    f
5    c    f
6    c    f

जवाबों:


169

यहाँ एक समाधान है:

df.expanded <- df[rep(row.names(df), df$freq), 1:2]

परिणाम:

    var1 var2
1      a    d
2      b    e
2.1    b    e
3      c    f
3.1    c    f
3.2    c    f

महान! मैं हमेशा भूल जाता हूं कि आप इस तरह से वर्ग कोष्ठक का उपयोग कर सकते हैं। मैं अनुक्रमण या पुन: व्यवस्थित करने के लिए अनुक्रमण करने के बारे में सोचता रहता हूं। मेरे पास एक और उपाय था जो अब तक कम सुरुचिपूर्ण है और इसमें कोई संदेह नहीं है कि कम कुशल है। मैं वैसे भी पोस्ट कर सकता हूं ताकि अन्य लोग तुलना कर सकें।
wkmor1

22
बड़े के लिए data.frameऔर अधिक कुशल को बदलने के लिए है row.names(df)के साथ seq.int(1,nrow(df))या seq_len(nrow(df))
मारेक

यह एक बड़े डेटा फ्रेम के लिए काल्पनिक रूप से काम करता था - 1.5 मिलियन बिलियन पंक्तियाँ, 5 कॉल, बहुत जल्दी चले गए। धन्यवाद!
gabe

4
1: 2 हार्ड कोड इस उदाहरण का हल है, 1: ncol (df) एक मनमाना डेटाफ्रेम के लिए काम करेगा।
vladiim

71

पुराने प्रश्न, tidyverse में नई क्रिया:

library(tidyr) # version >= 0.8.0
df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3)
df %>% 
  uncount(freq)

    var1 var2
1      a    d
2      b    e
2.1    b    e
3      c    f
3.1    c    f
3.2    c    f

2
एक साफ समाधान के लिए धन्यवाद। इस तरह के समाधान आमतौर पर "सरल" और पठनीय के मानदंडों को पूरा करते हैं।
D. वुड्स

45

पैकेज expandRows()से उपयोग करें splitstackshape:

library(splitstackshape)
expandRows(df, "freq")

सरल वाक्यविन्यास, बहुत तेज, पर काम करता है data.frameया data.table

परिणाम:

    var1 var2
1      a    d
2      b    e
2.1    b    e
3      c    f
3.1    c    f
3.2    c    f

23

@ नीलफूज का समाधान data.frameएस के लिए बहुत अच्छा काम करता है , लेकिन data.tableएस के लिए नहीं क्योंकि उनके पास row.namesसंपत्ति की कमी है । यह दृष्टिकोण दोनों के लिए काम करता है:

df.expanded <- df[rep(seq(nrow(df)), df$freq), 1:2]

कोड data.tableएक साफ क्लीनर है:

# convert to data.table by reference
setDT(df)
df.expanded <- df[rep(seq(.N), freq), !"freq"]

4
एक अन्य विकल्प:df[rep(seq(.N), freq)][, freq := NULL]
जाप

एक अन्य विकल्पdf[rep(1:.N, freq)][, freq:=NULL]
डेल क्यूब

4

यदि आपको यह ऑपरेशन बहुत बड़े डेटा.फ्रेम पर करना है, तो मैं इसे डेटाटेबल में बदलने की सलाह दूंगा और निम्नलिखित का उपयोग करूंगा, जो बहुत तेजी से चलना चाहिए:

library(data.table)
dt <- data.table(df)
dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")]
dt.expanded[ ,freq := NULL]
dt.expanded

देखें कि यह समाधान कितना तेज है:

df <- data.frame(var1=1:2e3, var2=1:2e3, freq=1:2e3)
system.time(df.exp <- df[rep(row.names(df), df$freq), 1:2])
##    user  system elapsed 
##    4.57    0.00    4.56
dt <- data.table(df)
system.time(dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")])
##    user  system elapsed 
##    0.05    0.01    0.06

मैं एक त्रुटि मिलती है: Error in rep(1, freq) : invalid 'times' argument। और यह देखते हुए कि इस प्रश्न का एक डेटाटेबल उत्तर पहले से ही है, आप यह वर्णन करना चाह सकते हैं कि आपका दृष्टिकोण अलग कैसे है या जब यह मौजूदा डेटा से बेहतर है। या यदि कोई बड़ा अंतर नहीं है, तो आप इसे मौजूदा उत्तर के लिए एक टिप्पणी के रूप में जोड़ सकते हैं।
सैम फ़िरके

@SamFirke: आपकी टिप्पणी के लिए धन्यवाद। अजीब बात है, मैंने बस फिर से कोशिश की और मुझे ऐसी कोई त्रुटि नहीं मिली। क्या आप dfओपी के प्रश्न से मूल का उपयोग करते हैं ? मेरा उत्तर बेहतर है क्योंकि अन्य उत्तर सिंटैक्स data.tableका उपयोग करके पैकेज का दुरुपयोग करने की तरह है data.frame, के FAQ देखें data.table: "यह आमतौर पर नाम के बजाय संख्याओं के आधार पर स्तंभों को संदर्भित करने के लिए बुरा व्यवहार है।"
वॉनजड

1
स्पष्टीकरण के लिए धन्यवाद। आपका कोड dfओपी द्वारा पोस्ट किए गए नमूने पर मेरे लिए काम करता है , लेकिन जब मैंने इसे बड़े डेटा पर बेंचमार्क करने की कोशिश की। मुझे वह त्रुटि मिली। मेरे द्वारा उपयोग किया जाने वाला डेटा.फ्रेम था: set.seed(1) dfbig <- data.frame(var1=sample(letters, 1000, replace = TRUE), var2=sample(LETTERS, 1000, replace = TRUE), freq=sample(1:10, 1000, replace = TRUE)) छोटे डेटा.फ्रेम पर, आधार उत्तर मेरे बेंचमार्किंग में अच्छा करता है, यह सिर्फ बड़े डेटा.फ्रेम में अच्छी तरह से पैमाने पर नहीं होता है। अन्य तीन उत्तर इस बड़े डेटा.फ्रेम के साथ सफलतापूर्वक चले।
सैम फर्के

@SamFirke: यह वास्तव में अजीब है, इसे वहां भी काम करना चाहिए और मुझे नहीं पता कि यह क्यों नहीं है। क्या आप इसमें से एक प्रश्न बनाना चाहते हैं या मैं?
वॉनजड

अच्छा विचार। क्या आप? मैं data.tableवाक्यविन्यास नहीं जानता, इसलिए मुझे जवाबों को देखते हुए नहीं होना चाहिए।
सैम फ़िरके

4

एक और dplyrविकल्प sliceजहां हम प्रत्येक पंक्ति संख्या freqबार दोहराते हैं

library(dplyr)

df %>%  
  slice(rep(seq_len(n()), freq)) %>% 
  select(-freq)

#  var1 var2
#1    a    d
#2    b    e
#3    b    e
#4    c    f
#5    c    f
#6    c    f

seq_len(n()) भाग को निम्न में से किसी के साथ बदला जा सकता है।

df %>% slice(rep(1:nrow(df), freq)) %>% select(-freq)
#Or
df %>% slice(rep(row_number(), freq)) %>% select(-freq)
#Or
df %>% slice(rep(seq_len(nrow(.)), freq)) %>% select(-freq)

2

एक और संभावना का उपयोग कर रहा है tidyr::expand:

library(dplyr)
library(tidyr)

df %>% group_by_at(vars(-freq)) %>% expand(temp = 1:freq) %>% select(-temp)
#> # A tibble: 6 x 2
#> # Groups:   var1, var2 [3]
#>   var1  var2 
#>   <fct> <fct>
#> 1 a     d    
#> 2 b     e    
#> 3 b     e    
#> 4 c     f    
#> 5 c     f    
#> 6 c     f

वॉनजड के उत्तर का वन-लाइनर संस्करण :

library(data.table)

setDT(df)[ ,list(freq=rep(1,freq)),by=c("var1","var2")][ ,freq := NULL][]
#>    var1 var2
#> 1:    a    d
#> 2:    b    e
#> 3:    b    e
#> 4:    c    f
#> 5:    c    f
#> 6:    c    f

2019-05-21 को रेप्रेक्स पैकेज (v0.2.1) द्वारा बनाया गया


1

मुझे पता है कि यह मामला नहीं है, लेकिन अगर आपको मूल फ्रीक कॉलम रखने की आवश्यकता है, तो आप इसके tidyverseसाथ एक और दृष्टिकोण का उपयोग कर सकते हैं rep:

library(purrr)

df <- data.frame(var1 = c('a', 'b', 'c'), var2 = c('d', 'e', 'f'), freq = 1:3)

df %>% 
  map_df(., rep, .$freq)
#> # A tibble: 6 x 3
#>   var1  var2   freq
#>   <fct> <fct> <int>
#> 1 a     d         1
#> 2 b     e         2
#> 3 b     e         2
#> 4 c     f         3
#> 5 c     f         3
#> 6 c     f         3

2019-12-21 को रेप्रेक्स पैकेज (v0.3.0) द्वारा बनाया गया


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