Satırları indekslerken ve eklerken panda veri çerçevelerinin zorlanmasını önleyin


16

Panda veri çerçevelerinin tek tek satırlarıyla çalışıyorum, ancak satırları indekslerken ve eklerken zorlama sorunları üzerinde tökezliyorum. Pandalar her zaman karışık bir int / float'tan tüm-float türlerine zorlamak istiyor gibi görünüyor ve bu davranış üzerinde belirgin kontroller göremiyorum.

Örneğin, aas intve bas ile basit bir veri çerçevesi 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

İşte bir satırı dizine eklerken bir zorlama sorunu:

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}

Ve bir satır eklerken bir baskı sorunu:

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

Her iki durumda da, abir kayan nokta türüne zorlanmak yerine sütunun bir tamsayı türü olarak kalmasını istiyorum .


Bulduğum bu ancak etkili bir mesele çözüldü eğer buldum olamazdı. Bu arada yapabilirim:df.loc[[0], df.columns]
Dani Mesejo


Pd.DataFrame, örneklemede tür karıştırmayı desteklemiyor mu? pandas.pydata.org/pandas-docs/stable/reference/api/… dtype param yalnızca tek bir türü destekler. .read_[type]olsa da birden fazla tip destekler ...
Quentin

Yanıtlar:


4

Bazı kazmalardan sonra, burada bazı çirkin geçici çözümler var. (Daha iyi bir cevap kabul edilecektir.)

Burada bulunan bir tuhaflık , sayısal olmayan sütunların zorlamayı durdurmasıdır, bu nedenle bir satırı bir dizine nasıl endeksleyeceğiniz aşağıda açıklanmıştır dict:

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

Ve bir satır eklemek, bir satırla yeni bir veri çerçevesi oluşturarak yapılabilir:

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

Bu hilelerin her ikisi de büyük veri çerçeveleri için optimize edilmemiştir, bu yüzden daha iyi bir cevap için çok minnettar olurum!


Her zaman sadece post apper zorlayabilirsiniz df['a'] = df.a.astype(mytype)... Yine de kirli ve muhtemelen verimli değil.
Quentin

.astype()şamandıra için tehlikelidir -> tamsayı; o değişen hiçbir sorunu var 1.1için 1gerçekten emin tüm değerleri bunu yapmadan önce 'tamsayı benzeri' olduğu olmaları gerekir, böylece. Muhtemelen en iyi kullanımı pd.to_numericiledowncast='integer'
ALollz

2

Sorunun kökü şudur:

  1. Pandalar veri çerçevesinin endekslenmesi bir panda serisi döndürür

Bunu görebiliyoruz:

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

Ve bir serinin sadece bir dtype'i olabilir, sizin durumunuzda int64 veya float64 olabilir.

Kafama iki geçici çözüm geliyor:

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}

veya

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. Eğer bir dataframe için bir sözlük eklemek olduğunda, bir sözlüğe dönüştürür Serisi ilk ve daha sonra ekleme. (Yani aynı problem tekrar olur)

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

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

Bu yüzden yürüyüş yolunuz aslında sağlam bir yer, yoksa yapabiliriz:

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

objectVeri türlerini kullanmak için iyi fikir ! Bir diğeri başından itibaren bir DataFrame nesnesi oluşturmaktır:df = pd.DataFrame({'a': [1], 'b': [2.2]}, dtype=object)
Mike T

2

Veri çerçevesinden veri alırken veya veri çerçevesine veri eklerken ve veri türünü aynı tutmanız gerektiğinde, gereken veri türlerinin farkında olmayan diğer iç yapılara dönüştürmekten kaçının.

Bunu yaptığınızda df.loc[0]o kadar dönüştürür pd.Series,

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

Ve şimdi, Seriessadece bir tane olacak dtype. Böylece zorlamak intiçin float.

Bunun yerine olarak yapısını korumak pd.DataFrame,

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

Çerçeve olarak gereken satırı seçin ve ardından dict

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

Benzer şekilde, yeni bir satır eklemek için Pandalar pd.DataFrame.appendişlevini kullan ,

>>> 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

Yukarıdaki tür dönüştürmeye neden olmaz,

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

Wow, ikinci kod bloğunu üç kez okumak zorunda kaldı. Bu çok ince. Bu geçmişte yaptığımdan çok daha iyi ... son veri çerçevesinde döngü yapın ve değerleri doğru veri türüyle yeniden atayın (evet yaptığım gerçekten ölçeklenmeyen korkunç bir çözüm.).
VanBantam

1
Ah. Glad it helped 😊 @VanBantam
Vishnudev

1

Hafif veri manipülasyonları ile farklı bir yaklaşım:

Sözlüklerin (veya veri çerçevelerinin) bir listesine sahip olduğunuzu varsayın

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

burada her sözlük bir satırı temsil eder (ikinci sözlükteki listelere dikkat edin). Daha sonra kolayca bir veri çerçevesi oluşturabilirsiniz:

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

ve sütun türlerini korursunuz. Bkz concat

Bir veri çerçeveniz ve bir dikte listeniz varsa,

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

0

İlk durumda, null olabilecek tamsayı veri türüyle çalışabilirsiniz . Seri seçimi zorlanmaz floatve değerler bir objectkaba yerleştirilir . Sözlük daha sonra, temel değer a olarak saklanacak şekilde düzgün bir şekilde oluşturulur 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

Sözdiziminizle, bu neredeyse ikinci durum için de işe yarıyor, ancak bu objectharika değil:

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

Ancak, sonunda bir satır eklemek için sözdiziminde küçük bir değişiklik yapabiliriz (RangeIndex ile) ve şimdi türler düzgün şekilde ele alınır.

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.