Converteer kolommen naar string in Panda’s

Ik heb het volgende DataFrame van een SQL-query:

(Pdb) pp total_rows
     ColumnID  RespondentCount
0          -1                2
1  3030096843                1
2  3030096845                1

en ik wil het als volgt draaien:

total_data = total_rows.pivot_table(cols=['ColumnID'])
(Pdb) pp total_data
ColumnID         -1            3030096843   3030096845
RespondentCount            2            1            1
[1 rows x 3 columns]
total_rows.pivot_table(cols=['ColumnID']).to_dict('records')[0]
{3030096843: 1, 3030096845: 1, -1: 2}

maar ik wil ervoor zorgen dat de 303 kolommen worden gecast als strings in plaats van gehele getallen, zodat ik dit krijg:

{'3030096843': 1, '3030096845': 1, -1: 2}

Antwoord 1, autoriteit 100%

Een manier om naar string te converteren is door astype te gebruiken :

total_rows['ColumnID'] = total_rows['ColumnID'].astype(str)

Misschien zoekt u echter de to_json functie, die sleutels converteert naar geldige json (en dus uw sleutels naar strings):

In [11]: df = pd.DataFrame([['A', 2], ['A', 4], ['B', 6]])
In [12]: df.to_json()
Out[12]: '{"0":{"0":"A","1":"A","2":"B"},"1":{"0":2,"1":4,"2":6}}'
In [13]: df[0].to_json()
Out[13]: '{"0":"A","1":"A","2":"B"}'

Opmerking: u kunt een buffer/bestand doorgeven om dit op te slaan, samen met enkele andere opties…


Antwoord 2, autoriteit 18%

Als u ALLE kolommen naar tekenreeksen moet converteren, kunt u eenvoudig het volgende gebruiken:

df = df.astype(str)

Dit is handig als je alles behalve een paar kolommen nodig hebt om strings/objecten te zijn, ga dan terug en converteer de andere naar wat je nodig hebt (in dit geval een geheel getal):

 df[["D", "E"]] = df[["D", "E"]].astype(int) 

Antwoord 3, autoriteit 9%

pandas >= 1.0: Het is tijd om te stoppen met het gebruik van astype(str)!

Vóór panda’s 1.0 (nou ja, 0,25 eigenlijk) was dit de feitelijke manier om een ​​reeks/kolom als tekenreeks te declareren:

# pandas <= 0.25
# Note to pedants: specifying the type is unnecessary since pandas will 
# automagically infer the type as object
s = pd.Series(['a', 'b', 'c'], dtype=str)
s.dtype
# dtype('O')

Overweeg vanaf pandas 1.0 om "string" typ in plaats daarvan.

# pandas >= 1.0
s = pd.Series(['a', 'b', 'c'], dtype="string")
s.dtype
# StringDtype

Dit is waarom, zoals geciteerd door de documenten:

  1. U kunt per ongeluk een combinatie van tekenreeksen en niet-tekenreeksen opslaan in een object-dtype-array. Het is beter om een ​​speciaal dtype te hebben.

  2. object dtype breekt dtype-specifieke bewerkingen zoals DataFrame.select_dtypes(). Er is geen duidelijke manier om alleen tekst te selecteren
    terwijl niet-tekst maar wel object-dtype kolommen worden uitgesloten.

  3. Bij het lezen van code is de inhoud van een object dtype-array minder duidelijk dan 'string'.

Zie ook het gedeelte over Gedragsverschillen tussen "string" en object.

Extensietypen (geïntroduceerd in 0.24 en geformaliseerd in 1.0) zijn dichter bij panda’s dan numpy, wat goed is omdat numpy-types niet krachtig genoeg zijn. NumPy heeft bijvoorbeeld geen enkele manier om ontbrekende gegevens in integere gegevens weer te geven (sinds type(NaN) == float). Maar panda’s kunnen Nullable Integer-kolommen gebruiken.


Waarom zou ik ermee stoppen?

Per ongeluk dtypes vermengd
De eerste reden, zoals uiteengezet in de documenten, is dat u per ongeluk niet-tekstuele gegevens in objectkolommen kunt opslaan.

# pandas <= 0.25
pd.Series(['a', 'b', 1.23])   # whoops, this should have been "1.23"
0       a
1       b
2    1.23
dtype: object
pd.Series(['a', 'b', 1.23]).tolist()
# ['a', 'b', 1.23]   # oops, pandas was storing this as float all the time.
# pandas >= 1.0
pd.Series(['a', 'b', 1.23], dtype="string")
0       a
1       b
2    1.23
dtype: string
pd.Series(['a', 'b', 1.23], dtype="string").tolist()
# ['a', 'b', '1.23']   # it's a string and we just averted some potentially nasty bugs.

