web-dev-qa-db-ja.com

Pythonパンダ:DataFrameの特定の列のみをピボットし、他の列は保持します

Pandasを使用してjsonから自動的に読み込んだDataFrameを再配置しようとしています。検索しましたが、成功しませんでした。

私は次のjson(コピー/貼り付けの便宜のために文字列として保存されています)を持っており、タグ 'value'の下にjsonオブジェクト/辞書の束があります

json_str = '''{"preferred_timestamp": "internal_timestamp",
    "internal_timestamp": 3606765503.684,
    "stream_name": "ctdpf_j_cspp_instrument",
    "values": [{
        "value_id": "temperature",
        "value": 9.8319
    }, {
        "value_id": "conductivity",
        "value": 3.58847
    }, {
        "value_id": "pressure",
        "value": 22.963
    }]
}'''

Jsonをフラット化されたPandasデータフレームにロードするために、関数 'json_normalize'を使用します。

>>> from pandas.io.json import json_normalize
>>> import simplejson as json
>>> df = json_normalize(json.loads(json_str), 'values', ['preferred_timestamp', 'stream_name', 'internal_timestamp'])
>>> df
      value      value_id preferred_timestamp  internal_timestamp  \
0   9.83190   temperature  internal_timestamp        3.606766e+09   
1   3.58847  conductivity  internal_timestamp        3.606766e+09   
2  22.96300      pressure  internal_timestamp        3.606766e+09   
3  32.89470      salinity  internal_timestamp        3.606766e+09   

               stream_name  
0  ctdpf_j_cspp_instrument  
1  ctdpf_j_cspp_instrument  
2  ctdpf_j_cspp_instrument  
3  ctdpf_j_cspp_instrument  

これが私が立ち往生しているところです。 value列とvalue_id列を取得し、value_idに基づいてこれらを新しい列にピボットします。

データフレームを次のようにしたいと思います。

stream_name              preferred_timestamp  internal_timestamp  conductivity  pressure  salinity  temperature    
ctdpf_j_cspp_instrument  internal_timestamp   3.606766e+09        3.58847       22.96300  32.89470  9.83190

ピボット関数とピボットテーブルPandas関数の両方を試し、「set_index」と「stack」を使用してテーブルを手動でピボットしようとしましたが、それは私が望む方法ではありません。

>>> df.pivot_table(values='value', index=['stream_name', 'preferred_timestamp', 'internal_timestamp', 'value_id'])
stream_name              preferred_timestamp  internal_timestamp  value_id    
ctdpf_j_cspp_instrument  internal_timestamp   3.606766e+09        conductivity     3.58847
                                                                  pressure        22.96300
                                                                  salinity        32.89470
                                                                  temperature      9.83190
Name: value, dtype: float64

これは近いですが、「value_id」の値を個別の列にピボットするようには見えませんでした。

そして

>>> df.pivot('stream_name', 'value_id', 'value')
value_id                 conductivity  pressure  salinity  temperature
stream_name                                                           
ctdpf_j_cspp_instrument       3.58847    22.963   32.8947       9.8319

もう一度閉じますが、この行に関連付けたい他の列がありません。

私はここで立ち往生しています。これを行うエレガントな方法はありますか、それともDataFrameを分割して、希望どおりに再マージする必要がありますか?

13
naja

最初の試みはほぼ正しかったので、インデックスに含める代わりにcolumns='value_id'を使用してください。

# Perform the pivot.
df = df.pivot_table(
    values='value',
    index=['stream_name', 'preferred_timestamp', 'internal_timestamp'],
    columns='value_id'
    )

# Formatting.
df.reset_index(inplace=True)
df.columns.name = None

これはサンプルデータの問題ではありませんが、複数の値が同じ位置にピボットされた場合(デフォルトでは平均をとる)、pivot_tableが値を集約することに注意してください。

10
root