DataFrame内の文字列、ただしdtypeはオブジェクト


96

選択した列のすべての項目が文字列であるにもかかわらず、明示的に変換した後でも、Pandasがオブジェクトを持っていると教えてくれるのはなぜですか。

これは私のデータフレームです:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 56992 entries, 0 to 56991
Data columns (total 7 columns):
id            56992  non-null values
attr1         56992  non-null values
attr2         56992  non-null values
attr3         56992  non-null values
attr4         56992  non-null values
attr5         56992  non-null values
attr6         56992  non-null values
dtypes: int64(2), object(5)

それらの5つですdtype object。これらのオブジェクトを明示的に文字列に変換します。

for c in df.columns:
    if df[c].dtype == object:
        print "convert ", df[c].name, " to string"
        df[c] = df[c].astype(str)

その後、df["attr2"]まだ持っているdtype objectものの、type(df["attr2"].ix[0]明らかにstr正しいいます、。

パンダは区別しint64float64object。ない場合の背後にあるロジックは何dtype strですか?なぜでstrカバーされていobjectますか?


すべての「is」文字列であるにもかかわらず「オブジェクトタイプ」が原因で結合が失敗するため、ここに来ました
モニカヘドネック

回答:


145

dtypeオブジェクトはNumPyに由来し、ndarray内の要素のタイプを記述します。ndarray内のすべての要素は、バイト単位で同じサイズでなければなりません。int64およびfloat64の場合、これらは8バイトです。ただし、文字列の場合、文字列の長さは固定されていません。そのため、文字列のバイトをndarrayに直接保存する代わりに、Pandasはオブジェクトへのポインタを保存するオブジェクトndarrayを使用します。これは、この種類のndarrayのdtypeがオブジェクトであるためです。

次に例を示します。

  • int64配列には4つのint64値が含まれています。
  • オブジェクト配列には、3つの文字列オブジェクトへの4つのポインタが含まれています。

ここに画像の説明を入力してください


3
ただし、「オブジェクト」タイプの列があると、DataFrameの読み取り/書き込み操作のパフォーマンスに大きな影響があることに注意してください
erwanp

どういうわけか、文字列として返されるデータ型を取得できますか?私は常にtype(df ["column"]。iloc [0])を使用できることを知っていますが、それがナンである場合があります
user1953366 '28

7

受け入れられた答えは良いです。ドキュメント参照する答えを提供したかっただけです。ドキュメントは言う:

Pandasは文字列の格納にオブジェクトdtypeを使用します。

冒頭のコメントで「心配しないで、こうなるはず」とあります。(受け入れられた答えは「なぜ」を説明する素晴らしい仕事をしましたが、文字列は可変長です)

ただし、文字列の場合、文字列の長さは固定されていません。


渡すために、すべての列をscipyまたはsklearn astype(str)に変換する必要があるのはなぜですか?最初はすべての列にそれを適用できるはずです。
Tinkinc

わかりません。@Tinkinc 列を文字列に変換しないとどうなりますか?そして、この答えは、すべての列をに変換するエレガントな方法のように思えますがastype(str)、文字列変換が必要かどうかはまだ疑問です
The Red Pea

Iカントfillna(0)私のデータフレームステー(1、ナン)内のすべてのオブジェクトの代わりに、(1,0)
Tinkinc

申し訳ありませんが、@ Tinkincまだわかりません。手助けしたいのですが、あなたの問題はスタックオーバーフローのコメントよりも複雑に聞こえます。質問するか、チャットに参加することを検討してください。(あなたを招待しただけ)
The Red Pea '21

5

@HYRYの答えは素晴らしいです。もう少しコンテキストを提供したいだけです。

配列は、連続した固定サイズのメモリブロックとしてデータを格納しました。これらのプロパティを組み合わせることにより、データアクセスのためにアレイが高速になります。たとえば、コンピューターが32ビット整数の配列をどのように格納するかを検討します[3,0,1]

ここに画像の説明を入力してください

配列の3番目の要素をフェッチするようにコンピューターに要求した場合、それは最初から始まり、次に64ビットをジャンプして3番目の要素に到達します。ジャンプするビット数を正確に知ることで、配列が高速になります

次に、文字列のシーケンスについて考えます['hello', 'i', 'am', 'a', 'banana']。文字列はサイズが異なるオブジェクトであるため、連続したメモリブロックに保存しようとすると、次のようになります。

ここに画像の説明を入力してください

これで、コンピューターにはランダムに要求された要素にアクセスするための高速な方法がありません。これを克服する鍵は、ポインタを使用することです。基本的に、各文字列をランダムなメモリ位置に格納し、各文字列のメモリアドレスで配列を埋めます。(メモリアドレスは単なる整数です。)さて、今は次のようになります

ここに画像の説明を入力してください

これで、以前と同じように3番目の要素をフェッチするようにコンピューターに要求すると、64ビットにジャンプして(メモリアドレスが32ビット整数であると仮定)、文字列をフェッチするための1つの追加手順を実行できます。

NumPyの課題は、ポインターが実際に文字列を指しているという保証がないことです。これが、dtypeを「オブジェクト」として報告する理由です。

私がこれを最初に議論した自分のブログ記事を恥知らずにプラグインするつもりです。


素敵なwritten..Thanks
TEDD

1

バージョン1.0.0(2020年1月)から、pandasは実験的な機能として導入され、からまでの文字列型のファーストクラスのサポートを提供しpandas.StringDtypeます。

引き続きobjectデフォルトで表示されますが、新しいタイプは、dtypeofを指定するpd.StringDtypeか、単に指定することで使用できます'string'

>>> pd.Series(['abc', None, 'def'])
0     abc
1    None
2     def
dtype: object
>>> pd.Series(['abc', None, 'def'], dtype=pd.StringDtype())
0     abc
1    <NA>
2     def
dtype: string
>>> pd.Series(['abc', None, 'def']).astype('string')
0     abc
1    <NA>
2     def
dtype: string

2
これは使用しないでください。彼らが述べたように、The implementation may change without warning.それは新しいアップデートがあなたの古いプログラムを壊すことを意味します。
NoName

1
まあ、それはあなたがそれを何のために使うつもりかによる。継続的なパッケージのアップグレードが必要であり、APIの破損により許容できないメンテナンスの負担が発生する本番稼働システムで使用する場合は、「実験的」という言葉に細心の注意を払ってください。ただし、パンダを使用して探索的に実行している場合はライフタイムが1日を増やさないスクリプトの分析では、それらの懸念はほとんど意味をなさないはずです。
fuglede

Pandas 1.1以降、APIは安定しているようですすべてのdtypeをStringDtypeに変換できるようになりました
D3f0
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.