LoginSignup
2
1

More than 5 years have passed since last update.

dataframeから気になるデータを取り出す関数

Last updated at Posted at 2017-04-23

関数の説明

データフレームを貰ったときに、そのデータフレームの要約情報を
summaryやstrといった関数で取り出すと思いますが、
それだけでは色々な使い方をする際に、足りないと感じる部分があったので、
欲しいなと思う情報を取り出して、データフレームにして返す関数を作ってみた。

データフレームから取り出したい情報について

データフレームの概要を見る時に欲しい情報はかなり多岐に渡ると思いますが、
その中でもnaの数や、factorのユニークな値の数、
その変数がユニークキーとなり得るのか、そうした点を中心に関数を構成しました。

作成される変数一覧

変数名 量的変数時 カテゴリ変数時
colname 変数名 変数名
class_info 変数のクラス 変数のクラス
unique_flag ユニークなキーとして使えるかどうか ユニークなキーとして使えるかどうか
max 最大値 文字列にしたときの最大サイズ
min 最小値 文字列にしたときの最大サイズ
na naの数 naの数
na_ratio naの比率 naの比率
data ユニークな値の数 ユニークな値の数
range 最大値-最小値
rec_n レコード数+naの数
mean 平均値
median 中央値
sd 標準偏差
lower_sd3 平均ー標準偏差×3
upper_sd3 平均+標準偏差×3
lower_outlier 下側外れ値
upper_outlier 上側外れ値
co_var 変動係数
ch_var_index 平均と中央値の差の絶対値を標準偏差で割った数。対数変換をしたほうが良いのかの指標にできる

関数内容



