非常に大きなテーブルをデータフレームとしてすばやく読み取る


504

Rのデータフレームとしてロードしたい非常に大きなテーブル(3000万行)があります。 read.table()便利な機能がたくさんありますが、実装には低速化するロジックがたくさんあるようです。私の場合、列のタイプが事前にわかっており、テーブルに列ヘッダーや行名が含まれておらず、心配する必要のある病理学的文字が含まれていないと想定しています。

を使用してリストとしてテーブルを読み取るのはscan()非常に高速である可能性があることを知っています。例:

datalist <- scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0)))

しかし、これをデータフレームに変換しようとする私の試みの一部は、上記のパフォーマンスを6分の1に低下させるように見えます。

df <- as.data.frame(scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0))))

これを行うより良い方法はありますか?または、問題へのまったく異なるアプローチ?

回答:


426

数年後のアップデート

この答えは古く、Rは先に進みました。read.table少し速く実行するように調整しても、ほとんどメリットがありません。オプションは次のとおりです。

  1. vroomtidyverseパッケージから使用して、vroomcsv /タブ区切りファイルからRチブルにデータを直接インポートします。

  2. csv / tabで区切られたファイルからRに直接データをインポートするためにfreadin data.tableを使用します。mnelの回答を参照してください。

  3. 使用read_tablereadr(2015年4月からCRAN上)。これはfread上記のように機能します。リンクのreadmeは、2つの機能の違いを説明しています(readr現在、「1.5〜2倍遅い」と主張していますdata.table::fread)。

  4. read.csv.rawfrom iotoolsは、CSVファイルをすばやく読み取るための3番目のオプションを提供します。

  5. フラットファイルではなく、データベースにできるだけ多くのデータを保存しようとします。(ならびにより良好な永久記憶媒体であるとして、データは高速であり、バイナリ形式で及びRから渡される)read.csv.sqlsqldfに記載されているように、パッケージJDロングの回答一時SQLiteデータベースに、インポートデータを、それを読み出します参照:RODBCパッケージ、およびDBIパッケージページの逆依存セクションを参照してください。MonetDB.Rデータフレームのふりをするデータタイプを提供しますが、実際にはその下にあるMonetDBであり、パフォーマンスが向上します。そのmonetdb.read.csv機能でデータをインポートします。 dplyr複数のタイプのデータベースに格納されているデータを直接操作できます。

  6. バイナリ形式でデータを保存することも、パフォーマンスの向上に役立ちます。使用saveRDS/ readRDS(下記参照)、h5またはrhdf5HDF5形式のパッケージ、またはwrite_fst/ read_fstからのfstパッケージ。


元の答え

read.tableを使用するかscanを使用するかにかかわらず、いくつかの簡単な方法があります。

  1. セットnrows= データ内のレコード数nmaxscan)。

  2. comment.char=""コメントの解釈をオフにすることを確認してください。

  3. colClassesin を使用して、各列のクラスを明示的に定義しますread.table

  4. 設定multi.line=FALSEにより、スキャンのパフォーマンスも向上する場合があります。

これらのいずれも機能しない場合は、プロファイリングパッケージの 1つを使用して、速度を低下させている行を特定します。おそらくread.table、結果に基づいてのカットダウンバージョンを作成できます。

もう1つの方法は、Rに読み込む前にデータをフィルタリングすることです。

または、問題を定期的に読み取る必要がある場合は、これらのメソッドを使用してデータを一度に読み取り、データフレームをバイナリBLOBとして保存します。 save saveRDS、次にあなたはそれを使ってそれをより速く取得することができます load readRDS


4
ヒントRichieをありがとう。私は少しテストを行いましたが、read.tableのnrowおよびcolClassesオプションを使用することによるパフォーマンスの向上はかなり控えめなようです。たとえば、約700万行のテーブルを読み取るには、オプションなしで78秒、オプションありで67秒かかります。(注:テーブルには1文字の列と4つの整数列があり、comment.char = ''とstringsAsFactors = FALSEを使用して読み取りました)。可能であればsave()とload()を使用するのは素晴らしいヒントです。save()で一度保存すると、同じテーブルの読み込みに12秒しかかかりません。
eytan 2009年

