मैं एक ऐसा फ़ंक्शन बनाने का प्रयास कर रहा हूं जो मुझे मेरे डेटा में चर के गुणों के बारे में सारांश देगा। उदाहरण के लिए, मैं जानना चाहता हूं कि क्या कुछ चरों के मूल्यों में अंक हैं, या विशिष्ट वर्ण हैं, या अन्यथा अद्वितीय मानों की संख्या है। हालांकि किसी विशिष्ट संपत्ति के लिए एक विशिष्ट चर का परीक्षण करते समय यह एक आसान काम है, मुझे नहीं पता कि इसे बड़े पैमाने पर कैसे किया जाए। यही है, मैं विभिन्न प्रकार के परीक्षणों को परिभाषित करना चाहता हूं और प्रत्येक परीक्षण पर परीक्षण करने के लिए कॉलम नामों के साथ एक वेक्टर पास करना चाहता हूं। मैं एक ऐसा फ़ंक्शन बनाना चाहता हूं जो स्केलेबल/लचीला हो ताकि मैं आवश्यकतानुसार परीक्षण जोड़ या हटा सकूं।

उदाहरण

मान लें कि मेरे पास उम्र, वजन और लिंग सहित लोगों के बारे में कुछ डेटा है। प्रत्येक रिकॉर्ड को एक विशेष आईडी स्ट्रिंग के साथ भी सौंपा गया है। हालांकि चर प्रकार में भिन्न होते हैं (यानी, उम्र संख्यात्मक है लेकिन लिंग चरित्र है), मैं अंत में पूरे डेटा को वर्णों के लिए मजबूर करता हूं।

library(tibble)
library(dplyr)

# a function to generate random alphanumeric strings (https://stackoverflow.com/a/42734863/6105259)
sample_strings <- function(n = 5000) {
  a <- do.call(paste0, replicate(5, sample(LETTERS, n, TRUE), FALSE))
  paste0(a, sprintf("%04d", sample(9999, n, TRUE)), sample(LETTERS, n, TRUE))
}

set.seed(2020)

desired_n <- 20

df <-
  tibble(special_id = sample_strings(desired_n),
         age = sample(c(10:80), size = desired_n),
         weight = sample(seq(45, 100, by = 0.001), size = desired_n, replace = TRUE),
         monthly_income = sample(c(2000:15000), size = desired_n),
         sex = sample(c("male", "female"), size = desired_n, replace = TRUE)) %>%
  mutate_all(as.character)

## # A tibble: 20 x 5
##    special_id age   weight monthly_income sex   
##    <chr>      <chr> <chr>  <chr>          <chr> 
##  1 LBRKP2319H 20    87.554 4699           male  
##  2 WXJZW1202W 60    95.617 3163           female
##  3 VHFFD6488D 22    56.573 3468           female
##  4 XDOBT5680G 19    69.092 13418          female
##  5 ARKYR3604N 64    84.654 7865           female
##  6 QNMCJ9652Q 68    85.483 11704          male  
##  7 DNXXA5261W 56    69.472 6075           female
##  8 JLMRO7068U 12    47.802 12712          male  
##  9 FPMAV9425D 34    85.468 10120          female
## 10 QOBVI1118X 53    58.419 6984           male  
## 11 MNPGP4717P 40    52.546 7040           female
## 12 XGMHF7783I 32    51.613 8443           male  
## 13 HTAUX2428V 79    74.555 8339           male  
## 14 JRFXW0040B 54    69.734 2394           male  
## 15 RTCMZ4379Q 57    87.162 13986          male  
## 16 PUYBJ1885Q 13    45.77  8770           female
## 17 VTMEZ2421E 30    51.458 3576           male  
## 18 BPKVA5731J 50    82.651 12497          female
## 19 PLYDA2818S 46    95.716 13701          male  
## 20 CVESQ8525O 61    56.157 8291           male  

इस डेटा को देखते हुए, मैं कई गुणों के लिए चर का परीक्षण करना चाहता हूं:

  • क्या अक्षरांकीय, अंक और वर्णमाला दोनों से मिलकर बनता है?
  • क्या सांख्यिक है, जिसमें केवल अंक होते हैं (दशमलव बिंदु स्वीकार किया जाता है)?
  • दशमलव है?
  • क्या केवल पत्र हैं?
  • कॉलम में अद्वितीय मानों की संख्या

और मेरे पास उन गुणों में से प्रत्येक का परीक्षण करने का एक तरीका है:

अल्फ़ान्यूमेरिक है grepl("([A-Za-z]+[0-9]|[0-9]+[A-Za-z])[A-Za-z0-9]*", colname)

संख्यात्मक है grepl("^[0-9]{1,}$", colname)

दशमलव है grepl("^[-]{0,1}[0-9]{0,}.{0,1}[0-9]{1,}$", colname)

केवल अक्षर हैं grepl("^[a-zA-Z]{1,}$", colname)

अद्वितीयों की संख्या length(unique(colname))

चूंकि मुझे उम्मीद है कि प्रत्येक कॉलम के भीतर सभी मान संपत्ति में सुसंगत होंगे, इसलिए मैं एक TRUE/FALSE प्राप्त करने के लिए उपरोक्त में से प्रत्येक (अनन्य की संख्या को छोड़कर) को all() के साथ लपेट सकता हूं।