Uitdagend om strings en andere python-objecten te onderscheiden
Een ander voor de hand liggend voorbeeld is dat het moeilijker is om onderscheid te maken tussen “strings” en “objecten”. Objecten zijn in wezen het algemene type voor elk type dat geen vectoriseerbare-bewerkingen ondersteunt.

Overweeg,

# Setup
df = pd.DataFrame({'A': ['a', 'b', 'c'], 'B': [{}, [1, 2, 3], 123]})
df
   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

Tot aan panda 0.25 was er vrijwel geen manier om te onderscheiden dat “A” en “B” niet hetzelfde type gegevens hebben.

# pandas <= 0.25  
df.dtypes
A    object
B    object
dtype: object
df.select_dtypes(object)
   A          B
0  a         {}
1  b  [1, 2, 3]
2  c        123

Vanaf pandas 1.0 wordt dit een stuk eenvoudiger:

# pandas >= 1.0
# Convenience function I call to help illustrate my point.
df = df.convert_dtypes()
df.dtypes
A    string
B    object
dtype: object
df.select_dtypes("string")
   A
0  a
1  b
2  c

Leesbaarheid
Dit spreekt voor zich 😉


Ok, dus moet ik er nu mee stoppen?

…Nee. Op het moment van schrijven van dit antwoord (versie 1.1) zijn er geen prestatievoordelen, maar de documenten verwachten dat toekomstige verbeteringen de prestaties aanzienlijk zullen verbeteren en het geheugengebruik voor "string"-kolommen zullen verminderen in plaats van naar objecten. Dat gezegd hebbende, het is echter nooit te vroeg om goede gewoonten aan te leren!


Antwoord 4, autoriteit 7%

Hier is de andere, bijzonder handig om de meerdere kolommen te converteren naar een tekenreeks in plaats van slechts één kolom:

In [76]: import numpy as np
In [77]: import pandas as pd
In [78]: df = pd.DataFrame({
    ...:     'A': [20, 30.0, np.nan],
    ...:     'B': ["a45a", "a3", "b1"],
    ...:     'C': [10, 5, np.nan]})
    ...: 
In [79]: df.dtypes ## Current datatype
Out[79]: 
A    float64
B     object
C    float64
dtype: object
## Multiple columns string conversion
In [80]: df[["A", "C"]] = df[["A", "C"]].astype(str) 
In [81]: df.dtypes ## Updated datatype after string conversion
Out[81]: 
A    object
B    object
C    object
dtype: object

Antwoord 5

Ik gebruik meestal deze:

pd['Column'].map(str)

Antwoord 6

Er zijn vier manieren om kolommen naar tekenreeksen te converteren

1. astype(str)
df['column_name'] = df['column_name'].astype(str)
2. values.astype(str)
df['column_name'] = df['column_name'].values.astype(str)
3. map(str)
df['column_name'] = df['column_name'].map(str)
4. apply(str)
df['column_name'] = df['column_name'].apply(str)

Laten we de prestaties van elk type bekijken

#importing libraries
import numpy as np
import pandas as pd
import time
#creating four sample dataframes using dummy data
df1 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])
df2 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])
df3 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])
df4 = pd.DataFrame(np.random.randint(1, 1000, size =(10000000, 1)), columns =['A'])
#applying astype(str)
time1 = time.time()
df1['A'] = df1['A'].astype(str)
print('time taken for astype(str) : ' + str(time.time()-time1) + ' seconds')
#applying values.astype(str)
time2 = time.time()
df2['A'] = df2['A'].values.astype(str)
print('time taken for values.astype(str) : ' + str(time.time()-time2) + ' seconds')
#applying map(str)
time3 = time.time()
df3['A'] = df3['A'].map(str)
print('time taken for map(str) : ' + str(time.time()-time3) + ' seconds')
#applying apply(str)
time4 = time.time()
df4['A'] = df4['A'].apply(str)
print('time taken for apply(str) : ' + str(time.time()-time4) + ' seconds')

Uitvoer

time taken for astype(str): 5.472359895706177 seconds
time taken for values.astype(str): 6.5844292640686035 seconds
time taken for map(str): 2.3686647415161133 seconds
time taken for apply(str): 2.39758563041687 seconds

map(str) en apply(str) kosten minder tijd in vergelijking met de overige twee technieken


Antwoord 7

Het gebruik van .apply() met een lambda conversiefunctie werkt ook in dit geval:

total_rows['ColumnID'] = total_rows['ColumnID'].apply(lambda x: str(x))

Voor volledige dataframes kunt u .applymap() gebruiken.
(maar in ieder geval is waarschijnlijk .astype() sneller)

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4 + five =

Other episodes