Python save CSV without changing ID to an integer - python

I have a df in Python with an ID column - those IDs can be a mix of numbers and letters, or solely numbers. Eg:
ID
00028D9D1
00027B98F
000275457
When I save this df out, using pandas to_csv I see in the resulting csv file when I share with others (or open up myself), I see the IDs that contain letters are maintained as is / treated as text, but the IDs that are solely numbers are treated as integers, and automatically formatted that way. For example, I would see this in my csv file after saving:
ID
00028D9D1
00027B98F
275457
Is there any way to disable this automatic treatment of integers, leading to different formatting? The dtype of this column does say it is an object so I assumed it would save in the same format for all values.

According to RFC 4180, CSV files do not contain any type information, so it is solely the responsibility of the application to correctly interpret the contents of the file. From what I read in your question,
I have a df in Python with an ID column - those IDs can be a mix of numbers and letters, or solely numbers.
and as far as I interpret your specification, it you'll have something like this:
input.csv
ID
00028D9D1
00027B98F
000275457
script
import pandas as pd
df = pd.read_csv('input.csv')
print(df)
print(df['ID'].dtype)
df.to_csv('output.csv', index=False)
console output
ID
0 00028D9D1
1 00027B98F
2 000275457
object
output.csv
ID
00028D9D1
00027B98F
000275457
In other words, use the right tool to "open up" the CSV file you create.
As I observe on Windows, spreadsheet applications like Excel or Open/Libre office register themselves with the .csv file extension, so just opening a CSV will lead to a very generic interpretation of data: cells that can be converted into a number without errors are treated as integer cells, regardless of their column.
One application that lets you view the actual contents of a text file is Windows Notepad, for example, but as a programmer you probably know better alternatives.

Related

CSV cannot be interpreted by numeric values

(This is a mix between code and 'user' issue, but since i suspect the issue is code, i opted to post in StackOverflow instead of SuperUser Exchange).
I generated a .csv file with pandas.DataFrame.to_csv() method. This file consists in 2 columns: one is a label (text) and another is a numeric value called accuracy (float). The delimiter used to separate columns is comma (,) and all float values are stored with dot ponctuation like this: 0.9438245862
Even saving this column as float, Excel and Google Sheets infer its type as text. And when i try to format this column as number, they ignore "0." and return a very high value instead of decimals like:
(text) 0.9438245862 => (number) 9438245862,00
I double-checked my .csv file reimporting it again with pandas.read_csv() and printing dataframe.dtypes and the column is imported as float succesfully.
I'd thank for some guidance on what am i missing.
Thanks,
By itself, the csv file should be correct. Both you and Pandas know what delimiter and floating point format are. But Excel might not agree with you, depending on your locale. A simple way to make sure is to write a tiny Excel sheet containing on first row one text value and one floating point one. You then export the file as csv and control what delimiter and floating point formats are.
AFAIK, it is much more easy to change your Python code to follow what your Excel expects that trying to explain Excel that the format of CSV files can vary...
I know that you can change the delimiter and floating point format in the current locale in a Windows system. Simply it is a global setting...
A short example of data would be most useful here. Otherwise we have no idea what you're actually writing/reading. But I'll hazard a guess based on the information you've provided.
The pandas dataframe will have column names. These column names will be text. Unless you tell Excel/Sheets to use the first row as the column name, it will have to treat the column as text. If this isn't the case, could you perhaps save the head of the dataframe to a csv, check it in a text editor, and see how Excel/Sheets imports it. Then include those five rows and two columns in your follow up.
The coding is not necessarily the issue here, but a combination of various factors. I am assuming that your computer is not using the dot character as a decimal separator, due to your language settings (for example, French, Dutch, etc). Instead your computer (and thus also Excel) is likely using a comma as a decimal separator.
If you want to open the data of your analysis / work later with Excel with little to no changes, you can either opt to change how Excel works or how you store the data to a CSV file.
Choosing the later, you can specify the decimal character for the df.to_csv method. It has the "decimal" keyword. You should then also remember that you have to change the decimal character during the importing of your data (if you want to read again the data).
Continuing with the approach of adopting your Python code, you can use the following code snippets to change how you write the dataframe to a csv
import pandas as pd
... some transformations here ...
df.to_csv('myfile.csv', decimal=',')
If you, then, want to read that output file back in with Python (using Pandas), you can use the following:
import pandas as pd
df = pd.read_csv('myfile.csv', decimal=',')

How to treat date as plain text with pandas?

