46

I have a dataframe

df = pd.DataFrame([
        ['2', '3', 'nan'],
        ['0', '1', '4'],
        ['5', 'nan', '7']
    ])

print df

   0    1    2
0  2    3  nan
1  0    1    4
2  5  nan    7

I want to convert these strings to numbers and sum the columns and convert back to strings.

Using astype(float) seems to get me to the number part. Then summing is easy with sum(). Then back to strings should be easy too with astype(str)

df.astype(float).sum().astype(str)

0     7.0
1     4.0
2    11.0
dtype: object

That's almost what I wanted. I wanted the string version of integers. But floats have decimals. How do I get rid of them?

I want this

0     7
1     4
2    11
dtype: object

7 Answers 7

44

For pandas >= 1.0:

<NA> type was introduced for 'Int64'. You can now do this:

df['your_column'].astype('Int64').astype('str')

And it will properly convert 1.0 to 1.


Alternative:

If you do not want to change the display options of all pandas, @maxymoo solution does, you can use apply:

df['your_column'].apply(lambda x: f'{x:.0f}')
Sign up to request clarification or add additional context in comments.

1 Comment

Great! astype('Int64').astype('str') worked for converting individual columns. Since it's true reformatting of data type, I'd prefer this over changing display option.
32

Converting to int (i.e. with .astype(int).astype(str)) won't work if your column contains nulls; it's often a better idea to use string formatting to explicitly specify the format of your string column; (you can set this in pd.options):

>>> pd.options.display.float_format = '{:,.0f}'.format
>>> df.astype(float).sum()
0     7
1     4
2    11
dtype: float64

4 Comments

I believe the correct method for a dataframe is applymap, not map.
@IanS yes you're right, I used map because because I summed the columns before doing the formatting
why does .format() convert to object here? It is implicitly converting from float to string?
@ℕʘʘḆḽḘ I guess the format is used in the conversion. Maybe in the series formatter as mentioned in the documentation.
25

Add a astype(int) in the mix:

df.astype(float).sum().astype(int).astype(str)

0     7
1     4
2    11
dtype: object

Demonstration of example with empty cells. This was not a requirement from the OP but to satisfy the detractors

df = pd.DataFrame([
        ['2', '3', 'nan', None],
        [None, None, None, None],
        ['0', '1', '4', None],
        ['5', 'nan', '7', None]
    ])

df

      0     1     2     3
0     2     3   nan  None
1  None  None  None  None
2     0     1     4  None
3     5   nan     7  None

Then

df.astype(float).sum().astype(int).astype(str)

0     7
1     4
2    11
3     0
dtype: object

Because the OP didn't specify what they'd like to happen when a column was all missing, presenting zero is a reasonable option.

However, we could also drop those columns

df.dropna(1, 'all').astype(float).sum().astype(int).astype(str)

0     7
1     4
2    11
dtype: object

4 Comments

I believe you were just now the victim of some strategic downvoting. +1 to counter that and because your answer came way before the other.
This won't handle a row with all missing values.
@dlm sure it does.. I just ran example. If you have a specific case, why don't you ask a question to clear it up. This answer satisfied the requirements of the OP. If you didn't find it useful, you don't have to up-vote. But a down-vote is a declaration that the answer is not useful when it clearly was, as it solved the problem presented.
Wrong solution, using sum changes the final result
3

Add astype(int) right before conversion to a string:

print (df.astype(float).sum().astype(int).astype(str))

Generates the desired result.

Comments

3

The above didnt work for me so im going to add my solution

Convert to a string and strip away the .0:

db['a] = db['a'].astype(str).str.rstrip('.0')

1 Comment

if it ends with 0, the 0 is also removed. Example: input: 1230.0 expected output: 1230 real output: 123
1

based on toto_tico's solution - alternative , minor changes to avoid null case become nan

df['your_column'].apply(lambda x: f'{x:.0f}' if not pd.isnull(x) else '')

Comments

0

The above solutions, when converting to string, will turn NaN into a string as well. To get around that and retain NaN, use:

c = ...  # your column
np.where(
    df[c].isnull(), np.nan,
    df[c].apply('{:.0f}'.format)
)

Retaining NaN allows you to do stuff like convert a nullable column of integers like 19991231, 20000101, np.nan, 20000102 into date time without triggering date parsing errors.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.