🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

1回答

2461閲覧

pandasを使ったデータフレームの数行まとめてのシャッフル

simpkins

総合スコア5

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

1グッド

1クリップ

投稿2020/11/13 13:46

編集2020/11/14 07:22

前提・実現したいこと

時間粒度が1時間のデータが3ヶ月分あります(時間の列はインデックス)。

時間data1data2
2015-04-01 00:00:00110
2015-04-01 01:00:00220
2015-04-01 02:00:00330
:::
2015-04-01 23:00:00440
2015-04-02 00:00:00550
:::
2015-06-30 22:00:00660
2015-06-30 23:00:00770

このデータフレームで、各月ごとに同じ日のデータを一つの塊としてシャッフルしたい。
同じ日のデータを一つの塊にするというのは、例えば、4月1日内の1時と5時のデータをシャッフルなどはせず、0時から23時までを1つの塊とし、4月1日の塊と4月5日の塊や4月2日の塊と4月10日の塊をシャッフルしたりするということ。
4月のデータは4月内だけで、5月のデータは5月内だけでシャッフルする。

最終的にはシャッフルしたデータを1つのリストに格納したい。

該当のソースコード

import pandas as pd import itertools import numpy as np csv = pd.read_csv('sample.csv', parse_dates=[0], index_col=0) data1_m4=[ list(csv.loc['2015-04-01 00:00:00':'2015-04-01 23:00:00', 'data1']),list(csv.loc['2015-04-02 00:00:00':'2015-04-02 23:00:00', 'data1']),list(csv.loc['2015-04-02 00:00:00':'2015-04-02 23:00:00', 'data1']),list(csv.loc['2015-04-03 00:00:00':'2015-04-03 23:00:00', 'data1']),list(csv.loc['2015-04-04 00:00:00':'2015-04-04 23:00:00', 'data1']),list(csv.loc['2015-04-05 00:00:00':'2015-04-02 23:00:00', 'data1']),list(csv.loc['2015-04-06 00:00:00':'2015-04-06 23:00:00', 'data1']) ] np.random.shuffle(data1_m4) a = list(itertools.chain.from_iterable(data1_m4)) #ここで二次元リストを一次元リストにする

試したこと

ここでは4月の中の6日分しか記述していないですが、本来は30日分書きます。
これを他の月でもやり、最後に3ヶ月のリストを1つのリストに結合すれば一応はやりたいことが達成できます。
しかし、このやり方はかなり面倒なので何か簡単にできる方法はないでしょうか。

import pandas as pd import itertools import numpy as np csv = pd.read_csv('sample.csv', parse_dates=[0], index_col=0) df=csv.resample('H').mean() #元のデータは30分刻みのデータなのでここで1時間ごとのデータにしています #ここから下は全く同じ def shuffle_days(df_month): groups = [df for _, csv1 in df_month.groupby('D')] random.shuffle(groups) return pd.concat(groups).reset_index(drop=True) df = df.reset_index() df['Y'] = df['時間'].dt.year df['M'] = df['時間'].dt.month df['D'] = df['時間'].dt.day df = df.groupby(['Y', 'M']).apply(shuffle_days) df = df.drop(['Y', 'M', 'D'], axis=1).reset_index(drop=True) print(df)

一応csvファイルの時間の表記も載せておきます。元のデータはcsv上でこのような形式になっています。

時間data1data2
2015/4/1 1:00:00110
2015/4/1 2:00:00220
:::
### 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

toast-uz👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

年月でグループ化して、さらにその中で日単位にグループ化してグループ単位でシャッフルする、という処理を書くことで、うまい具合に、質問者様の求めるシャッフル後のデータフレームを一気に、高速に得ることができます。

Python

