I think you're almost there, try removing the extra square brackets around the lst's (Also you don't need to specify the column names when you're creating a dataframe from a dict like this):
import pandas as pd
lst1 = range(100)
lst2 = range(100)
lst3 = range(100)
percentile_list = pd.DataFrame(
{'lst1Title': lst1,
'lst2Title': lst2,
'lst3Title': lst3
})
percentile_list
lst1Title lst2Title lst3Title
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
5 5 5 5
6 6 6 6
...
If you need a more performant solution you can use np.column_stack rather than zip as in your first attempt, this has around a 2x speedup on the example here, however comes at bit of a cost of readability in my opinion:
import numpy as np
percentile_list = pd.DataFrame(np.column_stack([lst1, lst2, lst3]),
columns=['lst1Title', 'lst2Title', 'lst3Title'])
Answer from miriamsimone on Stack OverflowI think you're almost there, try removing the extra square brackets around the lst's (Also you don't need to specify the column names when you're creating a dataframe from a dict like this):
import pandas as pd
lst1 = range(100)
lst2 = range(100)
lst3 = range(100)
percentile_list = pd.DataFrame(
{'lst1Title': lst1,
'lst2Title': lst2,
'lst3Title': lst3
})
percentile_list
lst1Title lst2Title lst3Title
0 0 0 0
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
5 5 5 5
6 6 6 6
...
If you need a more performant solution you can use np.column_stack rather than zip as in your first attempt, this has around a 2x speedup on the example here, however comes at bit of a cost of readability in my opinion:
import numpy as np
percentile_list = pd.DataFrame(np.column_stack([lst1, lst2, lst3]),
columns=['lst1Title', 'lst2Title', 'lst3Title'])
Adding to Aditya Guru's answer here. There is no need of using map. You can do it simply by:
pd.DataFrame(list(zip(lst1, lst2, lst3)))
This will set the column's names as 0,1,2. To set your own column names, you can pass the keyword argument columns to the method above.
pd.DataFrame(list(zip(lst1, lst2, lst3)),
columns=['lst1_title','lst2_title', 'lst3_title'])
Starting from Pandas 0.25.0, there is internal method DataFrame.explode(), which was designed just for that:
res = df.explode("b")
output
In [98]: res
Out[98]:
a b
0 1 1
0 1 2
1 2 2
1 2 3
1 2 4
2 3 5
Solution for Pandas versions < 0.25: generic vectorized approach - will work also for multiple columns DFs:
assuming we have the following DF:
In [159]: df
Out[159]:
a b c
0 1 [1, 2] 5
1 2 [2, 3, 4] 6
2 3 [5] 7
Solution:
In [160]: lst_col = 'b'
In [161]: pd.DataFrame({
...: col:np.repeat(df[col].values, df[lst_col].str.len())
...: for col in df.columns.difference([lst_col])
...: }).assign(**{lst_col:np.concatenate(df[lst_col].values)})[df.columns.tolist()]
...:
Out[161]:
a b c
0 1 1 5
1 1 2 5
2 2 2 6
3 2 3 6
4 2 4 6
5 3 5 7
Setup:
df = pd.DataFrame({
"a" : [1,2,3],
"b" : [[1,2],[2,3,4],[5]],
"c" : [5,6,7]
})
Vectorized NumPy approach:
In [124]: pd.DataFrame({'a':np.repeat(df.a.values, df.b.str.len()),
'b':np.concatenate(df.b.values)})
Out[124]:
a b
0 1 1
1 1 2
2 2 2
3 2 3
4 2 4
5 3 5
OLD answer:
Try this:
In [89]: df.set_index('a', append=True).b.apply(pd.Series).stack().reset_index(level=[0, 2], drop=True).reset_index()
Out[89]:
a 0
0 1 1.0
1 1 2.0
2 2 2.0
3 2 3.0
4 2 4.0
5 3 5.0
Or bit nicer solution provided by @Boud:
In [110]: df.set_index('a').b.apply(pd.Series).stack().reset_index(level=-1, drop=True).astype(int).reset_index()
Out[110]:
a 0
0 1 1
1 1 2
2 2 2
3 2 3
4 2 4
5 3 5
Here is another approach with itertuples -
df = pd.DataFrame({"a" : [1,2,3], "b" : [[1,2],[2,3,4],[5]]})
data = []
for i in df.itertuples():
lst = i[2]
for col2 in lst:
data.append([i[1], col2])
df_output = pd.DataFrame(data =data, columns=df.columns)
df_output
Output is -
a b
0 1 1
1 1 2
2 2 2
3 2 3
4 2 4
5 3 5
Edit: You can also compress the loops into a single code and populate data as -
data = [[i[1], col2] for i in df.itertuples() for col2 in i[2]]
python - How to save multiple lists into multiple rows in Pandas? - Stack Overflow
Pandas: Create several rows from column that is a list - Stack Overflow
python - converting list like column values into multiple rows using Pandas DataFrame - Stack Overflow
python - How to use multiple lists of lists to append new rows to a dataframe? - Stack Overflow
You can call DataFrame constructor after zipping both lists, where A, B represents column names and a, b are lists
df = pd.DataFrame(columns=['A','B'], data=zip(a, b))
If lists are of uneven lengths
from itertools import zip_longest
df = pd.DataFrame(columns=['A','B'], data=zip_longest(a, b)
You can do it like this:
list1 = [1,2,3]
list2 = [4,5,6]
df = pd.DataFrame({'list1': list1, 'list2': list2})
list1 list2
0 1 4
1 2 5
2 3 6
We can solve this using pandas.DataFrame.explode function which was introduced in version 0.25.0 if you have same or higher version, you can use below code.
explode function reference: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.explode.html
import pandas as pd
import ast
data = {
'Location_City': ['Los Angeles','Texas'],
'Location_State': ['CA','TX'],
'Name': ['John','Jack'],
'hobbies': ["['Music', 'Running']", "['Swimming', 'Trekking']"]
}
df = pd.DataFrame(data)
# Converting a string representation of a list into an actual list object
list_eval = lambda x: ast.literal_eval(x)
df['hobbies'] = df['hobbies'].apply(list_eval)
# Exploding the list
df = df.explode('hobbies')
print(df)
Location_City Location_State Name hobbies
0 Los Angeles CA John Music
0 Los Angeles CA John Running
1 Texas TX Jack Swimming
1 Texas TX Jack Trekking
You can use findall or extractall for get lists from hobbies colum, then flatten with chain.from_iterable and repeat another columns:
a = df['hobbies'].str.findall("'(.*?)'").astype(np.object)
lens = a.str.len()
from itertools import chain
df1 = pd.DataFrame({
'Location_City' : df['Location_City'].values.repeat(lens),
'Location_State' : df['Location_State'].values.repeat(lens),
'Name' : df['Name'].values.repeat(lens),
'hobbies' : list(chain.from_iterable(a.tolist())),
})
Or create Series, remove first level and join to original DataFrame:
df1 = (df.join(df.pop('hobbies').str.extractall("'(.*?)'")[0]
.reset_index(level=1, drop=True)
.rename('hobbies'))
.reset_index(drop=True))
print (df1)
Location_City Location_State Name hobbies
0 Los Angeles CA John Music
1 Los Angeles CA John Running
2 Texas TX Jack Swimming
3 Texas TX Jack Trekking
You can use itertools.chain to flatten each list, construct a dictionary with the flattened lists and cast it to a DataFrame:
from itertools import chain
A, B, C = [list(chain.from_iterable(lst)) for lst in [List_a, List_b, List_c]]
out = pd.DataFrame({'A': A, 'B': B, 'C': C})
Output:
A B C
0 1 16 31
1 2 17 32
2 3 18 33
3 4 19 34
4 5 20 35
5 6 21 36
6 7 22 37
7 8 23 38
8 9 24 39
9 10 25 40
10 11 26 41
11 12 27 42
12 13 28 43
13 14 29 44
14 15 30 45
It seems you need range(3), because length of sublists is 3:
for i in range(len(Some_List)):
for j in range(3):
df_temp = { 'A': List_a[i][j], 'B': List_b[i][j], 'C': List_c[i][j]}
All_Rows = All_Rows.append(df_temp, ignore_index = True)
Or you can loop by List_a with enumarate, so inner loop use actual length of sublists:
for i, vals in enumerate(List_a):
for j, vals1 in enumerate(vals):
df_temp = { 'A': List_a[i][j], 'B': List_b[i][j], 'C': List_c[i][j]}
All_Rows = All_Rows.append(df_temp, ignore_index = True)
If need only flatten lists:
L = [List_a, List_b, List_c]
df = pd.DataFrame([[z for y in x for z in y] for x in L], index = ['A','B','C']).T
print (df)
A B C
0 1 16 31
1 2 17 32
2 3 18 33
3 4 19 34
4 5 20 35
5 6 21 36
6 7 22 37
7 8 23 38
8 9 24 39
9 10 25 40
10 11 26 41
11 12 27 42
12 13 28 43
13 14 29 44
14 15 30 45
Here you go, just add column 'C' and you are sorted. Just to note, you must be seeking a pandas solution because merge is a pandas command and you're asking for a Python solution.
import pandas as pd
a = ["house","garden", "living room", "dog","cat"]
b= ["cat","dog", "chicken"]
df = pd.DataFrame(a, columns = ['a'])
df2 = pd.DataFrame(b, columns = ['b'])
dfa = df['a'].value_counts()
dfa.columns = ['a']
dfb = df2['b'].value_counts()
dfb.columns = ['b']
dfa = dfa.to_frame()
dfb = dfb.to_frame()
df3 = dfa.join(dfb).replace(np.nan, 0).astype(int)
print (df3)
Output
a b
house 1 0
garden 1 0
living room 1 0
dog 1 1
cat 1 1
and if you want to remove the 'a' column
print (df3.drop('a', axis=1))
b
house 0
garden 0
living room 0
dog 1
cat 1
Notes The key command here is value_counts and makes a frequency plot. Its output is a Series rather than a DataFrame so it needs converting.
If you want to keep all inputs the commands is
df3 = pd.concat([dfa, dfb]).replace(np.nan, 0).astype(int)
Alternatively,
a = ["house","garden", "living room", "dog","cat"]
b= ["cat","dog", "chicken"]
df = pd.DataFrame(a).value_counts().to_frame('a')
df2 = pd.DataFrame(b).value_counts().to_frame('b')
df3 = df.join(df2).replace(np.nan, 0).astype(int).rename_axis(None)
print (df3.drop('a', axis=1))
I'm aware that this asks specifically for a python solution, but I'd like to add an R answer as well, just in case someone using R has a similar problem:
> a <- c("house","garden", "living room", "dog","cat")
> b <- c("cat","dog", "chicken")
> c <- c("house", "garden","bathroom")
> (result <- data.frame(row.names=a, a=a %in% a, b=a %in% b, c=a %in% c))
a b c
house TRUE FALSE TRUE
garden TRUE FALSE TRUE
living room TRUE FALSE FALSE
dog TRUE TRUE FALSE
cat TRUE TRUE FALSE
or for strictly what you asked for, the TRUE/FALSE values can be encouraged into numbers by adding zero:
> (result <- data.frame(a=a, b=(a %in% b) + 0, c=(a %in% c) + 0))
a b c
1 house 0 1
2 garden 0 1
3 living room 0 0
4 dog 1 0
5 cat 1 0

