質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

解決済

メモリに乗りきらないcsvの重複レコード有無を判別する方法

ka-you
ka-you

総合スコア12

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

3回答

1評価

2クリップ

337閲覧

投稿2022/06/23 14:55

環境

CentOS
Python3

やりたいこと

メモリに乗りきらない大容量csvの重複レコード有無を判別したい。

補足

CentOS上で数十GBのcsvの集計を実施するタスクがある。
メモリに全レコード乗らないので、pandasでchunksizeを指定してTextFileReaderをループして集計する方針を立てた。

大部分の集計はこれで問題ないと思われたが、レコードを分割してしまうと全レコードに対して重複するレコードがないか確認する手段がないと気付いた。

概ね全カラム必要となるのでusecolでカラムを絞るのは不可。
csvの最大サイズが保証されないので、dtype明示してある程度メモリを節約してもオーバーフローする可能性あり。

試したこと

各カラムの値の組み合わせ毎に一意な識別子を生成する。
生成された識別子をリストに格納して重複判定する。
もしくはデリミタを設けて文字列型辺りでスタックして文字列検索して重複判定する。

ABC
123
456
789

上記テーブルの場合、
[123,456,789]に重複がないので重複レコードなし。
もしくは string型のstr = '/123/456/'と順番にスタックして、789が文字列内に含まれないので重複レコードなし。
以降は str = '/123/456/789/'として同様に後続の判定。

問題点

いずれの場合も数十GBのテーブルのすべてのレコードに対して識別子を生成する処理が必要となり、非常に処理時間が長くなってしまう。

かつ、レコードが非常に多い場合、リストでも文字列でもメモリに乗りきらない可能性がある。

結局知りたいこと

メモリは有限だが、csvの最大サイズは保証されない。
つまり、それらに依存せず、任意のメモリ内で分割して重複判定ができる方法があれば知りたい。

個人的には、少なくとも何らかの形でメモリに乗せきる必要はあると思う。

ただ、以前別件で鶴の一声があって、考えてみればそりゃそうだと思う様な手法で解決した実績があるので取り敢えず質問した次第です。

根幹的解決に至らずとも、少しでもメモリ効率を上げる手法がございましたらご提案いただけますと幸甚です。

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

meg_

2022/06/23 15:56

> メモリに乗りきらない大容量csvの重複レコード有無を判別したい。 どのようなデータか不明ですが、重複するようなデータなのですか?
ka-you

2022/06/23 15:58

いいえ。本来重複しないはずのデータです。 間違いなく重複がないか検品をする必要があります。
meg_

2022/06/23 16:13

awkを使ってもメモリ不足になりますか?
68user

2022/06/23 16:53

DBに突っ込んで重複行確認。 あるいは適当な行数でファイル分割してそれぞれをソートし、さらにマージソートで1ファイルに結合。上から順に見ていって同じ値が連続していたら重複 (全部をメモリ上に持たなくてもよい方法)
fourteenlength

2022/06/23 22:41 編集

> レコードが非常に多い場合、リストでも文字列でもメモリに乗りきらない可能性 カラムのボリュームによりますが、 1. レコード毎にSHA1(SHA2)ハッシュを生成 2. ハッシュを(リスト型よりコンパクトで済む)文字列型として結合 3. 連結したハッシュ文字列に対して一致ありなしを確認 ではいかがでしょうか? 質問の例のようにカラムの内容がSHA1ハッシュより短いとかえってかさばりますが、カラムの内容がSHA1ハッシュより長いならSHA1ハッシュ化すれば情報をいくらか集約できます。 「ハッシュでも長すぎる」であれば、ハッシュを前半後半に分割して、簡易的には前半のハッシュだけで検索してもし前半のハッシュが一致するなら別に取っておいてある後半のハッシュも検索--とすれば、一度に検索するデータ量は(前半が一致するまでは)半分まで減らせます。
fourteenlength

2022/06/23 22:39

stackoverflowを見るとmeg_さんのコメントにあるようにawkを使う方法がどれもトップに来ていました。たぶんPythonを使う時点で「メモリを食う」「処理が遅い」のダブルパンチになるのだと思います。
TakaiY

