Pandas:グループ毎に括って最大の値を含む列を抜き出す

PythonのライブラリーであるPandasを使って,「グループ毎に括って最大の値を含む列を抜き出す」方法のメモです.

対象とするのはこんなデータ 

Sensor Time Value
0 T-A 10:00:00 25
1 T-B 10:00:01 30
2 T-C 10:00:02 104
3 T-B 10:00:03 52
4 T-C 10:00:04 41
5 T-A 10:00:05 91
6 T-C 10:00:06 102
7 T-B 10:00:07 40
8 T-B 10:00:08 101
9 T-C 10:00:09 97

 
3種類のSensorから時間と検知された値(Value)が返ってきます.
Sensorの種類ごとに括って,その中で最大の値を出す時間(と言うか行)を抜き出す,というのが今回の狙いです.
 
コードは下記の通り.
特定の列に含まれる最大値を含む行を抜き出す(日本語が複雑・・)方法が分からなかったのでやや力技を使いました.

import pandas as pd

# データ生成
df = pd.DataFrame(
        {'Time': ['10:00:00', '10:00:01', '10:00:02', '10:00:03', '10:00:04','10:00:05', '10:00:06', '10:00:07', '10:00:08', '10:00:09'],
         'Sensor': ['T-A', 'T-B', 'T-C', 'T-B', 'T-C', 'T-A', 'T-C', 'T-B' ,'T-B' ,'T-C'],
           'Value': [25, 30, 104, 52, 41, 91, 102, 40 ,101 ,97]})

# datetime型に変換
df['Time'] = df['Time'].apply(lambda dd: pd.to_datetime(dd))

# 'Sensor'で括る    
df_g = df.groupby('Sensor')

# 'Sensor'でくくられたデータフレームの中で'Value'に最大値を含む行を抜き出す
def select(xx):
    # 'Value'に最大値を含む行を抜き出す(そういうメソッドがあるのかもしれないけど分からなかった)
    val_r = xx[xx['Value'] == max(xx['Value']) ]
    
    # 全く同じ行があった場合は削除(このデータの場合は無いですけど)
    val_r = val_r.drop_duplicates()
    
    return val_r

df_new = df_g.apply(select)

ご覧の通り,Valueに含まれる最大値を含む行は無理やり書きました.
結果は下記の通り
 

Sensor Time Value
Sensor 
T-A 5 T-A 2017-10-08 10:00:05 91
T-B 8 T-B 2017-10-08 10:00:08 101
T-C 2 T-C 2017-10-08 10:00:02 104

Anacondaをインストールしようとすると「Failed to create Anaconda menus」と言われる

Anacondaをアップデートしたらおかしくなったので再インストールした.

そしたら「Failed to create Anaconda menus」と言われてインストールできない.

shirabeta.net

アンインストールしてもフォルダが残っていたので削除したらインストールできたっぽい

Python:秒数が小数点以下のパース

Pandasでデータフレームに格納するときに,時間にナノ秒まで含まれている時のパースのやり方についてのメモ.

対象とするのはこんなデータ.

//file.csv
17:22:59.703371360,10
17:22:59.788956621,20
17:22:59.790719017,30
17:22:59.813919277,20
17:22:59.891942610,10
17:22:59.898820371,20
17:22:59.919604329,30

こんな感じで,小数点以下がすごい長いデータをパースしたいわけです.
一例としてこんな感じでしょうか.

import pandas as pd

# データ読み込み
df = pd.read_csv('file.csv', names=('time', 'val'))

# datetime型に変換
from dateutil import parser
df.time = df.time.apply(lambda x: parser.parse(x))

# 表示
print(df.dtypes)

出力すると

time    datetime64[ns]
val              int64
dtype: object

parserを使って無理やりdatetime型に変えています.
あとはapplyで一行づつ適用してます.
若干力技な気がしますが...

追記

このフォーマットの場合はparse_datesで指定するだけでも行けるっぽい.

import pandas as pd

# データ読み込み
df = pd.read_csv('time.csv', names=('time', 'val'),parse_dates=['time'])

# 表示
print(df.dtypes)

ランダム関数について

numpyランダム関数を色々使ってみました.

まずはインポート

In [1]: import numpy as np


random()は0から1までの値が得られる

In [10]: np.random.random()
Out[10]: 0.45226808024834264


引数を入れると,入れた数字分の乱数が得られる

In [12]: np.random.random(5)
Out[12]: array([ 0.93385679,  0.6383795 ,  0.20373784,  0.76812241,  0.42309771])


範囲指定は出来ないみたいです

In [13]: random.uniform(1,100)
Traceback (most recent call last):


random.uniformで値を指定できるみたいです

In [14]: np.random.uniform(1,100)
Out[14]: 8.543481477277378

In [17]: np.random.uniform(2,5)
Out[17]: 2.2877891814898934


引数を入れないとrandom()と同じなんですかね?

In [15]: np.random.uniform()
Out[15]: 0.4615576165499794


範囲を指定して,個数も指定できるみたいです

In [18]: np.random.uniform(2,5,3)
Out[18]: array([ 4.67283745,  2.26006292,  4.18645001])

移動平均を計算しようとすると「FutureWarning: pd.rolling_mean is deprecated for Series and will be removed in a future version, replace with ・・・」と出て来る


FutureWarning: pd.rolling_mean is deprecated for Series and will be removed in a future version, replace with ・・・


stackoverflow.com

特定の行・列を残す:Python,Numpy

Pandasで条件を指定して行・列を抜き出すやつが有ると思います.正式名称は分かりませんが,df[val>0]みたいなやつです.Numpyのarrayでおんなじことが出来るか試したので,メモ書きしておきます.

まずはこんな感じで配列を作ります.そして1個飛ばしで列を獲得できるかやってみます.

In [31]: import numpy as np

In [32]: a = np.array([[ 0,  1,  2,  3],
    ...:            [ 4,  5,  6,  7],
    ...:            [ 8,  9, 10, 11],
    ...:            [12, 13, 14, 15]])

In [33]: label = np.array([ 0,  1,  0,  1])

In [34]: mask = (label == 1)

まずは一個飛ばしで列を獲得してみます.
f:id:shu10038:20170411165227j:plain

In [35]: a[:,mask]
Out[35]: 
array([[ 1,  3],
       [ 5,  7],
       [ 9, 11],
       [13, 15]])


続いて一個飛ばしで行を獲得してみます.
f:id:shu10038:20170411165210j:plain

In [36]: a[mask,:]
Out[36]: 
array([[ 4,  5,  6,  7],
       [12, 13, 14, 15]])


それでは,一個飛ばしで行と列の両方を獲得するにはどうやるのでしょう?
f:id:shu10038:20170411165244j:plain

In [37]: a[mask,mask]
Out[37]: array([ 5, 15])

これだと上手く行かないので,次のように書いてみました.

In [38]: a[:,mask][mask,:]
Out[38]: 
array([[ 5,  7],
       [13, 15]])