2
「フェザー」パッケージには、Pythonのパンダデータフレームで
うまく機能

4
パッケージに関しては、投稿をもう一度更新する必要があると思いますfeather。データの読み取りfeatherは、よりもはるかに高速ですfread。たとえば、4GBのデータセットでロードしたのread_featherは、の約4.5倍freadでした。データを保存するためにfwriteさらに高速です。blog.dominodatalab.com/the-r-data-io-shootout
Z boson

2
ただし、RDSを使用する場合よりもフェザーの場合はファイルサイズがはるかに大きくなります。圧縮をサポートしていないと思います。RDSファイルは216 MB、フェザーファイルは4 GBです。したがってfeather、読み取りは高速ですが、使用するストレージスペースが多くなります。
Zボソン

@Zboson RとPythonの両方からアクセスできるファイルにデータフレームを格納する必要がある場合featherは、適切なオプションです。Rでデータを読み取ることができることだけに関心がある場合rdsは、それが推奨されます。
リッチーコットン

279

これは1.8.7 freadから利用する例ですdata.table

例はヘルプページからfreadにあり、私のタイミングはWindows XP Core 2 duo E8400です。

library(data.table)
# Demo speedup
n=1e6
DT = data.table( a=sample(1:1000,n,replace=TRUE),
                 b=sample(1:1000,n,replace=TRUE),
                 c=rnorm(n),
                 d=sample(c("foo","bar","baz","qux","quux"),n,replace=TRUE),
                 e=rnorm(n),
                 f=sample(1:1000,n,replace=TRUE) )
DT[2,b:=NA_integer_]
DT[4,c:=NA_real_]
DT[3,d:=NA_character_]
DT[5,d:=""]
DT[2,e:=+Inf]
DT[3,e:=-Inf]

標準のread.table

write.table(DT,"test.csv",sep=",",row.names=FALSE,quote=FALSE)
cat("File size (MB):",round(file.info("test.csv")$size/1024^2),"\n")    
## File size (MB): 51 

system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   24.71    0.15   25.42
# second run will be faster
system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   17.85    0.07   17.98

最適化されたread.table

system.time(DF2 <- read.table("test.csv",header=TRUE,sep=",",quote="",  
                          stringsAsFactors=FALSE,comment.char="",nrows=n,                   
                          colClasses=c("integer","integer","numeric",                        
                                       "character","numeric","integer")))


##    user  system elapsed 
##   10.20    0.03   10.32

恐怖

require(data.table)
system.time(DT <- fread("test.csv"))                                  
 ##    user  system elapsed 
##    3.12    0.01    3.22

sqldf

require(sqldf)

system.time(SQLDF <- read.csv.sql("test.csv",dbname=NULL))             

##    user  system elapsed 
##   12.49    0.09   12.69

# sqldf as on SO

f <- file("test.csv")
system.time(SQLf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))

##    user  system elapsed 
##   10.21    0.47   10.73

ff / ffdf

 require(ff)

 system.time(FFDF <- read.csv.ffdf(file="test.csv",nrows=n))   
 ##    user  system elapsed 
 ##   10.85    0.10   10.99

要約すれば:

##    user  system elapsed  Method
##   24.71    0.15   25.42  read.csv (first time)
##   17.85    0.07   17.98  read.csv (second time)
##   10.20    0.03   10.32  Optimized read.table
##    3.12    0.01    3.22  fread
##   12.49    0.09   12.69  sqldf
##   10.21    0.47   10.73  sqldf on SO
##   10.85    0.10   10.99  ffdf

43
すばらしい答えであり、ベンチマークは他の状況でも成り立ちます。で、1分もかからずに4GBファイルを読み込んでくださいfread。基本のR関数でそれを読み取ってみましたが、約15時間かかりました。
Ari B. Friedman、