2022/06/24 01:20

「同一装置の同一時刻のデータ」など重複しているレコードの判断基準は無いのでしょう。これまでいろいろデータを扱ってきましたが、「全カラム同一なら重複」というデータを見たことがありません。
ka-you

2022/06/24 04:34

meg_様 awkでも乗り切りません。 swapは完全に使い潰しませんが、全体の8割程度のメモリを喰った後にstat:Dで処理が止まります。 68user様 DBの内部処理は明るくないので恐縮ですが、重複行の確認にレコード分のメモリ必要ないのでしょうか。 ただ、いずれにしても新規システムの導入は不可ですのでDBの利用はできません。 こちらもそこまで明るくありませんが、マージソートはIn-place等除いて要素数分メモリ必要な認識です。 分割した各ファイルはソート可能と思いますが、最終的に1ファイルに結合する際に全件分のメモリ必要ではないでしょうか。 fourteenlength様 ハッシュは私も考えました。 本文の例では単に結合しただけですが、文中の一意な識別子というのがそれです。 ご指摘の通り、Pythonで扱う時点で処理が遅い事案は発生してしまう様です。 awkを使ってもメモリに乗り切りませんでした。 TakaiY様 >...データを見たことがありません。 とのことですが、事実ベースそうなっています。 というか、既に不要なカラムを排除している状態です。 必要なカラムのみを抽出した結果、メモリに乗りきらないサイズのデータになっています。
68user

2022/06/24 07:32

> DBの内部処理は明るくないので恐縮ですが、重複行の確認にレコード分のメモリ必要ないのでしょうか。 メモリに乗らない分は一時領域であるHDD/SSDなどのストレージを使うのが一般的かと思います。もちろん遅いし、一時領域不足ならエラーになります。 > 分割した各ファイルはソート可能と思いますが、最終的に1ファイルに結合する際に全件分のメモリ必要ではないでしょうか。 試してませんが sort -m *.splitted-and-sorted | uniq -d で重複行出てこないでしょうか。sort -m は各ファイルがソートされている前提なのでファイル全体を溜め込まない。uniq は同じ行が連続していたら出力するだけ。 そもそも GNU sort であればメモリで足りない分は一時ファイルを使ってくれるので、微妙に足りない程度なら -S オプションを適切に使えば分割せずにいけるのかもしれません。
68user

2022/06/24 07:34

なおメモリはないけどストレージはそこそこあるという前提で書いてます。
ka-you

2022/06/24 14:46 編集

68user様 sort -m *.splitted-and-sorted | uniq -d についてです。 まだ試せていませんが、調べた所 sort -m はソートせずにマージのみ行うと認識しました。 マージというのはマージソートの事でしょうか。 そうでない場合、分割された各ファイルがソートされていたとしても、それぞれを連結しただけでは uniq -d では重複検出できないと思います。異なるファイル間で重複レコードが発生した場合など。 またマージソートの場合はやはりメモリに乗りきらないかと思います。 月曜日までにご返信いただければラッキー程度です。 月曜日には自分で検証できますので。 ちなみにストレージはそこそこあると思います。
otn

2022/06/24 15:48 編集

マージというのは、あらかじめソートされた複数ファイルから、全体としてソートされた1つのファイルを作ると言うことなので、出力ファイルはソート済みで、uniq コマンドが使えます。 データ用のメモリーは、「最大行長 * ファイル数」だけです。 例で言い換えると、 学校の各クラスの生徒が、身長順にクラス毎に一列になっているとして(5クラスの場合は5列に並ぶ)、 「各列の先頭の人の中で一番身長の低い人を出力列に移動する」 という操作を誰もいなくなるまで繰り返せば、出力列には全生徒が身長順に並んでいます。 これがマージです。 比較するのは先頭の5人だけで、先頭の人が移動するまで、次の人のデータは読まないので、 データを読み込むメモリーは5人の分だけあれば良いです。
ka-you

2022/06/25 02:22

otn様 ありがとうございます。納得できました。 stackoverflow等確認した所、想定しない一時ファイルが作成される、一度に処理可能なファイル数に上限がある、などの情報があり、他オプションも適切に利用する必要があるものと思いました。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。