行のインデックス作成と挿入中にパンダデータフレームの強制を防止


16

私はパンダのデータフレームの個々の行を操作していますが、行のインデックス付けと挿入を行う際に、強制に関する問題に遭遇しています。Pandasは常に、int / floatの混合型からall-float型に強制的に変換することを望んでいるようで、この動作に対する明確なコントロールはありません。

たとえば、以下はaas intおよびbasを使用した単純なデータフレームfloatです。

import pandas as pd
pd.__version__  # '0.25.2'

df = pd.DataFrame({'a': [1], 'b': [2.2]})
print(df)
#    a    b
# 0  1  2.2
print(df.dtypes)
# a      int64
# b    float64
# dtype: object

これは、1つの行にインデックスを付ける際の強制に関する問題です。

print(df.loc[0])
# a    1.0
# b    2.2
# Name: 0, dtype: float64
print(dict(df.loc[0]))
# {'a': 1.0, 'b': 2.2}

そして、1つの行を挿入する際の強制の問題を次に示します。

df.loc[1] = {'a': 5, 'b': 4.4}
print(df)
#      a    b
# 0  1.0  2.2
# 1  5.0  4.4
print(df.dtypes)
# a    float64
# b    float64
# dtype: object

どちらの場合aも、float型に強制的に変換されるのではなく、列を整数型のままにしておきます。


私はこれを見つけましたが、問題が効果的に解決されたかどうかはわかりませんでした。その間に私はあなたができると思います:df.loc[[0], df.columns]
Dani Mesejo '23 / 10/23


pd.DataFrameのようなサウンドは、インスタンス化での型混合をサポートしていませんか? pandas.pydata.org/pandas-docs/stable/reference/api/…dtype paramは単一のタイプのみをサポートします。 .read_[type]ただし、複数のdtypeをサポートしています...
Quentin

回答:


4

少し掘り下げた後、ここにいくつかのひどく醜い回避策があります。(より良い答えが受け入れられます。)

ここ見つかった奇妙な点は、非数値列が強制を停止することです。そのため、次のようにして1つの行をaにインデックス付けしますdict

dict(df.assign(_='').loc[0].drop('_', axis=0))
# {'a': 1, 'b': 2.2}

行を挿入するには、1つの行で新しいデータフレームを作成します。

df = df.append(pd.DataFrame({'a': 5, 'b': 4.4}, index=[1]))
print(df)
#    a    b
# 0  1  2.2
# 1  5  4.4

これらのトリックはどちらも大きなデータフレーム用に最適化されていないため、より適切な回答をいただければ幸いです。


あなたはいつでもポストアペンドを強制することができますdf['a'] = df.a.astype(mytype)...それはまだ汚いです、そしておそらく効率的ではありません。
Quentin

.astype()float-> integerでは危険です。に変更1.1しても問題はない1ので、実際に実行する前に、すべての値が「整数型」であることを確認する必要があります。おそらく以下との併用pd.to_numericが最適downcast='integer'
ALollz

2

問題の根本は

  1. パンダデータフレームのインデックス付けは、パンダシリーズを返します

次のことがわかります。

type(df.loc[0])
# pandas.core.series.Series

また、シリーズに含めることができるdtypeは1つだけです。あなたの場合は、int64またはfloat64です。

私の頭には2つの回避策があります。

print(df.loc[[0]])
# this will return a dataframe instead of series
# so the result will be
#    a    b
# 0  1  2.2

# but the dictionary is hard to read
print(dict(df.loc[[0]]))
# {'a': 0    1
# Name: a, dtype: int64, 'b': 0    2.2
# Name: b, dtype: float64}

または

print(df.astype(object).loc[0])
# this will change the type of value to object first and then print
# so the result will be
# a      1
# b    2.2
# Name: 0, dtype: object

print(dict(df.astype(object).loc[0]))
# in this way the dictionary is as expected
# {'a': 1, 'b': 2.2}
  1. 辞書をデータフレームに追加すると、最初に辞書がシリーズに変換されてから追加されます。(したがって、同じ問題が再び発生します)

