提出了几个与我类似的问题并得到了回答,但是他们都使用了
pd.concat
,而我想使用merge
或可以给我类似结果的东西。
我想将多个 CSV 文件合并到一个主 df 中。我的所有 CSV 文件都有相同的两列(“gene”和“log2foldchange”)。
我的 CSV 文件都类似于以下内容:
基因 | log2foldchange |
---|---|
基因1 | 0.03 |
基因2 | 0.02 |
基因3 | 0.01 |
基因4 | 0.05 |
每个 CSV 文件:
我想将 CSV 文件的名称合并为存储 log2foldchange 值的列名称,以便我知道数据来自哪里。我希望我的最终 master df 看起来像下面这样:
左 | 第一个 CSV_文件的名称 | 第二个 CSV_文件的名称 | 第 3 个 CSV 文件的名称 | 第 4 个 CSV_文件的名称 |
---|---|---|---|---|
基因1 | 0.08 | 0.09 | 0.07 | 0.01 |
基因2 | 0.07 | 0.03 | 0.06 | 0.001 |
基因3 | 0.08 | 0.06 | 0.05 | 0.2 |
基因4 | 0.09 | 0.02 | 0.03 | 0.011 |
我能够成功地使用
pd.concat
将所有 CSV 文件合并到一个主 df 中,但是,我最终 df 的结构是所有 CSV 文件都堆叠在一起。这种结构对于我想做的分析类型没有意义。我想使用 merge
,但我遇到的问题是它需要 two 对象,我不知道如何解决这个问题。
此外,我只能将文件名作为其自己的单独列,而不是像我希望的那样作为 log2fold 更改的列名。
这是我使用 pd.concat 的代码:
source_files = sorted(Path('path/to/my/files').glob('*.csv'))
dataframes = []
for file in source_files:
df = pd.read_csv(file)
df['source'] = file.name
dataframes.append(df)
df_all = pd.concat(dataframes)
display(df_all)
这会产生如下所示的 df:
基因 | log2foldchange | 来源 |
---|---|---|
基因1 | 0.03 | 第一个 CSV 文件 |
基因2 | 0.02 | 第一个 CSV 文件 |
基因3 | 0.01 | 第一个 CSV 文件 |
基因4 | 0.04 | 第一个 CSV 文件 |
基因1 | 0.05 | 第二个 CSV 文件 |
基因2 | 0.06 | 第二个 CSV 文件 |
等等...
这是我使用 pd.merge 的代码,它会导致错误,因为只给出了一个对象:
path = 'path/to/my/files'
all_files = glob.glob(os.path.join(path, "*.csv")) #make list of file paths
#initialize empty data frame
li = []
for filename in all_files:
df = pd.read_csv(filename, index_col=None, header=0)
li.append(df)
frame = pd.merge(li, axis=0, ignore_index=True)
display(frame)
编辑:根据评论进行调整
这行得通吗?
from functools import reduce
list_of_dfs = []
for file in all_files:
df = pd.read_csv(file, header=0, sep=",") #Change sep to whatever separates your data
df = df.loc[:, ['gene', 'log2foldchange']] #Subset out only the two columns you want
file_name = os.path.splitext(os.path.basename(file))[0] #Get filename without extension
df = df.rename(columns={'log2foldchange': file_name}) #Rename log2fold column with file name
list_of_dfs.append(df) #Add df to list of dfs
df_merged = reduce(lambda left,right: pd.merge(left,right,on='gene',how='outer'), list_of_dfs)
比接受的答案更短、更高效的代码,尤其是对于大文件数。
这不是一个
.concat
问题。将文件源作为新列进行跟踪是一个好主意。但您在这里想要的是直接重命名保存数据的列。
您最终会这样做,所以为什么不跳过额外的临时列呢?
考虑一下:
# 1. This is your pre-processing. Shape the unit dataframes for aggregation.
def csv_to_df(file):
'''Convert file path to unit dataframe'''
df = pd.read_csv(file)
return df.rename(columns={'log2foldchange' : file.name})
# 2. concat works naturally
df_all = pd.concat( [csv_to_df(file) for file in source_files], axis=1)
您寻求的内容保持在 4 行中,并且没有
for
循环,因为对于大文件数,建议使用数据帧的列表理解,而不是用 list.append
结束每次迭代的循环。
使用以下代码在 python 中合并两个 csv 文件。它创建一个 DataFrame 列表,每个 DataFrame 包含“
gene
”列和以文件命名的 log2foldchange 列。然后,它根据“DataFrames
”列合并这些gene
。
import pandas as pd
from pathlib import Path
source_files = sorted(Path('path/to/my/files').glob('*.csv'))
dataframes = []
for file in source_files:
df = pd.read_csv(file)
# Create a new column with log2foldchange values named after the file
df[file.stem] = df['log2foldchange']
dataframes.append(df[['gene', file.stem]])
# Merge DataFrames on the 'gene' column
df_all = dataframes[0] # Initialize with the first DataFrame
for df in dataframes[1:]:
df_all = pd.merge(df_all, df, on='gene')
# You can set 'gene' as the index
df_all.set_index('gene', inplace=True)
display(df_all)