I use pandas to read a .csv file, then save it as .xls file. Code as following:
import pandas as pd
df = pd.read_csv('filename.csv', encoding='GB18030')
print(df)
df.to_excel('filename.xls')
There's a column contains date like '2020/7/12', it's looks like pandas recognized it as date and output it to '2020-07-12' automatically. I don't want to format this column, or any other columns like this, I'd like to keep all data remain the same as plain text.
This convertion happens at read_csv(), because print(df) already outputs YYYY-MM-DD, before to_excel().
I tried use df.info() to check the data type of that column, the data type is object. Then I added argument dtype=pd.StringDtype() to read_csv() and it doesn't help.
The file contains Chinese characters so I set encoding to GB18030, don't know if this matters.
My experience concerning pd.read_csv indicates that:
Only columns convertible to int or float are by default
converted to respective types.
"Date-like" strings are still read as strings (the column type in
the resulting DataFrame is actually object).
If you want read_csv to convert such column to datetime type, you
should pass parse_dates parameter, specifying a list of columns to be
parsed as dates. Since you didn't do it, no source column should be
converted to datetime type.
To check this detail, after you read file, run file.info() and check
the type of the column in question.
So if respective Excel file column is of Date type, then probably
this conversion is caused by to_excel.
And one more remark concerning variable names:
What you have read using read_csv is a DataFrame, not a file.
Actual file is the source object, from which you read the content,
but here you passed only file name.
So don't use names like file to name the resulting DataFrame, as this
is misleading. It is much better to use e.g. df.
Edit following a comment as of 05:58Z
To check in full extent what you wrote in your comment, I created
the following CSV file:
DateBougth,Id,Value
2020/7/12,1031,500.15
2020/8/18,1032,700.40
2020/10/16,1033,452.17
I ran: df = pd.read_csv('Input.csv') and then print(df), getting:
DateBougth Id Value
0 2020/7/12 1031 500.15
1 2020/8/18 1032 700.40
2 2020/10/16 1033 452.17
So, at the Pandas level, no format conversion occurred in DateBougth
column. Both remaining columns, contain numeric content, so they were
silently converted to int64 and float64, but DateBought remained as object.
Then I saved this df to an Excel file, running: df.to_excel('Output.xls')
and opened it with Excel. The content is:
So neither at the Excel level any data type conversion took place.
To see the actual data type of B2 cell (the first DateBougth),
I clicked on this cell and pressed Ctrl-1, to display cell formatting.
The format is General (not Date), just as I expected.
Maybe you have some outdated version of software?
I use Python v. 3.8.2 and Pandas v. 1.0.3.
Another detail to check: Look at your code after pd.read_csv.
Maybe somewhere you put instruction like df.DateBought = pd.to_datetime(df.DateBought) (explicit type conversion)?
Or at least format conversion. Note that in my environment
there was absolutely no change in the format of DateBought column.
Problem solved. I double checked my .csv file, opened it with notepad, the data is 2020-07-12, which displays as 2020/7/12 on Office. Turns out that Office reformatted date to yyyy/m/d (based on your region). I'm developing a tool to process and import data to DB for my company, we did these work manually by copy and paste so no one noticed this issue. Thanks to #Valdi_Bo for his investigate and patience.

Plus sign lost when reading excel sheet with pandas

I have a list of phone numbers in an excel sheet, along with other information related to the phone numbers. The phone numbers can be from different countries, so they start with a + sign, followed by a country code (for example +1055592947). The string is stored in excel as '+1055592947 to make it appear as a string.
However, when I read the excel file, the plus sign is lost. How can I prevent this from happening?
df = pd.read_excel(data_file_location, index_col=0)
You can define that it is a string when reading the file as follows:
pd.read_excel('Book.xlsx',dtype = {'colname': str})
Refer documentation to handle the datatypes here

Pandas to_csv now not writing values correctly

I'm using to csv to save a datframe which looks like this:
PredictionIdx CustomerInterest
0 fe789a06f3 0.654059
1 6238f6b829 0.654269
2 b0e1883ce5 0.666289
3 85e07cdd04 0.664172
in which I've a value '0e15826235' in first column.I'm writing this dataframe to csv using pandas to_csv() . But when I open this csv in google excel or libreoffice it shows 0E in excel and 0 in libreoffice. It is giving me problem during submission in kaggle. But one point to note here is that when I'm reading the same csv using pandas read_csv it shows the above value correctly in dataframe.
As noted in the first comment, the error is resulting from your choice of editor. Many editors will use some version of scientific notation that reads an e (in specific places like the second character) as an indicator of an exponent. Excel, for instance, will read it as a "base X raised to the power Y" where X are the numbers before the e and Y are the numbers after the e. This is a brief description of Excel's scientific notation.
This does not happen in the other cell entries because there appear to be other string-like characters. Excel, Libre, and possibly Google attempt to interpret what the entry is, rather than taking it literally.
In your question you write '0e15826235' with single quotes, indicating that it might be a string, but this might be something to make sure of when writing out the values to a file -- Excel and the rest might not know this is meant to be a string literal.
In general, check for the format of the value and consider what your eventual editor might "think" it is when it opens. For Excel specifically, a single quote character at the start of the string will force Excel to read it as a string. See this answer.
For me code below works correctly with google spreadsheets:
import pandas as pd
df = pd.DataFrame({'PredictionIdx': ['fe789a06f3',
'6238f6b829',
'b0e1883ce5',
'85e07cdd04'],
'CustomerInterest': [0.654059,
0.654269,
0.666289,
0.664172]})
df.to_csv('./test.csv', index = None)
Also csv is very simple text format, it doesn't hold any information about data types.
So you could use df.to_excel() as Nihal suggested, or adjust column type settings in your favourite spreadsheets viewer.

Conforming dataframe dtypes between read_excel() and to_excel()

I am reading a dataframe from an excel file (specifically xlsx) that contains rows and columns about vendors, including zip_code and tax_id columns. When the numbers are read IN and then I cast the column astype(unicode), tax_id 123456789 becomes 123456789.0.
I don't want to cast to int and then mod / truncate (because, in the case of zip_code and theoretically tax_id too, '07443' will get converted to 7443 which isn't good). I just want to clip the '.0' and have to_excel() treat the whole column as strings (unicodes, more specifically).
Sometimes read_excel() correctly identifies a number as a string (07443 is a good example, actually). In the case of the tax_id though, it's clearly coming in as a number of some kind (even though until I astype(unicode) it, the '.0' doesn't show up.
One thing I've tried is df.astype(unicode).replace(".0",""), but this doesn't seem to be getting it done. The resulting df still shows 123456789.0.
I'm not sure how to illustrate this with code because you need an Excel file, which I can't attach. I'm open to suggestions as to how to clarify my question if necessary.
Thank you!
Hmm, one thing that appear to be working (which I suppose speaks to the awesomeness of pandas):
df['tax_id'].replace(".0$","",regex=True)

Categories

Resources