https://github.com/pandas-dev/pandas/blob/master/pandas/core/frame.py#L6973

if isinstance(other, dict):
    other = Series(other)

だからあなたのウォークアラウンドは実際にはしっかりしたものであるか、そうでなければ私たちはできる:

df.append(pd.Series({'a': 5, 'b': 4.4}, dtype=object, name=1))
#    a    b
# 0  1  2.2
# 1  5  4.4

objectデータ型を使用するのは良い考えです!もう一つは、最初からオブジェクトのデータフレームを作成することです:df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
マイク・T

2

データフレームからデータを取得するか、データフレームにデータを追加し、データ型を同じに保つ必要がある場合は、必要なデータ型を認識しない他の内部構造への変換を避けてください。

すると、df.loc[0]に変換されますpd.Series

>>> type(df.loc[0])
<class 'pandas.core.series.Series'>

そして今、Series1つだけになりますdtype。したがって、に強制intfloatます。

代わりに、構造をpd.DataFrame

>>> type(df.loc[[0]])
<class 'pandas.core.frame.DataFrame'>

フレームとして必要な行を選択して、次に変換します dict

>>> df.loc[[0]].to_dict(orient='records')
[{'a': 1, 'b': 2.2}]

同様に、新しい行を追加するには、パンダpd.DataFrame.append関数を使用します。

>>> df = df.append([{'a': 5, 'b': 4.4}]) # NOTE: To append as a row, use []
   a    b
0  1  2.2
0  5  4.4

上記は型変換を引き起こしません、

>>> df.dtypes
a      int64
b    float64
dtype: object

うわー、2番目のコードブロックを3回読み取って取得する必要がありました。それは非常に微妙です。これは、私が過去に行ったことよりもはるかに優れています...最終データフレームをループして、正しいデータ型で値を再割り当てします(はい、私が行ったのは、実際にはスケーリングしない恐ろしいソリューションです)。
VanBantam

1
ああ。V @VanBantam
Vishnudev

1

わずかなデータ操作による別のアプローチ:

辞書(またはデータフレーム)のリストがあると仮定します

lod=[{'a': [1], 'b': [2.2]}, {'a': [5], 'b': [4.4]}]

ここで、各辞書は行を表します(2番目の辞書のリストに注意してください)。その後、次の方法でデータフレームを簡単に作成できます。

pd.concat([pd.DataFrame(dct) for dct in lod])
   a    b
0  1  2.2
0  5  4.4

列のタイプを維持します。連結を参照

したがって、データフレームと辞書のリストがある場合は、単に使用することができます

pd.concat([df] + [pd.DataFrame(dct) for dct in lod])

0

最初のケースでは、null許容整数データ型を使用できます。シリーズの選択は強制されずfloat、値はobjectコンテナーに配置されます。その後、辞書が適切に作成され、基になる値がとして保存されますnp.int64

df = pd.DataFrame({'a': [1], 'b': [2.2]})
df['a'] = df['a'].astype('Int64')

d = dict(df.loc[0])
#{'a': 1, 'b': 2.2}

type(d['a'])
#numpy.int64

あなたの構文では、これはほとんど 2番目のケースでも機能しますが、これはにアップキャストするobjectので、すばらしいことではありません。

df.loc[1] = {'a': 5, 'b': 4.4}
#   a    b
#0  1  2.2
#1  5  4.4

df.dtypes
#a     object
#b    float64
#dtype: object

ただし、最後に行を追加するための構文(RangeIndexを使用)に小さな変更を加えることができ、タイプが適切に処理されるようになりました。

df = pd.DataFrame({'a': [1], 'b': [2.2]})
df['a'] = df['a'].astype('Int64')

df.loc[df.shape[0], :] = [5, 4.4]
#   a    b
#0  1  2.2
#1  5  4.4

df.dtypes
#a      Int64
#b    float64
#dtype: object
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.