1
私のベンチマークは、data.table内のread.csvの速度がさらに向上することを示しています。data.tableは標準のRではありませんが、(悲しいことに)CRANで作成者がうまく共有していることに注意してください。共通のRパッケージリストを作成するのに十分な標準とは見なされておらず、データフレームの代替としての適格性ははるかに低くなっています。これには多くの利点がありますが、直観に反する側面もあります。as.data.frame(fread.csv( "test.csv"))をパッケージで使用して、標準のRデータフレームの世界に戻ることができます。
ivo Welch、2015

3
@mnelベンチマークを再実行して含めてreadrください。
jangorecki

2
2番目の@jangorecki。また、与えられたfreadいくつかの本当の競争相手がいるので、最適化されたfread使用法のためのベンチマークを追加するのに役立つかもしれません-指定colClassesなど
MichaelChirico

1
@jangorecji @ MichaelChirico指定されたコードは完全に再現可能であるため、読み取りをシミュレートすることは簡単です...コードを再実行すると、ネットワーク上で実行している場合でも、ほとんどの結果では、マシンの経過時間は2倍速くなります。現在しばらく更新されているバージョンです)...そして、readerを使用して、私は7秒ですが、2回目(0.66秒)を実行すると、1秒未満でも、ネットワークにキャッシングまたはボトルネックがあると思われます。ここに示されている最速の解決策に対する恐怖は、何らかの理由で比較のために比較のために私の側で2秒です(初回は8.69秒で実行されます)
R.プロスト

249

最初はこの質問がありませんでしたが、数日後に同様の質問をしました。以前の質問を削除sqldf()しますが、これを行う方法を説明するためにここに回答を追加すると思いました。

そこをされている議論の少し Rのデータフレームに2GB以上のテキストデータをインポートするための最良の方法のよう。昨日、ステージングエリアとしてSQLiteにデータをインポートし、SQLiteからRにデータを取り込む方法についてブログ投稿sqldf()しました。これは私にとって非常にうまく機能します。2GB(3列、40mm行)のデータを5分未満で取り込むことができました。対照的に、read.csvコマンドは一晩中実行され、完了しませんでした。

これが私のテストコードです:

テストデータを設定します。

bigdf <- data.frame(dim=sample(letters, replace=T, 4e7), fact1=rnorm(4e7), fact2=rnorm(4e7, 20, 50))
write.csv(bigdf, 'bigdf.csv', quote = F)

次のインポートルーチンを実行する前にRを再起動しました。

library(sqldf)
f <- file("bigdf.csv")
system.time(bigdf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))

次の行を一晩中実行させましたが、完了しませんでした。

system.time(big.df <- read.csv('bigdf.csv'))

1
こんにちは。すべてのデータを同時に使用するように設計された、zooなどの他のパッケージの入力としてそれをどのように使用しますか?
skan 2013年

@skan終了オブジェクトはデータフレームです。したがって、zooで使用するには、zooオブジェクトに変換する必要があります。動物園のドキュメントの例を参考にしてください。
JD Long

@JD Long。こんにちは、問題は、それを動物園オブジェクトに変換するときに、メモリ上に収めようとすることです。大きすぎるとエラーになります。また、zooオブジェクトの結果(2つのシリーズの集計など)も多すぎる場合は、sqlまたはffオブジェクトである必要もあります。
SKAN

sqldfの何が問題なのかわかりません。ディスク(数値列が2つある)上に単純な1GBファイルを作成し、DTSQL <-read.csv.sql( "f2.txt"、dbname = tempfile())を使用して、データ全体をメモリにロードしようとしました。明日はffとrevoscalerを試してみます。
skan 2013

1
@what mは1000なので、mmは1000千、または100万です。私はおそらくそれをMMとして大文字にすべきでした。しかし、十分に多様なオーディエンスを持っている場合、約100万の略語が誰かを混乱させる可能性があることがわかります。過度に冗長にしようとして、もっと混乱させてすみません! accountingcoach.com/blog/what-does-m-and-mm-stand-for
JD Long

73

奇妙なことに、これは重要な問題ですが、何年も質問の下部に答えた人はいませんでした。s data.frameは適切な属性を持つ単なるリストであるため、大量のデータがありas.data.frame、リストに使用したくない、または類似していない場合です。リストをインプレースでデータフレームに単純に「変換」する方がはるかに高速です。