1import pandas as pd 2import random 3 4# 質問にあるようなデータフレームを作成 5datetime_ = pd.to_datetime('2015-04-01 00:00:00') 6df_elm = [] 7for i in range(2000): 8 df_elm.append([datetime_, i, i*10]) 9 datetime_ += pd.Timedelta('1 hours') 10df = pd.DataFrame(df_elm, columns=['時間', 'data1', 'data2']) 11df = df.set_index('時間', drop=True) 12 13# ここからが計算本番 14def shuffle_days(df_month): 15 groups = [df for _, df in df_month.groupby('D')] 16 random.shuffle(groups) 17 return pd.concat(groups).reset_index(drop=True) 18 19df = df.reset_index() 20df['Y'] = df['時間'].dt.year 21df['M'] = df['時間'].dt.month 22df['D'] = df['時間'].dt.day 23df = df.groupby(['Y', 'M']).apply(shuffle_days) 24df = df.drop(['Y', 'M', 'D'], axis=1).reset_index(drop=True) 25 26pd.set_option('display.max_rows', None) 27print(df)

結果

時間 data1 data2 0 2015-04-13 00:00:00 288 2880 1 2015-04-13 01:00:00 289 2890 2 2015-04-13 02:00:00 290 2900 3 2015-04-13 03:00:00 291 2910 4 2015-04-13 04:00:00 292 2920 5 2015-04-13 05:00:00 293 2930 6 2015-04-13 06:00:00 294 2940 7 2015-04-13 07:00:00 295 2950 8 2015-04-13 08:00:00 296 2960 9 2015-04-13 09:00:00 297 2970 10 2015-04-13 10:00:00 298 2980 11 2015-04-13 11:00:00 299 2990 12 2015-04-13 12:00:00 300 3000 13 2015-04-13 13:00:00 301 3010 14 2015-04-13 14:00:00 302 3020 15 2015-04-13 15:00:00 303 3030 16 2015-04-13 16:00:00 304 3040 17 2015-04-13 17:00:00 305 3050 18 2015-04-13 18:00:00 306 3060 19 2015-04-13 19:00:00 307 3070 20 2015-04-13 20:00:00 308 3080 21 2015-04-13 21:00:00 309 3090 22 2015-04-13 22:00:00 310 3100 23 2015-04-13 23:00:00 311 3110 24 2015-04-09 00:00:00 192 1920 25 2015-04-09 01:00:00 193 1930 26 2015-04-09 02:00:00 194 1940 27 2015-04-09 03:00:00 195 1950 28 2015-04-09 04:00:00 196 1960 29 2015-04-09 05:00:00 197 1970 30 2015-04-09 06:00:00 198 1980 31 2015-04-09 07:00:00 199 1990 32 2015-04-09 08:00:00 200 2000 33 2015-04-09 09:00:00 201 2010 34 2015-04-09 10:00:00 202 2020 35 2015-04-09 11:00:00 203 2030 36 2015-04-09 12:00:00 204 2040 37 2015-04-09 13:00:00 205 2050 38 2015-04-09 14:00:00 206 2060 39 2015-04-09 15:00:00 207 2070 40 2015-04-09 16:00:00 208 2080 41 2015-04-09 17:00:00 209 2090 42 2015-04-09 18:00:00 210 2100 43 2015-04-09 19:00:00 211 2110 44 2015-04-09 20:00:00 212 2120 45 2015-04-09 21:00:00 213 2130 46 2015-04-09 22:00:00 214 2140 47 2015-04-09 23:00:00 215 2150 48 2015-04-08 00:00:00 168 1680 49 2015-04-08 01:00:00 169 1690 50 2015-04-08 02:00:00 170 1700 51 2015-04-08 03:00:00 171 1710 52 2015-04-08 04:00:00 172 1720 以下続く

投稿2020/11/13 23:55

toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

simpkins

2020/11/14 02:32

回答ありがとうございます。 私の場合はcsvファイルからデータフレームを作成しました。 それを使って、シャッフル後のデータフレームを出力しようとしたらデータの出力が大きすぎて出力できないというエラーが出てしまいました。データフレームの一部なら出力できたのですが、出力結果はシャッフルされる前の結果が出力されてしまいました。どうしてこうなったのかわかりません。 ちなみに、回答者様のプログラムをそのまま入力したらシャッフルされた値がきちんと出力されました。
toast-uz

2020/11/14 03:18 編集