अब मैं उन सभी उपनामों को व्यवस्थित करना चाहता हूं जिन्हें मैं एक वेक्टर में परीक्षण करना चाहता हूं:

vec_of_colnames <- c("special_id", "age", "weight", "sex")

और मैं एक ऐसे समारोह में vec_of_colnames पास करना चाहता हूं जो सारांश तालिका लौटाएगा जैसे:

  var_name   is_alphanumeric is_numeric is_decimal has_letters_only number_of_uniques
  <chr>      <lgl>           <lgl>      <lgl>      <lgl>                        <dbl>
1 special_id TRUE            FALSE      FALSE      FALSE                           20
2 age        FALSE           TRUE       FALSE      FALSE                           20
3 weight     FALSE           TRUE       TRUE       FALSE                           20
4 sex        FALSE           FALSE      FALSE      TRUE                             2

मैं ऐसी तालिका कैसे प्राप्त कर सकता हूं, जिससे आसानी से "गुण परीक्षण" जोड़ने या निकालने की अनुमति मिल सके?

0
Emman 15 पद 2020, 10:20

1 उत्तर

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

आप फ़ंक्शन को इस प्रकार लिख सकते हैं:

library(dplyr)
library(tidyr)


return_stats <- function(data, vec_of_colnames) {
  data %>%
    summarise(across(.cols = all_of(vec_of_colnames), .fns = list(
      isAlphanumeric  = ~all(grepl("([A-Za-z]+[0-9]|[0-9]+[A-Za-z])[A-Za-z0-9]*", .)), 
      isNumeric  = ~all(grepl("^[0-9]{1,}$", .)),
      isDecimal = ~all(grepl("^[-]{0,1}[0-9]{0,}\\.{0,1}[0-9]{1,}$", .)),
      hasLettersOnly = ~all(grepl("^[a-zA-Z]{1,}$", .)),
      numberOfUniques = ~n_distinct(.)
    ))) %>%
    pivot_longer(cols = everything(), 
                 names_to = c('var_name', '.value'), 
                 names_pattern = '(.*)_(.*)')
}

vec_of_colnames <- c("special_id", "age", "weight", "sex")
return_stats(df, vec_of_colnames)

#  var_name   isAlphanumeric isNumeric isDecimal hasLettersOnly numberOfUniques
#  <chr>      <lgl>          <lgl>     <lgl>     <lgl>                    <int>
#1 special_id TRUE           FALSE     FALSE     FALSE                       20
#2 age        FALSE          TRUE      TRUE      FALSE                       20
#3 weight     FALSE          FALSE     TRUE      FALSE                       20
#4 sex        FALSE          FALSE     FALSE     TRUE                         2

ध्यान दें कि मैंने ओपी द्वारा आपूर्ति की गई रेगेक्स का उपयोग किया है। किनारे के मामलों के लिए इसे कुछ और शोधन या परीक्षण की आवश्यकता हो सकती है।

1
Ronak Shah 15 पद 2020, 11:01
बहुत बहुत धन्यवाद! हां, रेगेक्स 100% सही नहीं है, लेकिन कार्यात्मक ढांचा वास्तव में वही है जिसे मैं ढूंढ रहा था। हालांकि, एक प्रश्न यह है कि क्या names_pattern = '(.*?)_(is.*|has.*|num.*)' से अधिक मूर्खतापूर्ण तरीका हो सकता है? मुझे चिंता है कि यह अनजाने में विफल हो सकता है यदि आंतरिक फ़ंक्शन नामकरण असंगत रूप से उपयोग किया जाता है ...
 – 
Emman
15 पद 2020, 10:55
हाँ मैं सहमत हूँ। हालाँकि, हम यह नहीं मान सकते कि सभी नाम डेटा में हो सकते हैं। यदि मूल कॉलम नामों में अंडरस्कोर या शायद नए नाम नहीं होते तो यह और अधिक मजबूत होता। अद्यतन उत्तर देखें जो अंडरस्कोर के बिना नए कॉलम नाम बदलने में मदद कर सकता है।
 – 
Ronak Shah
15 पद 2020, 11:02
मैं देख रहा हूं, लेकिन क्या हम आंतरिक कार्यों के सभी नाम एकत्र नहीं कर सकते (जैसे, isAlphanumeric, isNumeric, isDecimal, आदि) और इसे सीधे pivot_longer में फीड नहीं कर सकते?
 – 
Emman
15 पद 2020, 11:20
1
मुझे लगता है कि मेरा वर्तमान उत्तर मजबूत होना चाहिए और असफल नहीं होना चाहिए क्योंकि यह इस बात पर निर्भर नहीं है कि आपके मूल डेटाफ़्रेम में आपके कॉलम का नाम क्या है। जब हम across के साथ summarise का उपयोग करते हैं, तो vec_of_colnames में प्रत्येक कॉलम के लिए डिफ़ॉल्ट रूप से एक _ जोड़ा जाता है। इसलिए यदि आपका मूल कॉलम नाम 'abc' या 'abc_var' है, तो यह 'abc_isAlphanumeric' और 'abc_var_isAlphanumeric' के रूप में एक नया कॉलम बनाएगा और pivot_longer में मैं उन्हें अंतिम अंडरस्कोर पर अलग कर दूंगा।
 – 
Ronak Shah
15 पद 2020, 11:41