attr(df, "row.names") <- .set_row_names(length(df[[1]]))
class(df) <- "data.frame"

これはデータのコピーを作成しないため、(他のすべてのメソッドとは異なり)即時です。それにnames()応じて、すでにリストに設定されていることを前提としています。

[大きなデータをRにロードする場合-個人的には、列readBin()ごとにバイナリファイルにダンプして使用します。これは(mmapping以外の)最速の方法であり、ディスク速度によってのみ制限されます。ASCIIファイルの解析は、バイナリデータと比較して本質的に(Cでも)遅くなります。]


6
を使用tracmemするとattr<-、それclass<-が示唆され、内部でコピーが作成されます。bit::setattrまたはしdata.table::setattrません。
mnel 2012

6
多分あなたは間違った注文を使いましたか?使用してもコピーはありませんdf=scan(...); names(df)=...; attr...; class...-参照tracemem()(R 2.15.2でテスト済み)
Simon Urbanek

3
大きなデータを列ごとにバイナリファイルにダンプする方法を詳しく説明できますか?
dabsingh 2016

32

これは以前R-Help尋ねられたので、検討する価値があります。

1件の提案があり使用していたreadChar()し、その後で結果を文字列操作を行うstrsplit()substr()。readCharに含まれるロジックがread.tableよりもはるかに少ないことがわかります。

ここでメモリに問題があるかどうかはわかりませんがHadoopStreamingパッケージを確認することできます。これ、大きなデータセットを処理するために設計されたMapReduceフレームワークであるHadoopを使用します。これには、hsTableReader関数を使用します。これは例です(ただし、Hadoopを学ぶための学習曲線があります)。

str <- "key1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey2\t9.9\nkey2\"
cat(str)
cols = list(key='',val=0)
con <- textConnection(str, open = "r")
hsTableReader(con,cols,chunkSize=6,FUN=print,ignoreKey=TRUE)
close(con)

ここでの基本的な考え方は、データのインポートをチャンクに分割することです。並列フレームワークの1つ(例:雪)を使用して、ファイルをセグメント化することでデータインポートを並行して実行することもできますが、メモリ制約に遭遇するため役に立たない大きなデータセットの場合は、これがmap-reduceの方が優れている理由です。


簡単なテストを行ったところ、いくつかの不可解な理由により、readCharはreadLinesよりもはるかに高速に見えます。ただし、単純なCテストと比較して、それはまだ罪のように遅いです。100 MBを読み取るという単純なタスクでは、RはCよりも5〜10倍遅い
Jonathan Chang

1
あなたのポイントを理解しないでください。Hadoopのポイントは、非常に大きなデータを処理することです。これが問題でした。
シェーン

1
その名前にもかかわらず、hsTableReaderはHadoop自体とは何の関係もありません。大規模なデータをバラバラに処理するためのものです。一度に行のチャンクであるconから読み取り、各チャンクをdata.frameとしてFUNに渡して処理します。ignoreKey = FALSEの場合、キー(最初の列のエントリ)による追加のグループ化が行われます。これは、Map / Reduceアプローチに関連しています。
DavidR 2013年

こんにちは。このHadoopデータを、すべてのデータと同時に使用するように設計されたzooなどの他のパッケージの入力としてどのように使用しますか?
skan 2013年

10

別の方法は、vroomパッケージを使用することです。クランになりました。 vroomファイル全体をロードするのではなく、各レコードが配置されている場所にインデックスを付け、後で使用するときに読み込まれます。

使用した分だけお支払いください。

参照してくださいVROOMの概要をVROOMを使ってみるVROOMのベンチマーク

基本的な概要は、巨大なファイルの最初の読み取りははるかに速くなり、その後のデータの変更はわずかに遅くなる可能性があるということです。したがって、用途によっては、これが最良のオプションになる可能性があります。

以下のvroomベンチマークの簡略化された例を参照してください。確認する重要な部分は、超高速の読み取り時間ですが、集計などの操作がわずかに不足しています。

