私は約60を持っています
csv
マージしたいファイル。 1つの課題は、列の名前の一貫性がないことですが、本質的にすべてのファイル(必要)は同じデータを持っています。
この問題に対処するために、私は最初にどのファイルが持っているかをテストしたいと思います特定の列名(およびそうではない)。各要素が列名を反映する文字列のベクトルがあり、各csvファイルに存在するかどうかを確認します。
私は次のようなデータフレームを実現しようとしています。
- 列:各列は、存在するかどうかをテストしようとしている列名に対応しています
- 行:各行は1つのcsvファイルに対応します
- 値:各セルで、どちらか
0
または1
csvファイルに列名があるかどうかをマークします
library(tidyverse)
df_1 <-
tribble(~ date, ~ name, ~ age, ~ gender,
"2020-11-29", "sarah", 43, "female")
df_2 <-
tribble(~ createdAt, ~ person, ~ age, ~ is_female,
"2020-10-10", "bob", 25, 0)
df_3 <-
tribble(~ date, ~ name, ~ age_value, ~ gender,
"2010-01-07", "wendy", 70, "female")
write_csv(df_1, "csv_1.csv")
write_csv(df_2, "csv_2.csv")
write_csv(df_3, "csv_3.csv")
名前のベクトル
ここで、上記で作成した3つのCSVの列名を知らないとしましょう。私は信じている各CSVの列名は次のとおりです。どちらか
date
、
name
、
age
、
age_value
、
gender
。
col_names_to_test <-
c(
"date",
"name"
"age",
"age_value"
"gender"
)
ソリューションの基礎
これは私の方向性であり、この素晴らしい解決策 読み取りおよび編集機能を定義し、次に使用する
list.files
と
purrr::map_df
定義された関数について。
read_plus <-
function(flnm) {
read_csv(flnm, col_types = cols(.default = "c")) # %>%
## here some testing against the vector `col_names_to_test` ?
}
tbl_with_sources <-
list.files(path = //folder-with-csv-files,
pattern = "*.csv",
full.names = TRUE,
recursive = TRUE) %>%
map_df(~ read_plus(.))
これは単なる一般的な考え方です...私はきちんとしたアプローチに慣れていますが、どんな解決策にも満足します。
必要な出力
filename date name age age_value gender
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 csv_1 1 1 1 0 1
2 csv_2 0 0 1 0 0
3 csv_3 1 0 0 1 1
回答 2 件
一致する列のインデックスのみが必要な場合
col_names_to_test
、このアプローチを使用できます。library('data.table') library('dplyr') col_names_to_test = c('date', 'name', 'age', 'age_value', 'gender') # define columns indexes matching the pattern DefCols = function(input_path, patterns) { pattern = patterns %>% str_flatten('|') cols = input_path %>% fread(nrows = 1) %>% colnames() %>% str_which(pattern) return(cols) } # define the input directory input_dir = '' cols = input_dir %>% dir(pattern = '.*.csv$', full.names = TRUE, recursive = TRUE) %>% lapply(DefCols, col_names_to_test)
ただし、一致する列のみを含むデータフレームもロードする場合は、次のように拡張できます。
library('data.table') library('dplyr') col_names_to_test = c('date', 'name', 'age', 'age_value', 'gender') # define columns indexes matching the pattern LoadDF = function(input_path, patterns) { pattern = patterns %>% str_flatten('|') cols = input_path %>% fread(nrows = 1) %>% colnames() %>% str_which(pattern) df = input_path %>% fread(drop = -cols) %>% as.data.frame() return(df) } # define the input directory input_dir = '' dfs = 'input_dir' %>% dir(pattern = '.*.csv$', full.names = TRUE, recursive = TRUE) %>% lapply(LoadDF, col_names_to_test)
注:列名を確認するためにデータをロードするときは、最初の行のみを保持します(
nrows = 1
)、各セルの値は気にしないためです。
関連記事
- DataFrameapplyから不明な列名を取得する
- pandas groupbyトランスフォーム内の列名にアクセスすることは可能ですか?
- 列名を分割して名前の一部を削除し、Rでデータをワイド形式からロング形式に変換する方法
- シートの特定のポイントから最初の列を取得します
- 特定の列の平均が最大であるグループを取得します
- リストから列名を取得してテーブルを作成できませんか?(postgresql/psycopg2)
- 列名のベクトル
- すべての列にわたって特定の文字列を含む行をフィルタリングします(dplyrを使用)
- 列が特定の文字列で始まり、数字で続くEntityFrameworkを使用してDBから最初の行を取得する方法
関数を定義する
ok
ファイル名を付けたf
と同じ長さの名前付き0/1ベクトルを返しますcol_names_to_test
の対応するコンポーネントの場合は1col_names_to_test
そのファイルには列名として存在し、それ以外の場合は0です。次に、ファイル名のベクトルを定義しますfiles
。拡張子なしで名前を付けて適用しますok
を使用してそれにmap_dfr
。これは適度にコンパクトで、purrrのみを使用します。
与える:
更新完全に改訂しました。