2017-02-25 6 views
1

Bitte könnte jemand erklären, warum, wenn ich einen einfachen heterogenen Datenrahmen mit Pandas erstellen, die Datentypen ändern, wenn ich auf jede Zeile einzeln zugreife.Pandas Warum ändert sich mein Spaltentyp?

z.B.

scene_df = pd.DataFrame({ 
    'magnitude': np.random.uniform(0.1, 0.3, (10,)), 
    'x-center': np.random.uniform(-1, 1, (10,)), 
    'y-center': np.random.uniform(-1, 1, (10,)), 
    'label': np.random.randint(2, size=(10,), dtype='u1')}) 

scene_df.dtypes 

druckt:

label   uint8 
magnitude float64 
x-center  float64 
y-center  float64 
dtype: object 

aber wenn ich iterieren Reihen:

[r['label'].dtype for i, r in scene_df.iterrows()] 

I float64 für Etiketten

[dtype('float64'), 
dtype('float64'), 
dtype('float64'), 
dtype('float64'), 
dtype('float64'), 
... 

bearbeiten erhalten:

zu beantworten, was ich damit vorhatte:

def square(mag, x, y): 
    wh = np.array([mag, mag]) 
    pos = np.array((x, y)) - wh/2 
    return plt.Rectangle(pos, *wh) 

def circle(mag, x, y): 
    return plt.Circle((x, y), mag) 

shape_fn_lookup = [square, circle] 

die als dieses hässliche Stück Code endet:

[shape_fn_lookup[int(s['label'])](
     *s[['magnitude', 'x-center', 'y-center']]) 
for i, s in scene_df.iterrows()] 

, die eine Reihe von Kreisen und Quadraten gibt, die ich vielleicht Grundstück:

[<matplotlib.patches.Circle at 0x7fcf3ea00d30>, 
<matplotlib.patches.Circle at 0x7fcf3ea00f60>, 
<matplotlib.patches.Rectangle at 0x7fcf3eb4da90>, 
<matplotlib.patches.Circle at 0x7fcf3eb4d908>, 
... 
] 

Selbst DataFrame.to_dict('records') erledigt diese Datentyp-Konvertierung:

type(scene_df.to_dict('records')[0]['label']) 

Antwort

1

Ich schlage vor, itertuples statt interrows verwenden, da iterrows eine Serie für jede Zeile zurückgibt, ist es nicht dtypes über die Konserve Zeilen (dtypes werden in Spalten für DataFrames beibehalten).

[type(r.label) for r in scene_df.itertuples()] 

Ausgang:

[numpy.uint8, 
numpy.uint8, 
numpy.uint8, 
numpy.uint8, 
numpy.uint8, 
numpy.uint8, 
numpy.uint8, 
numpy.uint8, 
numpy.uint8, 
numpy.uint8] 
+0

Ja, das ist viel schöner für meinen Anwendungsfall: '[shape_fn_lookup [s] (* Rest) für i, s, * rest in scene_df. ittuples()] ' –

1

Weil iterrows() eine Serie mit dem Index der Spaltennamen für jede Zeile zurückgibt.

Pandas.Series hat nur ein dtype, so wird es zu float64 downcasted werden:

In [163]: first_row = list(scene_df.iterrows())[0][1] 

In [164]: first_row 
Out[164]: 
label  0.000000 
magnitude 0.293681 
x-center -0.628142 
y-center -0.218315 
Name: 0, dtype: float64 # <--------- NOTE 

In [165]: type(first_row) 
Out[165]: pandas.core.series.Series 

In [158]: [(type(r), r.dtype) for i, r in scene_df.iterrows()] 
Out[158]: 
[(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64')), 
(pandas.core.series.Series, dtype('float64'))] 
+0

So gibt es einen vernünftigen Weg, um den Downcasting zu vermeiden? –

+0

Sie können 'int' als' float' darstellen, ohne irgendwelche Informationen zu verlieren, aber nicht umgekehrt. Wie ich oben sagte Pandas.Series muss einen einzigen 'dtype' haben – MaxU

+0

@FrankWilson, es hängt davon ab, was Sie in dieser Schleife tun möchten ... – MaxU

Verwandte Themen