df_info <- function(dataframe){
  require(tidyverse)
  dataframe_head <- head(dataframe) #クラス情報を取るのに軽くするために頭だけにする
  class_info <- sapply(dataframe_head, class) %>% 
    data.frame(.)

  DF <-  data.frame(colname = as.character(""), class_info = as.character(""), unique_flag = as.character(""),   max = 0, min = 0, 
                    na = 0,na_ratio = 0, data = 0, range = 0,rec_n = 0,
                    mean = 0, median = 0, sd = 0, lower_sd3 = 0, upper_sd3 = 0, lower_outlier = 0,  upper_outlier = 0,
                    co_var = 0, ch_var_index = 0,
                    stringsAsFactors = FALSE )
  for (c in 1:ncol(dataframe_head)){
    class_data <- ifelse(ncol(class_info) >1, class_info[[1,c]], as.character(class_info[c,]))
    #print(class_info[[1,c]])
    #print(colnames(dataframe_head)[c])
    #print(class_data)
    if (class_data == "integer" | class_data == "numeric"){
      unique <- length(unique(dataframe[,c]))
      counter<- plyr::count(is.na(dataframe[,c]))
      colnames(counter)[1] <- "x"
      na   <- filter(counter, x == TRUE)$freq 
      na   <- as.numeric(ifelse(length(na) == 0, 0, na))
      data   <- filter(counter, x == FALSE)$freq
      data   <- as.numeric(ifelse(length(data) == 0, 0, data))
      max_data <- max(dataframe[,c], na.rm = TRUE)
      min_data <- min(dataframe[,c], na.rm = TRUE)
      range_data <- max_data - min_data
      rec_n <- na + data
      unique_key <-  ifelse(rec_n == unique, "UNIQUE", "")
      na_ratio <- round(na/rec_n, 2)

      if(sum(dataframe[,c]) == 0) {
        median_df <- 0
        mean_df   <- 0
        sd_df     <- 0
        lower_outlier_line <- 0
        upper_outlier_line <- 0

        lower_outlier <- 0
        upper_outlier <- 0

        co_var <- 0
        ch_var_index <- 0

      }else{
        median_df <- median(dataframe[,c], na.rm = TRUE)
        mean_df <- mean(dataframe[,c], na.rm = TRUE)
        sd_df <- sd(dataframe[,c])
        lower_outlier_line <- mean_df-sd_df*3
        upper_outlier_line <- mean_df+sd_df*3

        lower_outlier <- sum(dataframe[,c]<=lower_outlier_line, na.rm = TRUE)
        upper_outlier <- sum(dataframe[,c]>=upper_outlier_line, na.rm = TRUE)

        co_var <- round(sd_df/mean_df,2) # coefficient of variance
        ch_var_index <- round(abs(mean_df -  median_df)/sd_df,2) # 対数変換したほうがいいかという指標
      }
      DF[c,] <- c(colnames(dataframe_head)[c], 
                  as.character(class_data),
                  unique_key,
                  max_data,
                  min_data, 
                  na,
                  na_ratio,
                  data,
                  range_data,
                  rec_n,
                  round(mean_df,2),
                  median_df,
                  round(sd_df,2),
                  round(lower_outlier_line,2),
                  round(upper_outlier_line,2),
                  lower_outlier,
                  upper_outlier,
                  co_var,
                  ch_var_index
      )
    }else if (class_data == "character" | class_data == "factor" | class_data == "ordered" ){
      counter<- plyr::count(is.na(dataframe[,c]))
      colnames(counter)[1] <- "x"
      na   <- filter(counter, x == TRUE)$freq
      na   <- as.numeric(ifelse(length(na) == 0, 0, na))
      data <- filter(counter, x == FALSE)$freq
      data <- as.numeric(ifelse(length(data) == 0, 0, data))
      rec_n <- na +data
      na_ratio <- round(na/rec_n, 2)
      char <- as.character(dataframe[,c])
      max_char <- max(nchar(char), na.rm = TRUE)
      min_char <- min(nchar(char), na.rm = TRUE)
      range <- nlevels(as.factor(dataframe[,c]))
      unique_key <-  ifelse(rec_n == range, "UNIQUE", "")
      DF[c,] <- c(colnames(dataframe_head)[c],
                  as.character(class_data),
                  unique_key,
                  max_char,
                  min_char, 
                  na,
                  na_ratio,
                  data,
                  range,
                  rec_n,
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  ""
      )
    } else{
      counter<- plyr::count(is.na(dataframe[,c]))
      colnames(counter)[1] <- "x"
      na   <- filter(counter, x == TRUE)$freq
      na   <- as.numeric(ifelse(length(na) == 0, 0, na))
      data <- filter(counter, x == FALSE)$freq
      data <- as.numeric(ifelse(length(data) == 0, 0, data))
      rec_n <- na +data
      na_ratio <- round(na/rec_n, 2)
      range <- nlevels(as.factor(dataframe[,c]))
      unique_key <-  ifelse(rec_n == range, "UNIQUE", "")
      DF[c,] <- c(colnames(dataframe_head)[c],
                  as.character(class_data),
                  "",
                  "",
                  "", 
                  na,
                  na_ratio,
                  data,
                  nlevels(as.factor(dataframe[,c])),
                  rec_n,
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  "",
                  ""
      )
    }
  }
  DF  
}

実際に関数にデータフレームを入れてみましょう

newdata <- esoph

test <- df_info(newdata)

結果は下記のようなデータフレーム型で帰ってきます。

row_no colname class_info unique_flag max min na na_ratio data range rec_n mean median sd lower_sd3 upper_sd3 lower_outlier upper_outlier co_var ch_var_index
1 agegp ordered 5 3 0 0 88 6 88
2 alcgp ordered 9 4 0 0 88 4 88
3 tobgp ordered 8 3 0 0 88 4 88
4 ncases numeric 17 0 0 0 88 17 88 2.27 1 2.75 -5.99 10.53 0 1 1.21 0.46
5 ncontrols numeric 60 1 0 0 88 59 88 11.08 6 12.72 -27.09 49.25 0 1 1.15 0.4

更にここをこうした方がいいんじゃないか、という点などがあれば、ぜひご意見をください。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1