Hi I have the following dataframe:
>df1
code item01 item02 item03 item04 item05
0 1111 nan nan nan nan 440
1 1111 nan nan nan 650 nan
2 1111 nan nan nan nan nan
3 1111 nan nan nan nan nan
4 1111 32 nan nan nan nan
5 1111 nan nan nan nan nan
6 1111 nan nan nan nan nan
7 1111 nan nan nan nan nan
8 1111 nan nan nan nan nan
9 1111 nan nan nan nan nan
10 1111 nan nan nan nan nan
11 2222 20 nan nan nan nan
12 2222 nan nan nan nan nan
13 2222 nan nan nan 5 nan
14 2222 nan 7 nan nan nan
15 2222 nan nan nan nan nan
16 2222 nan nan nan nan nan
How can I merge using 'code' column within the dataframe to get df2 without for loop or iterrows().
>df2
code item01 item02 item03 item04 item05
0 1111 32 130 nan 650 440
1 2222 20 7 nan 5 nan
You can use:
If max one non value in column per group only:
df.groupby('code').first()
If possible multiple values - more general solution:
cols = df.columns.difference(['code'])
df = df.groupby('code')[cols]
.apply(lambda x: x.apply(lambda y: pd.Series(y.dropna().values)))
print (df)
item01 item02 item03 item04 item05
code
1111 0 32.0 NaN NaN 650.0 440.0
2222 0 20.0 7.0 NaN 5.0 NaN
You can simply use a groupby:
df1.groupby('code').max().reset_index(drop=True,inplace=True)
Be careful, if there are many values for an item with the same code, here you will keep the biggest one.
The reset_index is only used to get Output DataFrame in the same format.
Related
I want to get the number of consecutive NaN's in each column and if the maximum of these consecutive NaN's are smaller than, let's say 3, then I want to fill those with the first prior non-NaN value, and if it's more than 3, then remove the whole column. Here's a small part of my dataset to work with.
>>> df
113550 100285 112283 101668 114157 100019
0 NaN 27.60000 NaN NaN NaN NaN
1 NaN 27.50000 NaN NaN 36.25000 NaN
2 NaN 27.25000 NaN NaN 36.25000 22.5
3 NaN 27.90000 NaN NaN 47.33333 22.5
4 NaN 28.00000 NaN NaN NaN NaN
5 NaN 27.66667 NaN NaN 36.25000 NaN
6 NaN 26.41667 NaN NaN 40.00000 NaN
7 NaN NaN NaN NaN 36.25000 NaN
8 NaN 27.87500 NaN NaN 41.87500 22.5
9 NaN 27.85000 NaN NaN 46.66667 22.5
10 NaN 27.45000 NaN NaN 40.00000 22.5
11 NaN 27.45000 NaN NaN 41.75000 NaN
12 NaN 26.43750 NaN NaN 40.00000 NaN
13 NaN 26.50000 NaN NaN 41.75000 NaN
14 NaN 26.60000 NaN NaN 41.75000 22.5
15 NaN 26.60000 NaN NaN 41.75000 22.5
16 NaN 24.62500 NaN NaN 39.83333 NaN
17 NaN 24.60000 NaN NaN 41.75000 NaN
18 NaN 24.50000 NaN NaN NaN 22.5
19 NaN 23.62500 NaN NaN 41.87500 NaN
From Identifying consecutive NaNs with Pandas, you can use:
consecutive_nans = lambda x: x.isna().groupby(x.notna().cumsum()).sum().max()
out = df[df.apply(consecutive_nans).loc[lambda x: x <= 3].index].ffill().bfill()
print(out)
# Output
100285 114157
0 27.60000 36.25000
1 27.50000 36.25000
2 27.25000 36.25000
3 27.90000 47.33333
4 28.00000 47.33333
5 27.66667 36.25000
6 26.41667 40.00000
7 26.41667 36.25000
8 27.87500 41.87500
9 27.85000 46.66667
10 27.45000 40.00000
11 27.45000 41.75000
12 26.43750 40.00000
13 26.50000 41.75000
14 26.60000 41.75000
15 26.60000 41.75000
16 24.62500 39.83333
17 24.60000 41.75000
18 24.50000 41.75000
19 23.62500 41.87500
I need to get ad dataframe from files built up like this:
MANDT#|#BWKEY#|#BUKRS#|#BWMOD#|#XBKNG#|#MLBWA#|#MLBWV#|#XVKBW
150#|#2000#|#1001#|##|##|##|##|#
150#|#2001#|#1001#|##|##|##|##|#
150#|#2002#|#1001#|##|##|##|##|#
150#|#4000#|#1000#|##|##|##|##|#
150#|#4001#|#1000#|##|##|##|##|#
150#|#4002#|#1000#|##|##|##|##|#
150#|#4003#|#1000#|##|##|##|##|#
150#|#4005#|#1000#|##|##|##|##|#
What would be the right python regex for separation (#|#) in read_csv?
ThankĀ“s!
Escape the vertical bar, which has a special meaning, with \|
df = pd.read_clipboard(sep=r'#\|#')
print(df)
MANDT BWKEY BUKRS BWMOD XBKNG MLBWA MLBWV XVKBW
0 150 2000 1001 NaN NaN NaN NaN NaN
1 150 2001 1001 NaN NaN NaN NaN NaN
2 150 2002 1001 NaN NaN NaN NaN NaN
3 150 4000 1000 NaN NaN NaN NaN NaN
4 150 4001 1000 NaN NaN NaN NaN NaN
5 150 4002 1000 NaN NaN NaN NaN NaN
6 150 4003 1000 NaN NaN NaN NaN NaN
7 150 4005 1000 NaN NaN NaN NaN NaN
I want to divide a DataFrame by one of its columns (a Series), they both share the index, so I expect the result has the shape of the original DataFrame.
This code shows what I did:
import numpy as np
import pandas as pd
cols = ['A', 'B', 'C', 'D']
ix = range(10)
df = pd.DataFrame(index=ix, columns=cols, data=np.random.randint(0, 100, size=(10, 4)))
print(df / df['A'])
The result is something like that:
0 1 2 3 4 5 6 7 8 9 A B C D
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
But I expect something like that:
A B C D
0 1 .. .. ..
1 1 .. .. ..
2 1 .. .. ..
3 1 .. .. ..
4 1 .. .. ..
5 1 .. .. ..
6 1 .. .. ..
7 1 .. .. ..
8 1 .. .. ..
9 89 94 14 44
Thanks in advance.
use div with axis=0, it's aligning on the columns hence you get the 0...9 and original columns, you should use div and explicitly pass axis=0 so it broadcasts along the index:
In [58]:
, axis=0
df.div(df['A'], axis=0)
Out[58]:
A B C D
0 1.0 0.818182 1.681818 0.431818
1 1.0 1.562500 0.625000 1.468750
2 1.0 17.000000 5.400000 2.800000
3 1.0 9.428571 13.857143 8.285714
4 1.0 0.256098 0.085366 1.146341
5 1.0 27.000000 21.500000 7.500000
6 1.0 0.444444 1.236111 1.041667
7 1.0 0.268293 0.048780 1.146341
8 1.0 0.505051 0.434343 0.101010
9 1.0 0.673684 0.378947 0.873684
You can see a related question: What does the term "broadcasting" mean in Pandas documentation? that illustrates the broadcasting rules
I have a dataframe that looks like this
dg:
thing1 thing2 thing3 thing4 thing5 thing6 thing7 ID
NAN 1 NAN NAN NAN NAN NAN 222
NAN NAN 3 NAN NAN NAN NAN 222
NAN NAN NAN 2 NAN NAN NAN 222
3 NAN NAN NAN NAN NAN 3 222
NAN NAN NAN NAN NAN NAN NAN 222
NAN NAN NAN NAN 4 NAN NAN 222
NAN NAN NAN NAN NAN 4 NAN 222
NAN 3 NAN 2 NAN NAN NAN 555
NAN NAN 3 NAN NAN NAN NAN 555
NAN NAN NAN NAN NAN NAN NAN 555
when I do a groupby like this:
dg = dg.groupby('ID').max().reset_index()
it produces the following ouput, omitting two columns, like this:
ID thing2 thing3 thing4 thing5 thing7
222 1 3 2 4 3
555 3 2
The dataframe follows that pattern but I don't know why two columns are being omitted
NAN values are np.nan
I found out I had a string "N/A" value in the midst of my np.nan values. Lesson is strings with integers can cause columns to disappear when doing groupby functions. The columns that didn't have "N/A" string didn't disappear upon doing groupby functions. When I replaced "N/A" strings with np.nan the columns didn't disappear when I did the groupby
I have a .asc file where each line has 655 entries and looks somewhat like the following (note the leading whitespace)
-999 -999 -999 -999 -999 -999 -999 -999 -999 ... -999 -999
When I read the file using pandas read_fwf
data = pd.read_fwf('Users/.../file.asc', index_col=False, sep=' ', skiprows=6, header=None, na_values=[-999])
the first three columns are thrown into the 0 column such that I obtain the output
0 1 2 3 4 5 6 7 8 9 ... 641 \
0 -999 -999 -999 -999 NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN
It seems like the function interprets my first 4 columns as an index. index_col=False didn't help fixing the problem. Also, I tried to let pandas create an index column but couldn't find this feature.
Looking forward to your solution. Thanks.
UPDATE2: using colspecs parameter when calling read_fwf()
In [83]: df = pd.read_fwf(fn, skiprows=6, header=None, na_values=[-999],
....: colspecs=[(5,6)] * 654)
In [84]: df.head()
Out[84]:
0 1 2 3 4 5 6 7 8 9 ... 644 645 646 647 648 649 650 651 652 653
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
[5 rows x 654 columns]
UPDATE:
use read_csv() instead of read_fwf() and it'll work:
In [61]: fn = r'D:\download\BRD_8110_YY_GIS.asc'
In [62]: df = pd.read_csv(fn, skiprows=6, header=None, na_values=[-999], delim_whitespace=True)
In [63]: df.head()
Out[63]:
0 1 2 3 4 5 6 7 8 9 ... 644 645 646 647 648 649 650 651 652 653
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
[5 rows x 654 columns]
Use sep='\s+'as keyword argument as stated in the current documentation for pandas - read_fwf to accept 1 or more white space characters as spearators for fields. I would be reluctant in supplying '\s*' as this means 0 or more which might get you into trouble ;-)