package                 read    print   sample   filter  aggregate   total
read.delim              1m      21.5s   1ms      315ms   764ms       1m 22.6s
readr                   33.1s   90ms    2ms      202ms   825ms       34.2s
data.table              15.7s   13ms    1ms      129ms   394ms       16.3s
vroom (altrep) dplyr    1.7s    89ms    1.7s     1.3s    1.9s        6.7s

5

言及する価値があるマイナーな追加のポイント。非常に大きなファイルがある場合bedGraphは、(ヘッダーがない場合)を使用してその場で行数を計算できます(は作業ディレクトリ内のファイルの名前です)。

>numRow=as.integer(system(paste("wc -l", bedGraph, "| sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/'"), intern=T))

その後、それをread.csvread.table...のいずれかで使用できます。

>system.time((BG=read.table(bedGraph, nrows=numRow, col.names=c('chr', 'start', 'end', 'score'),colClasses=c('character', rep('integer',3)))))
   user  system elapsed 
 25.877   0.887  26.752 
>object.size(BG)
203949432 bytes

4

多くの場合、私はデータベース(例えばPostgres)内に大きなデータベースを保持することがちょうど良い習慣だと思います。(nrow * ncol)ncell = 10Mよりかなり大きいものは使用しません。これはかなり小さいです。しかし、複数のデータベースからクエリを実行している間だけ、Rにメモリを大量に使用するグラフを作成して保持させたいことがよくあります。32 GBラップトップの将来的には、これらのタイプのメモリの問題のいくつかはなくなるでしょう。しかし、データベースを使用してデータを保持し、結果のクエリ結果とグラフにRのメモリを使用するという魅力は、依然として有用かもしれません。いくつかの利点は次のとおりです。

(1)データはデータベースにロードされたままです。ラップトップを再びオンにしたときに、pgadminで必要なデータベースに再接続するだけです。

(2)確かに、RはSQLよりもはるかに優れた統計およびグラフ作成操作を実行できます。しかし、SQLはRよりも大量のデータをクエリするように設計されていると思います。

# Looking at Voter/Registrant Age by Decade

library(RPostgreSQL);library(lattice)

con <- dbConnect(PostgreSQL(), user= "postgres", password="password",
                 port="2345", host="localhost", dbname="WC2014_08_01_2014")

