LoginSignup
0
0

More than 1 year has passed since last update.

データフレームのHEX(16進数)カラムを自動判定、10進数に自動変換

Last updated at Posted at 2022-05-10

はじめに

分析対象データにHEX(16進数)データがある場合、基本統計量や傾向を確認するためには、10進数に変換しなければなりません。
できればPythonで、HEXだけのデータカラムを自動で判定し、10進数に自動変換させたいということで、実行してみました。

実行条件など

  • Google colabで実行

まずはデータを準備

16進数⇒10進数変換を試行するデータを仮想、以下の通りデータフレームに格納しました。
aはint、cはfloat、b,fがHEX(16進数)データ、dはobject、eはint(ほぼ欠損データ)としています。
16進数⇒10進数変換したいカラムは b列,f列です。

df = pd.DataFrame({
  'a': [5, 2, 3, 100, 110, 200],
  'b': ['abc', '0C3A', '9F07D2','ffff','ffff','7b2'],
  'c': [19.3, 22.7, 99.5, 200.2, 300.5, 1200.3],
  'd': ['A', '100', 'a','abc','AB','ZA-20'],
  'e': [1, np.nan, np.nan, np.nan, np.nan, np.nan],
  'f': ['abc', '0C3A', '9F07D2','ffff','ffff','7b2']
})
print(df)
index a b c d e f
0 5 abc 19.3 A 1.0 abc
1 2 0C3A 22.7 100 NaN 0C3A
2 3 9F07D2 99.5 a NaN 9F07D2
3 100 ffff 200.2 abc NaN ffff
4 110 ffff 300.5 AB NaN ffff
5 200 7b2 1200.3 ZA-20 NaN 7b2

HEX⇒INT処理をデータフレーム全体に実行すると?

def hex_to_int(s):
  try:
    return int(s, base=16)
  except:
    return s

dfx = df.applymap(hex_to_int)
dfx

元データ

index a b c d e f
0 5 abc 19.3 A 1.0 abc
1 2 0C3A 22.7 100 NaN 0C3A
2 3 9F07D2 99.5 a NaN 9F07D2
3 100 ffff 200.2 abc NaN ffff
4 110 ffff 300.5 AB NaN ffff
5 200 7b2 1200.3 ZA-20 NaN 7b2

変換後データ

index a b c d e f
0 5 2748 19.3 10 1.0 2748
1 2 3130 22.7 256 NaN 3130
2 3 10422226 99.5 10 NaN 10422226
3 100 65535 200.2 2748 NaN 65535
4 110 65535 300.5 171 NaN 65535
5 200 1970 1200.3 ZA-20 NaN 1970

上記が変換結果です。
b,f列は意図通り10進数に変換され、int, float列はそのまま維持されていますが、d列(object)の ’A’、’100’、’abc’等がHEX(16進数)と認識され、変換されてしまいます。

HEX⇒INT変換するカラムを指定してみる

上記のままではまずいので、10進数に変換するカラムを指定して実行してみます。

#カラムの指定(※ #@param {type:"raw"} はGoogleColabのフォームです)
Object_label_to = 'b','f' #@param {type:"raw"}
#指定カラムHEX⇒INT変換
for i in Object_label_to:
  if df[col].dtype == 'object':
    df[i]=df[i].apply(lambda x:int(x, 16))
print(df)
index a b c d e f
0 5 2748 19.3 A 1.0 2748
1 2 3130 22.7 100 NaN 3130
2 3 10422226 99.5 a NaN 10422226
3 100 65535 200.2 abc NaN 65535
4 110 65535 300.5 AB NaN 65535
5 200 1970 1200.3 ZA-20 NaN 1970

これで、意図した変換ができました。
 

string.hexdigits を利用してみる

ただ、カラムの指定はデータフレームサイズが大きくなるほど面倒なので、カラムデータが16進数であるかどうかを判定してみます。
以下を実行すると、16進数の要素を返してくれます。

import string
string.hexdigits

0123456789abcdefABCDEF

 
このstringを利用して、データフレームの各カラムが16進数データかどうかを確認してみます。

for col in df.columns:
  if df[col].dtype == 'object':   #int,floatカラムに実行するとエラーになるのでobject指定
    print(col)
    result=df[col].map(lambda x: set(x).issubset(set(string.hexdigits)))
    print(result)

b
0 True
1 True
2 True
3 True
4 True
5 True
Name: b, dtype: bool
d
0 True
1 True
2 True
3 True
4 True
5 False
Name: d, dtype: bool
f
0 True
1 True
2 True
3 True
4 True
5 True
Name: f, dtype: bool

上記は、object列であるb,d,f列のみ、データが16進数であるかが判定された結果です。
d列のNo.5データ(ZA-20)のみ、False(16進数ではない)と判定されています。
 
 
次にカラム全体が16進数データであるかを判定します。

for col in df.columns:
  if df[col].dtype == 'object':
    if all(df[col].apply(lambda x: set(x).issubset(set(string.hexdigits)))) ==True:
      print(col,True)
    else:
      print(col,False)

b True
d False
f True

これで、16進数だけで構成されているb列、f列だけをピックアップすることができました。

16進数だけのカラムデータを自動判定し、10進数に変換

for col in df.columns:
  if df[col].dtype == 'object':
    if all(df[col].apply(lambda x: set(x).issubset(set(string.hexdigits)))) ==True:
      df[col]=df[col].apply(lambda x:int(x, 16))
print(df)
index a b c d e f
0 5 2748 19.3 A 1.0 2748
1 2 3130 22.7 100 NaN 3130
2 3 10422226 99.5 a NaN 10422226
3 100 65535 200.2 abc NaN 65535
4 110 65535 300.5 AB NaN 65535
5 200 1970 1200.3 ZA-20 NaN 1970

いけました。

ところが、現実データを確認するとあまりにゴミデータが多い。。。
16進数だけのカラムデータというのは、ありえない気がしてきましたので、結局、16進数のカラムを指定し、16進数データのみ10進数に変換することに。

16進数のカラムを指定し、16進数データのみ10進数に変換

HEX2INT = 'b1', 'f1' # @param {type: "raw"}
HEX2INT = pd. Series(HEX2INT)

import string
for i in HEX2INT:
  if df[i].dtype == 'object':
     for x in df[i]:
       try:
         if set (x).issubset(set(string.hexdigits)) ==True
         df[i].replace(x, int(x, 16), inplace=True)
       except:
         print('例外',i,x)

‘abc’,‘---’,‘fail’,‘ffff’,‘NaN’,‘7b2’というデータならば、
‘2738’,‘---’,‘fail’,‘65535’,‘NaN’,‘1970’となります。
isdigitで数字以外を nanにするか、削除するかなど、もう一段処理は必要ですが。

参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0