質問者様のデータフレームを、私の回答後半にかけると、エラーがでる、ということでしょうか? エラーは最後のprint(df)で発生するのでしょうか? その前のpd.set_option('display.max_rows', None)は、表示形式を調整しているだけで本質的ではありません。質問者様の環境に合わないのかもしれませんので、この行を削除して試してみてください。
simpkins

2020/11/14 04:04

pd.set_option('display.max_rows', None)を消したらエラーはでなくなりました。 しかし、結果の行数が元の行数の6倍くらいに増えて出力されてしまいます。元のデータフレームだけを出力するとちゃんと出力されるのですが、このプログラムに入れると行数がおかしくなってしまいます。 元の行数は1464に対して出力の行数は89304という感じです。これは4月と5月のみで実行しています。
toast-uz

2020/11/14 05:30

謎ですね。質問者様のread_csvの直後に pd.set_option('display.max_rows', None) print(csv) を入れて、最初の100行くらいを見せていただけますでしょうか?
simpkins

2020/11/14 05:57

4月1日から4月5日までです。csvファイルの何かがおかしいんですかね? 時間          data1 data2 2015-04-01 00:00:00 80 0.0 2015-04-01 01:00:00 90 0.0 2015-04-01 02:00:00 80 0.0 2015-04-01 03:00:00 80 0.0 2015-04-01 04:00:00 80 0.0 2015-04-01 05:00:00 80 0.0 2015-04-01 06:00:00 80 0.1 2015-04-01 07:00:00 70 0.3 2015-04-01 08:00:00 100 0.7 2015-04-01 09:00:00 170 1.4 2015-04-01 10:00:00 170 2.5 2015-04-01 11:00:00 160 2.5 2015-04-01 12:00:00 110 3.7 2015-04-01 13:00:00 90 4.1 2015-04-01 14:00:00 210 0.9 2015-04-01 15:00:00 190 1.3 2015-04-01 16:00:00 210 0.7 2015-04-01 17:00:00 200 1.0 2015-04-01 18:00:00 200 0.1 2015-04-01 19:00:00 170 0.0 2015-04-01 20:00:00 160 0.0 2015-04-01 21:00:00 140 0.0 2015-04-01 22:00:00 300 0.0 2015-04-01 23:00:00 360 0.0 2015-04-02 00:00:00 230 0.0 2015-04-02 01:00:00 160 0.0 2015-04-02 02:00:00 150 0.0 2015-04-02 03:00:00 140 0.0 2015-04-02 04:00:00 140 0.0 2015-04-02 05:00:00 130 0.0 2015-04-02 06:00:00 120 0.2 2015-04-02 07:00:00 60 1.8 2015-04-02 08:00:00 30 4.2 2015-04-02 09:00:00 30 7.1 2015-04-02 10:00:00 10 8.6 2015-04-02 11:00:00 10 9.5 2015-04-02 12:00:00 0 9.8 2015-04-02 13:00:00 0 9.5 2015-04-02 14:00:00 0 8.7 2015-04-02 15:00:00 30 7.4 2015-04-02 16:00:00 110 4.2 2015-04-02 17:00:00 210 0.7 2015-04-02 18:00:00 240 0.1 2015-04-02 19:00:00 230 0.0 2015-04-02 20:00:00 220 0.0 2015-04-02 21:00:00 170 0.0 2015-04-02 22:00:00 200 0.0 2015-04-02 23:00:00 190 0.0 2015-04-03 00:00:00 160 0.0 2015-04-03 01:00:00 140 0.0 2015-04-03 02:00:00 130 0.0 2015-04-03 03:00:00 120 0.0 2015-04-03 04:00:00 120 0.0 2015-04-03 05:00:00 120 0.0 2015-04-03 06:00:00 110 0.0 2015-04-03 07:00:00 100 0.4 2015-04-03 08:00:00 130 0.5 2015-04-03 09:00:00 170 2.1 2015-04-03 10:00:00 210 1.9 2015-04-03 11:00:00 230 1.5 2015-04-03 12:00:00 230 1.2 2015-04-03 13:00:00 200 1.3 2015-04-03 14:00:00 210 2.5 2015-04-03 15:00:00 190 1.9 2015-04-03 16:00:00 240 0.9 2015-04-03 17:00:00 230 0.6 2015-04-03 18:00:00 250 0.0 2015-04-03 19:00:00 230 0.0 2015-04-03 20:00:00 200 0.0 2015-04-03 21:00:00 170 0.0 2015-04-03 22:00:00 150 0.0 2015-04-03 23:00:00 110 0.0 2015-04-04 00:00:00 100 0.0 2015-04-04 01:00:00 90 0.0 2015-04-04 02:00:00 90 0.0 2015-04-04 03:00:00 90 0.0 2015-04-04 04:00:00 80 0.0 2015-04-04 05:00:00 90 0.0 2015-04-04 06:00:00 70 0.0 2015-04-04 07:00:00 80 0.2 2015-04-04 08:00:00 90 0.2 2015-04-04 09:00:00 120 0.4 2015-04-04 10:00:00 130 1.1 2015-04-04 11:00:00 130 1.5 2015-04-04 12:00:00 130 2.4 2015-04-04 13:00:00 130 2.9 2015-04-04 14:00:00 140 2.5 2015-04-04 15:00:00 150 1.7 2015-04-04 16:00:00 160 0.9 2015-04-04 17:00:00 150 0.3 2015-04-04 18:00:00 160 0.0 2015-04-04 19:00:00 140 0.0 2015-04-04 20:00:00 140 0.0 2015-04-04 21:00:00 130 0.0 2015-04-04 22:00:00 270 0.0 2015-04-04 23:00:00 300 0.0 2015-04-05 00:00:00 160 0.0 2015-04-05 01:00:00 140 0.0 2015-04-05 02:00:00 130 0.0 2015-04-05 03:00:00 120 0.0 2015-04-05 04:00:00 120 0.0 2015-04-05 05:00:00 130 0.0 2015-04-05 06:00:00 120 0.0 2015-04-05 07:00:00 110 0.3 2015-04-05 08:00:00 110 0.5 2015-04-05 09:00:00 120 0.7 2015-04-05 10:00:00 130 1.0 2015-04-05 11:00:00 140 1.2 2015-04-05 12:00:00 140 1.4 2015-04-05 13:00:00 150 1.2 2015-04-05 14:00:00 160 0.8 2015-04-05 15:00:00 170 0.3 2015-04-05 16:00:00 190 0.2 2015-04-05 17:00:00 170 0.0 2015-04-05 18:00:00 130 0.0 2015-04-05 19:00:00 140 0.0 2015-04-05 20:00:00 130 0.0 2015-04-05 21:00:00 110 0.0 2015-04-05 22:00:00 170 0.0 2015-04-05 23:00:00 220 0.0
toast-uz