Decade_BD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from Birthdate) from voterdb where extract(DECADE from Birthdate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")

Decade_RD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from RegistrationDate) from voterdb where extract(DECADE from RegistrationDate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")

with(Decade_BD_1980_42,(barchart(~count | as.factor(precinctid))));
mtext("42LD Birthdays later than 1980 by Precinct",side=1,line=0)

with(Decade_RD_1980_42,(barchart(~count | as.factor(precinctid))));
mtext("42LD Registration Dates later than 1980 by Precinct",side=1,line=0)

3

新しいarrowパッケージを使用して非常に迅速にデータを読み取っています。かなり初期の段階にあるようです。

具体的には、寄木細工の柱状形式を使用しています。これdata.frameはRでa に変換されますが、変換しない場合はさらに高速化できます。このフォーマットは、Pythonからも使用できるため便利です。

これの私の主な使用例は、かなり制限されたRShinyサーバー上です。これらの理由から、私はデータをアプリに添付したままにする(つまり、SQLから除外する)ことを好むので、小さいファイルサイズと速度を必要とします。

このリンクされた記事は、ベンチマークと優れた概要を提供します。以下にいくつか興味深い点を引用しました。

https://ursalabs.org/blog/2019-10-columnar-perf/

ファイルサイズ

つまり、Parquetファイルはgzip圧縮されたCSVの半分の大きさです。Parquetファイルが非常に小さい理由の1つは、辞書エンコーディング(「辞書圧縮」とも呼ばれる)が原因です。辞書圧縮は、LZ4やZSTD(FST形式で使用される)などの汎用バイトコンプレッサーを使用するよりも大幅に優れた圧縮を実現できます。Parquetは、読み取りが高速な非常に小さなファイルを生成するように設計されています。

読み取り速度

出力タイプ(たとえば、すべてのR data.frame出力を互いに比較する)で制御する場合、Parquet、Feather、およびFSTのパフォーマンスは互いに比較的小さいマージン内に収まっています。同じことがpandas.DataFrame出力にも当てはまります。data.table :: freadは1.5 GBのファイルサイズと非常に競争力がありますが、2.5 GBのCSVでは他のファイルよりも遅れています。


独立したテスト

1,000,000行のシミュレーションデータセットに対して、いくつかの独立したベンチマークを実行しました。基本的に、私は圧縮に挑戦するために周りのものの束をシャッフルしました。また、ランダムな単語と2つのシミュレートされた要素の短いテキストフィールドを追加しました。

データ

library(dplyr)
library(tibble)
library(OpenRepGrid)

n <- 1000000

set.seed(1234)
some_levels1 <- sapply(1:10, function(x) paste(LETTERS[sample(1:26, size = sample(3:8, 1), replace = TRUE)], collapse = ""))
some_levels2 <- sapply(1:65, function(x) paste(LETTERS[sample(1:26, size = sample(5:16, 1), replace = TRUE)], collapse = ""))


test_data <- mtcars %>%
  rownames_to_column() %>%
  sample_n(n, replace = TRUE) %>%
  mutate_all(~ sample(., length(.))) %>%
  mutate(factor1 = sample(some_levels1, n, replace = TRUE),
         factor2 = sample(some_levels2, n, replace = TRUE),
         text = randomSentences(n, sample(3:8, n, replace = TRUE))
         )

読み書き

データの書き込みは簡単です。

library(arrow)

write_parquet(test_data , "test_data.parquet")

# you can also mess with the compression
write_parquet(test_data, "test_data2.parquet", compress = "gzip", compression_level = 9)

データの読み取りも簡単です。

read_parquet("test_data.parquet")

# this option will result in lightning fast reads, but in a different format.
read_parquet("test_data2.parquet", as_data_frame = FALSE)

私はいくつかの競合するオプションに対してこのデータの読み取りをテストしましたが、予想された上記の記事とは少し異なる結果が得られました。

ベンチマーク

このファイルはベンチマークの記事ほど大きくはないので、おそらくそれが違いです。

テスト

  • rds test_data.rds(20.3 MB)
  • parquet2_native:(高圧縮で14.9 MBおよびas_data_frame = FALSE
  • parquet2: test_data2.parquet(高圧縮で14.9 MB)
  • 寄木細工: test_data.parquet(40.7 MB)
  • fst2: test_data2.fst(より高い圧縮で27.9 MB)
  • fst test_data.fst(76.8 MB)
  • fread2: test_data.csv.gz(23.6MB)
  • fread: test_data.csv(98.7MB)
  • feather_arrow: test_data.feather(157.2 MBで読み込まれるarrow
  • feather: test_data.feather(157.2 MBで読み込まれるfeather

観察

この特定のファイルの場合、fread実際には非常に高速です。高度に圧縮されたparquet2テストの小さいファイルサイズが好きです。data.frameスピードアップが本当に必要な場合は、時間をかけてネイティブデータ形式で作業する場合があります。

ここfstも素晴らしい選択です。速度またはファイルサイズのトレードオフが必要かどうかに応じて、高度に圧縮されたfst形式または高度に圧縮された形式のいずれかを使用parquetします。


0

従来のread.tableの代わりに、freadの方が高速な関数だと思います。必要な列のみを選択するなどの追加属性を指定し、要素としてcolclassesとstringを指定すると、ファイルのインポートにかかる時間が短縮されます。

data_frame <- fread("filename.csv",sep=",",header=FALSE,stringsAsFactors=FALSE,select=c(1,4,5,6,7),colClasses=c("as.numeric","as.character","as.numeric","as.Date","as.Factor"))

0

上記のすべてを試してみて、[reader] [1]が最高の仕事をしました。RAMが8GBしかない

20ファイル、各5GB、7列のループ:

read_fwf(arquivos[i],col_types = "ccccccc",fwf_cols(cnpj = c(4,17), nome = c(19,168), cpf = c(169,183), fantasia = c(169,223), sit.cadastral = c(224,225), dt.sitcadastral = c(226,233), cnae = c(376,382)))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.