2020/11/14 06:30

ありがとうございます。データにおかしいところは見当たらないです。念のため120行を取り込んでシャッフルしてみましたが、120行のままでした。私の環境では不具合が再現していません。 考えられるのは、私のコードを質問者様のコードに加えた際に、うまくつながっていないところがあるということです。不具合が発生するコード全体(元のコードのread_csvから私のコードを追加した部分の全体)を、質問文の「試したこと」のところに、コードの挿入ボタンを使って挿入してください。
simpkins

2020/11/14 07:22

質問編集しました。
toast-uz

2020/11/14 08:26

この行が違っています。 groups = [df for _, csv1 in df_month.groupby('D')]
simpkins

2020/11/14 09:11

csv1をdfにしたら上手くいきました。もっと注意深く見ればわかるものでしたね。 長々と付き合わせてしまい申し訳ありませんでした。グループ化のやり方など大変勉強になりました。 ありがとうございました。
toast-uz

2020/11/14 09:19

こういうのは思い込むとわからなくなってしまうものですね。resampleを使いこなしているあたり、質問者様はレベルが高いと思います。私はresampleを知らなくて、(この質疑とは無関係に)昨日「Pandasクックブック」を読んで学んだところでした。質疑の中で偶然出てきたので、おおっと思いました。
simpkins

2020/11/15 01:53

回答者様に褒めていただくとは思いませんでした。うれしいです。 pandasだけでもまだまだ知らないことがたくさんありそうですね。 今後もお世話になることがあると思いますが、そのときはよろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問